Your AI Connector Docs

FAQs API

FAQs are the question-and-answer entries your AI bot draws on when replying to customers. Each FAQ belongs to your account and can be linked to one or more campaigns, so the same answer can be reused everywhere it’s relevant. The FAQs API lets you manage that library programmatically — create, update, bulk-import, reorder, and link FAQs to campaigns from your own code.

All endpoints below are relative to the base URL https://api.youraiconnector.com/v1. Every request must be authenticated — see API Access and Authentication. API access is a paid feature; without it, requests are rejected with a 403.

How the bot uses a FAQ: When you create or change a FAQ, the platform prepares its search data (used to match the FAQ to incoming questions) in the background. This usually finishes within a few seconds, after which the bot starts using the entry automatically.


The FAQ object

Every FAQ that comes back from the API has this shape:

Field Type Description
id string The FAQ’s unique identifier.
question string The customer question this entry answers.
answer string The answer the AI bot gives.
category string | null Optional free-form category label.
tags string[] Optional labels for organizing FAQs.
is_active boolean Whether the bot is allowed to use this FAQ. Defaults to true.
is_global boolean Marks the FAQ as not tied to one specific campaign or Agent. It does not make the FAQ apply everywhere: an FAQ is only used by the campaigns and Agents it is linked to. Defaults to false.
usage_count integer How many times this FAQ has been used in AI replies.
order_index integer Display position of this FAQ within its campaign.
campaign_ids string[] IDs of the campaigns this FAQ is linked to.
created_at string | null ISO 8601 timestamp of when the FAQ was created.
updated_at string | null ISO 8601 timestamp of the last change.

The fields you can set are: question, answer, is_active, is_global, category, tags, and order_index. The platform manages everything else (search data, usage counts, timestamps); any other fields in your request body are ignored.


List FAQs

GET /faqs

Returns the FAQs in your account, newest first. Optionally filter to a single campaign or by active state.

Query parameters

Parameter Required Description
campaign_id No Only return FAQs linked to this campaign.
is_active No Only return FAQs with this active state (true or false). This filter is applied per page, so a page may contain fewer items than limit.
limit No Maximum FAQs per page. Default 50, maximum 100.
cursor No A FAQ ID to continue after. Pass the next_cursor value from the previous page.

cURL

curl "https://api.youraiconnector.com/v1/faqs?campaign_id=campaign123&limit=50&apiKey=YOUR_API_KEY"

JavaScript

const res = await fetch(
  "https://api.youraiconnector.com/v1/faqs?campaign_id=campaign123&limit=50",
  { headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();
console.log(data.faqs, data.next_cursor);

Python

import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/faqs",
    params={"campaign_id": "campaign123", "limit": 50},
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()
print(data["faqs"], data["next_cursor"])

Response

{
  "success": true,
  "faqs": [
    {
      "id": "aBcD1234eFgH5678",
      "question": "How long does shipping take?",
      "answer": "Standard shipping takes 3-5 business days.",
      "category": "shipping",
      "tags": ["logistics", "delivery"],
      "is_active": true,
      "is_global": false,
      "usage_count": 12,
      "order_index": 0,
      "campaign_ids": ["campaign123"],
      "created_at": "2026-01-01T12:00:00.000Z",
      "updated_at": "2026-01-02T08:30:00.000Z"
    }
  ],
  "next_cursor": "aBcD1234eFgH5678"
}

When next_cursor is null, there are no more results.


Get a FAQ

GET /faqs/{faqId}

Returns a single FAQ by its ID.

cURL

curl "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678?apiKey=YOUR_API_KEY"

JavaScript

const res = await fetch(
  "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678",
  { headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const { faq } = await res.json();

Python

import requests

res = requests.get(
    "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
faq = res.json()["faq"]

Response

{
  "success": true,
  "faq": {
    "id": "aBcD1234eFgH5678",
    "question": "How long does shipping take?",
    "answer": "Standard shipping takes 3-5 business days.",
    "category": "shipping",
    "tags": ["logistics"],
    "is_active": true,
    "is_global": false,
    "usage_count": 12,
    "order_index": 0,
    "campaign_ids": ["campaign123"],
    "created_at": "2026-01-01T12:00:00.000Z",
    "updated_at": "2026-01-02T08:30:00.000Z"
  }
}

Create a FAQ

POST /faqs

Creates a new FAQ and links it to a campaign.

Request fields

Field Required Description
campaign_id Yes The campaign to link the new FAQ to.
question Yes The customer question this entry answers.
answer Yes The answer the bot should give.
is_active No Whether the bot may use this FAQ. Defaults to true.
is_global No Whether the FAQ applies to all campaigns. Defaults to false.
category No A free-form category label.
tags No An array of labels.
order_index No Display position within the campaign. Defaults to 0.

cURL

curl -X POST "https://api.youraiconnector.com/v1/faqs?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "campaign_id": "campaign123",
    "question": "How long does shipping take?",
    "answer": "Standard shipping takes 3-5 business days.",
    "category": "shipping",
    "tags": ["logistics"]
  }'

JavaScript

const res = await fetch("https://api.youraiconnector.com/v1/faqs", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    campaign_id: "campaign123",
    question: "How long does shipping take?",
    answer: "Standard shipping takes 3-5 business days.",
    category: "shipping",
    tags: ["logistics"],
  }),
});
const { faq_id } = await res.json();

Python

import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/faqs",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "campaign_id": "campaign123",
        "question": "How long does shipping take?",
        "answer": "Standard shipping takes 3-5 business days.",
        "category": "shipping",
        "tags": ["logistics"],
    },
)
faq_id = res.json()["faq_id"]

