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.
Link a FAQ to a campaign
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"
}
Unlink a FAQ from a campaign
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()
Response — 201 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()
Response — 202 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()
Response — 202 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.
Related
- Campaigns API — the campaigns your FAQs are linked to.
- Knowledge Base API — import websites and documents into FAQs automatically, and bundle FAQs into reusable knowledge groups.
- API Access — generate your API key.
- Authentication — all the ways to pass your key.