ReaktlyDocs
API Reference

Ingestion API

REST endpoints for pushing content into a Reaktly knowledge base.

Base URL

https://api.reaktly.com

Every request needs an API key with the iq:import scope (see Authentication):

curl https://api.reaktly.com/ingest \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{ ... }'

Ingestion is asynchronous: an accepted item is queued, processed (normalized, chunked, embedded) and then searchable by the AI. jobIds are derived from integrationId + externalId, so re-submitting the same pair does not create duplicate work.

POST /ingest — single item

Request body

FieldTypeRequiredDescription
integrationIdstringYesYour integration's ID (the connector this data belongs to)
knowledgeBaseIdstringNoTarget knowledge base. Omit to use the tenant's default
sourceTypestringYesContent kind — see Source types
externalIdstringYesStable ID from your system; the deduplication key within the integration
sourceOriginstringNoOrigin tag (e.g. wordpress-rest). Scopes cleanup to this connector
data.titlestringYesItem title
data.contentstringYesThe text the AI answers from — this is what gets embedded
data.urlstringNoCanonical URL of the original item, used in citations
data.metadataobjectNoOriginal raw data (price, sku, author, …)
data.sourceDataobjectNoStructured source data for richer answers
data.hashstringNoContent hash — unchanged hashes skip re-processing (Change detection)
options.forceRefreshbooleanNoRe-process even if the hash is unchanged
options.priority"high" | "low"NoQueue priority. Use high for user-triggered imports, low for background syncs
options.metadataOnlybooleanNoUpdate url, metadata and sourceData without re-embedding — for price or URL changes

Example

{
  "integrationId": "int_abc123",
  "knowledgeBaseId": "kb_xyz789",
  "sourceType": "ARTICLE",
  "externalId": "blog-post-42",
  "sourceOrigin": "my-cms",
  "data": {
    "title": "How to use our product",
    "content": "This guide walks you through...",
    "url": "https://your-site.com/blog/how-to-use",
    "hash": "a1b2c3d4e5f6"
  },
  "options": {
    "priority": "high"
  }
}

Response 200

{
  "status": "queued",
  "jobId": "int_abc123-blog-post-42"
}

POST /ingest/bulk — batch import

Optimised for initial loads. Each item has the shape above; the tenant is taken from the API key.

{
  "items": [
    { "integrationId": "int_abc123", "sourceType": "PRODUCT", "externalId": "sku-1", "data": { "title": "…", "content": "…" } },
    { "integrationId": "int_abc123", "sourceType": "PRODUCT", "externalId": "sku-2", "data": { "title": "…", "content": "…" } }
  ]
}

Response 200

{
  "status": "queued",
  "jobCount": 50,
  "estimatedTime": "5s",
  "jobIds": ["int_abc123-sku-1", "int_abc123-sku-2"]
}

estimatedTime is the queue's own estimate (10 items per second). It describes queueing, not embedding time.

POST /ingest/cleanup — remove orphaned items

After a full sync, tell Reaktly which externalIds still exist. Sources with the same sourceOrigin that are not in the keep list are deleted — so items removed from your CMS disappear from the knowledge base too.

{
  "knowledgeBaseId": "kb_xyz789",
  "sourceOrigin": "my-cms",
  "keepExternalIds": ["blog-post-42", "blog-post-43"]
}

Response 200

{
  "deleted": 3,
  "orphanedExternalIds": ["blog-post-17", "blog-post-18", "blog-post-19"]
}

Cleaning up is scoped: only sources whose sourceOrigin matches are considered. An empty keepExternalIds list deletes every source from that origin — use it with care.

Errors

See Error handling for status codes, retry and backoff.

Where to go next

On this page