Response

{
  "success": true,
  "faq_id": "aBcD1234eFgH5678"
}

Update a FAQ

PUT /faqs/{faqId}

Partially updates a FAQ. Only the supplied writable fields are changed; everything else keeps its current value. Changing the question or answer automatically refreshes the FAQ’s search data in the background.

If you send question or answer, they must be non-empty strings. Sending no recognized writable fields returns a 400.

cURL

curl -X PUT "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "is_active": false }'

JavaScript

const res = await fetch(
  "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678",
  {
    method: "PUT",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ is_active: false }),
  }
);
const data = await res.json();

Python

import requests

res = requests.put(
    "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"is_active": False},
)
data = res.json()

Response

{
  "success": true,
  "faq_id": "aBcD1234eFgH5678"
}

Delete a FAQ

DELETE /faqs/{faqId}

Permanently deletes a FAQ. Optionally pass campaign_id as a query parameter to also remove the FAQ from that campaign’s FAQ list.

Query parameters

Parameter Required Description
campaign_id No Also remove the FAQ from this campaign’s FAQ list.

cURL

curl -X DELETE "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678?campaign_id=campaign123&apiKey=YOUR_API_KEY"

JavaScript

const res = await fetch(
  "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678?campaign_id=campaign123",
  { method: "DELETE", headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();

Python

import requests

res = requests.delete(
    "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678",
    params={"campaign_id": "campaign123"},
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()

Response

{
  "success": true
}

Bulk-delete FAQs

POST /faqs/bulk-delete

Deletes up to 500 FAQs in a single request. When campaign_id is supplied, the deleted FAQs are also removed from that campaign’s FAQ list.

Request fields

Field Required Description
faq_ids Yes A non-empty array of FAQ IDs to delete (max 500).
campaign_id No Also remove the deleted FAQs from this campaign’s FAQ list.

cURL

curl -X POST "https://api.youraiconnector.com/v1/faqs/bulk-delete?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "faq_ids": ["faqId1", "faqId2"], "campaign_id": "campaign123" }'

JavaScript

const res = await fetch("https://api.youraiconnector.com/v1/faqs/bulk-delete", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    faq_ids: ["faqId1", "faqId2"],
    campaign_id: "campaign123",
  }),
});
const data = await res.json();

Python

import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/faqs/bulk-delete",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"faq_ids": ["faqId1", "faqId2"], "campaign_id": "campaign123"},
)
data = res.json()

Response

{
  "success": true,
  "deleted_count": 2
}

Import FAQs

POST /faqs/import

Bulk-imports up to 500 FAQs and links them all to one campaign. Items whose question matches an existing FAQ in your library (case-insensitive) update that FAQ instead of creating a duplicate.

Performance tip: Duplicate matching scans your whole FAQ library, so very large libraries make imports slower. Prefer fewer, larger imports over many small ones.

Request fields

Field Required Description
campaign_id Yes The campaign all imported FAQs are linked to.
faqs Yes A non-empty array of FAQ items (max 500). Each item must have a non-empty question and answer; it may also include is_active, is_global, category, tags, and order_index.

cURL

curl -X POST "https://api.youraiconnector.com/v1/faqs/import?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "campaign_id": "campaign123",
    "faqs": [
      { "question": "Do you ship internationally?", "answer": "Yes, we ship to most countries worldwide." },
      { "question": "What is your return policy?", "answer": "You can return any item within 30 days." }
    ]
  }'

JavaScript

const res = await fetch("https://api.youraiconnector.com/v1/faqs/import", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    campaign_id: "campaign123",
    faqs: [
      {
        question: "Do you ship internationally?",
        answer: "Yes, we ship to most countries worldwide.",
      },
      {
        question: "What is your return policy?",
        answer: "You can return any item within 30 days.",
      },
    ],
  }),
});
const data = await res.json();

Python

import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/faqs/import",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "campaign_id": "campaign123",
        "faqs": [
            {"question": "Do you ship internationally?", "answer": "Yes, we ship to most countries worldwide."},
            {"question": "What is your return policy?", "answer": "You can return any item within 30 days."},
        ],
    },
)
data = res.json()

Response

{
  "success": true,
  "faq_ids": ["aBcD1234eFgH5678", "iJkL9012mNoP3456"],
  "imported_count": 2
}

faq_ids are the created or updated FAQ IDs, in the order you supplied them.


Reorder FAQs

POST /faqs/reorder

Sets the display order of a campaign’s FAQs. Supply the full list of FAQ IDs in the desired order; each FAQ’s position is updated to match its place in the array.

Request fields

Field Required Description
campaign_id Yes The campaign whose FAQs are being reordered.
ordered_faq_ids Yes A non-empty array of all the campaign’s FAQ IDs in the desired display order (max 500).

cURL

curl -X POST "https://api.youraiconnector.com/v1/faqs/reorder?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "campaign_id": "campaign123",
    "ordered_faq_ids": ["faqId2", "faqId1", "faqId3"]
  }'

JavaScript

const res = await fetch("https://api.youraiconnector.com/v1/faqs/reorder", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    campaign_id: "campaign123",
    ordered_faq_ids: ["faqId2", "faqId1", "faqId3"],
  }),
});
const data = await res.json();

Python

import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/faqs/reorder",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "campaign_id": "campaign123",
        "ordered_faq_ids": ["faqId2", "faqId1", "faqId3"],
    },
)
data = res.json()

Response

{
  "success": true
}

If the campaign or any of the FAQ IDs isn’t found in your account, the request returns 404 One or more FAQs were not found.


POST /faqs/{faqId}/link

Links an existing FAQ to an additional campaign. A FAQ can be shared by any number of campaigns, so the same answer only needs to be maintained once.

Request fields

Field Required Description
campaign_id Yes The campaign to link the FAQ to.

cURL

curl -X POST "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678/link?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "campaign_id": "campaign456" }'

JavaScript

const res = await fetch(
  "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678/link",
  {
    method: "POST",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ campaign_id: "campaign456" }),
  }
);
const data = await res.json();

Python

import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678/link",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"campaign_id": "campaign456"},
)
data = res.json()

Response

{
  "success": true,
  "faq_id": "aBcD1234eFgH5678",
  "campaign_id": "campaign456"
}

POST /faqs/{faqId}/unlink

Removes a FAQ from a campaign without deleting the FAQ itself. The FAQ stays in your library and remains linked to any other campaigns.

Request fields

Field Required Description
campaign_id Yes The campaign to remove the FAQ from.

cURL

curl -X POST "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678/unlink?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "campaign_id": "campaign456" }'

JavaScript

const res = await fetch(
  "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678/unlink",
  {
    method: "POST",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ campaign_id: "campaign456" }),
  }
);
const data = await res.json();

Python

import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678/unlink",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"campaign_id": "campaign456"},
)
data = res.json()

Response

{
  "success": true,
  "faq_id": "aBcD1234eFgH5678",
  "campaign_id": "campaign456"
}

Rebuild a FAQ’s search data

POST /faqs/{faqId}/rebuild-embeddings

Queues a rebuild of the data the AI bot uses to find this FAQ (its semantic and keyword search data). This is useful if a FAQ isn’t being picked up in replies as expected. The rebuild runs in the background and usually completes within a few seconds; the FAQ may be temporarily excluded from AI replies while it is being rebuilt.

This endpoint returns 202 Accepted because the work continues after the response is sent. The status is always "processing" — re-fetch the FAQ later if you need to confirm completion.

cURL

curl -X POST "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678/rebuild-embeddings?apiKey=YOUR_API_KEY"

JavaScript

const res = await fetch(
  "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678/rebuild-embeddings",
  { method: "POST", headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const data = await res.json();

Python

import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678/rebuild-embeddings",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()

Response

{
  "success": true,
  "faq_id": "aBcD1234eFgH5678",
  "status": "processing"
}

AI-assisted FAQ management

The endpoints below go beyond plain CRUD: they call the same AI-assist tools the dashboard’s FAQ editor uses — finding duplicates, generating entries from a document, and matching FAQs to open knowledge-gap tasks. Request bodies on this set use camelCase field names (campaignId, taskId, sourceIds…), matching the app’s own request shapes, rather than the snake_case used elsewhere on this page — copy the examples below rather than guessing a field name.

Fork a FAQ into a campaign-only copy

POST /faqs/{faqId}/fork-for-campaign

Creates a new FAQ that’s a copy of an existing one, scoped to a single campaign, and re-links that campaign to the new copy instead of the original. Use this when you want to customize an answer for one campaign without changing it everywhere else the original FAQ is used. The original FAQ is left in place — it only loses this campaign’s link.

Request fields

Field Required Description
campaign_id Yes The campaign to scope the new copy to, and to re-link from the original FAQ.
question Yes The question for the new, campaign-specific copy.
answer Yes The answer for the new, campaign-specific copy.

cURL

curl -X POST "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678/fork-for-campaign?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "campaign_id": "campaign456",
    "question": "How long does shipping take to the EU?",
    "answer": "For EU orders, shipping takes 7-10 business days."
  }'

JavaScript

const res = await fetch(
  "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678/fork-for-campaign",
  {
    method: "POST",
    headers: {
      "X-API-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      campaign_id: "campaign456",
      question: "How long does shipping take to the EU?",
      answer: "For EU orders, shipping takes 7-10 business days.",
    }),
  }
);
const data = await res.json();

Python

import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/faqs/aBcD1234eFgH5678/fork-for-campaign",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "campaign_id": "campaign456",
        "question": "How long does shipping take to the EU?",
        "answer": "For EU orders, shipping takes 7-10 business days.",
    },
)
data = res.json()

Response201 Created

{
  "success": true,
  "faq_id": "nEwFaQiD9012mNoP",
  "campaign_id": "campaign456",
  "original_faq_id": "aBcD1234eFgH5678"
}

Find near-duplicate FAQs

POST /faqs/dedupe

Starts a background job that scans your FAQ library for near-duplicate and overlapping entries and merges or removes them where it’s confident. Useful after a bulk import, or after several rounds of AI-generated FAQs have left the library with overlap. Only one dedupe job can run per account at a time — starting a second one while a job is still running returns 409.

Request fields

Field Required Description
sourceIds No Array of knowledge-base source IDs to scope the dedupe to. Omit to scan your whole FAQ library.

cURL

curl -X POST "https://api.youraiconnector.com/v1/faqs/dedupe?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

JavaScript

const res = await fetch("https://api.youraiconnector.com/v1/faqs/dedupe", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({}),
});
const data = await res.json();

Python

import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/faqs/dedupe",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={},
)
data = res.json()

Response202 Accepted

{
  "success": true,
  "job_id": "dedupJob_aBc123"
}

The job runs in the background and typically takes a few minutes on a large library. There’s no separate status endpoint — re-fetch GET /faqs after a short wait to see what changed. When you’re done reviewing the result, call the dismiss endpoint below to clear it.

Dismiss a duplicate-check result

POST /faqs/dedupe/dismiss

Clears the finished dedupe job so it stops showing as an active result. Idempotent — safe to call even if there’s nothing to dismiss. Returns 409 if the job is still queued or processing (you can’t dismiss a run that hasn’t finished).

cURL

curl -X POST "https://api.youraiconnector.com/v1/faqs/dedupe/dismiss?apiKey=YOUR_API_KEY"

JavaScript

const res = await fetch("https://api.youraiconnector.com/v1/faqs/dedupe/dismiss", {
  method: "POST",
  headers: { "X-API-Key": "YOUR_API_KEY" },
});
const data = await res.json();

Python

import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/faqs/dedupe/dismiss",
    headers={"X-API-Key": "YOUR_API_KEY"},
)
data = res.json()

Response

{ "success": true }

Generate FAQs from uploaded documents

POST /faqs/generate-from-documents

Reads one or more documents already in your account’s file storage and has the AI draft FAQs from their content, checking the drafts against your existing library so it reuses or updates entries instead of creating duplicates. Results are not written immediately — they’re stored as a pending change set on the campaign for you to review, then applied (or discarded) with Apply reviewed FAQ changes below. This costs credits, since it’s an AI generation pass over the document text.

This endpoint doesn’t carry the file: storagePath must point to a file already under your own uploads folder (users/{your user id}/uploads/), the same convention as Import an uploaded document on the Knowledge Base API.

Request fields

Field Required Description
campaignId Yes The campaign the generated FAQs are proposed for.
uploadedFiles Yes Non-empty array of files to read, each { storagePath, fileName, mimeType }. storagePath must start with users/{your user id}/uploads/.

cURL

curl -X POST "https://api.youraiconnector.com/v1/faqs/generate-from-documents?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "campaignId": "campaign123",
    "uploadedFiles": [
      { "storagePath": "users/abc123uid/uploads/handbook.pdf", "fileName": "handbook.pdf", "mimeType": "application/pdf" }
    ]
  }'

JavaScript

const res = await fetch("https://api.youraiconnector.com/v1/faqs/generate-from-documents", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    campaignId: "campaign123",
    uploadedFiles: [
      { storagePath: "users/abc123uid/uploads/handbook.pdf", fileName: "handbook.pdf", mimeType: "application/pdf" },
    ],
  }),
});
const data = await res.json();

Python

import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/faqs/generate-from-documents",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "campaignId": "campaign123",
        "uploadedFiles": [
            {"storagePath": "users/abc123uid/uploads/handbook.pdf", "fileName": "handbook.pdf", "mimeType": "application/pdf"},
        ],
    },
)
data = res.json()

Response202 Accepted

{
  "success": true,
  "faqCount": 6,
  "reusedCount": 2,
  "modifiedCount": 1,
  "newCount": 3
}

faqCount is the total number of proposed changes waiting for review; reusedCount, modifiedCount and newCount break that down into FAQs that matched an existing entry unchanged, ones the AI proposes editing, and brand-new ones. Uploaded files are deleted from storage once processing finishes, whether or not it succeeds.

Apply reviewed FAQ changes

POST /faqs/apply-optimization

Applies (or discards) a pending set of AI-proposed FAQ changes — the kind produced by Generate FAQs from documents above, or by the dashboard’s FAQ optimization review. You choose exactly which proposed changes to accept; anything you don’t mention is left untouched (an omitted change is never treated as a rejection that deletes something).

Request fields

Field Required Description
campaignId One of these two The campaign whose pending FAQ changes are being applied.
agentId One of these two The AI Agent whose pending FAQ changes are being applied, on an agent-native account. Supply exactly one of campaignId / agentId, never both.
acceptedChanges Yes Array of the changes you accept, each { action, faq_id?, faq_ref_path?, question?, answer?, edit_scope? }. action is one of keep, remove, add_from_library, create_new, modify. Send an empty array to discard the pending set without applying anything.

cURL

curl -X POST "https://api.youraiconnector.com/v1/faqs/apply-optimization?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "campaignId": "campaign123",
    "acceptedChanges": [
      { "action": "create_new", "question": "Do you ship to the EU?", "answer": "Yes, EU shipping takes 7-10 business days." },
      { "action": "remove", "faq_ref_path": "users/abc123uid/faqs/oldFaqId" }
    ]
  }'

JavaScript

const res = await fetch("https://api.youraiconnector.com/v1/faqs/apply-optimization", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    campaignId: "campaign123",
    acceptedChanges: [
      { action: "create_new", question: "Do you ship to the EU?", answer: "Yes, EU shipping takes 7-10 business days." },
      { action: "remove", faq_ref_path: "users/abc123uid/faqs/oldFaqId" },
    ],
  }),
});
const data = await res.json();

Python

import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/faqs/apply-optimization",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={
        "campaignId": "campaign123",
        "acceptedChanges": [
            {"action": "create_new", "question": "Do you ship to the EU?", "answer": "Yes, EU shipping takes 7-10 business days."},
            {"action": "remove", "faq_ref_path": "users/abc123uid/faqs/oldFaqId"},
        ],
    },
)
data = res.json()

Response

{
  "success": true,
  "message": "Applied 2 FAQ changes",
  "faq_count": 7
}

faq_count is the campaign’s (or Agent’s) total linked FAQ count after applying. If there was no pending change set to apply, the response is { "success": true, "message": "No pending FAQ changes to apply" }.

Find FAQs similar to a task

POST /faqs/similar-for-task

Ranks your FAQ library by relevance to a knowledge-gap task’s question — the same lookup behind the dashboard’s “Use an existing FAQ” picker. Read-only. taskId must point to a task of type faq_update.

This endpoint always answers 200, even on an expected failure like an unknown task — check success in the body rather than the HTTP status.

Request fields

Field Required Description
taskId Yes The faq_update task to find matches for.
limit No Maximum matches to return. Defaults to 20, capped at 50.

cURL

curl -X POST "https://api.youraiconnector.com/v1/faqs/similar-for-task?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "taskId": "task789", "limit": 10 }'

JavaScript

const res = await fetch("https://api.youraiconnector.com/v1/faqs/similar-for-task", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ taskId: "task789", limit: 10 }),
});
const data = await res.json();

Python

import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/faqs/similar-for-task",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"taskId": "task789", "limit": 10},
)
data = res.json()

Response

{
  "success": true,
  "data": {
    "task_id": "task789",
    "matches": [
      {
        "faq_id": "aBcD1234eFgH5678",
        "question": "How long does shipping take?",
        "answer": "Standard shipping takes 3-5 business days.",
        "category": "shipping",
        "created_at": "2026-01-01T12:00:00.000Z",
        "similarity": 0.81,
        "embedding_similarity": 0.81,
        "keyword_similarity": 0.6,
        "bm25_score": 4.2,
        "distance": 0.19
      }
    ]
  }
}

Matches are sorted by similarity (semantic match when available, keyword overlap otherwise), best first. On a soft failure the shape is { "success": false, "error": "...", "error_code": 404 }error_code mirrors what the HTTP status would normally be.

Resolve a task with an existing FAQ

POST /faqs/resolve-task

Resolves a knowledge-gap task by linking it to an FAQ you already have (instead of writing a new one), sends that FAQ’s answer to the contact who triggered the gap, and marks the task complete. Use this after Find FAQs similar to a task turns up an existing FAQ that already covers the question.

Like the endpoint above, this always answers 200 — check success in the body.

Request fields

Field Required Description
taskId Yes The faq_update task to resolve.
faqId Yes The existing FAQ to link and send as the answer.

cURL

curl -X POST "https://api.youraiconnector.com/v1/faqs/resolve-task?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "taskId": "task789", "faqId": "aBcD1234eFgH5678" }'

JavaScript

const res = await fetch("https://api.youraiconnector.com/v1/faqs/resolve-task", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ taskId: "task789", faqId: "aBcD1234eFgH5678" }),
});
const data = await res.json();

Python

import requests

res = requests.post(
    "https://api.youraiconnector.com/v1/faqs/resolve-task",
    headers={"X-API-Key": "YOUR_API_KEY"},
    json={"taskId": "task789", "faqId": "aBcD1234eFgH5678"},
)
data = res.json()

Response

{
  "success": true,
  "data": {
    "task_id": "task789",
    "faq_id": "aBcD1234eFgH5678",
    "follow_up_status": "published"
  }
}

follow_up_status tells you what happened to the contact follow-up: published (sent right away), queued (the AI was already mid-reply to that contact, so it’ll go out next), skipped_no_contact (the task has no linked contact), or skipped_no_campaign (no campaign to send it through).


FAQs API errors

FAQ endpoints return the standard error envelope:

{
  "success": false,
  "error": "FAQ not found"
}
Status When it happens on an FAQ endpoint
400 A required field is missing or invalid (for example an empty question, a missing campaign_id, or more than 500 items in a bulk request).
404 The FAQ or campaign was not found — either it doesn’t exist or it belongs to another account.
409 POST /faqs/dedupe was called while a dedupe job is already queued/processing, or POST /faqs/dedupe/dismiss was called while the job hasn’t finished yet.

The shared codes every endpoint can return — 401, 403 (your plan does not include API access), 429 (rate limit) and 500 — are listed with retry guidance in Errors & Pagination.

POST /faqs/similar-for-task and POST /faqs/resolve-task are the two exceptions on this page: they answer 200 even for an expected failure (unknown task, wrong task type) and put the real status in the body’s error_code instead — see each endpoint above.