ReaktlyDocs
Integrations

Data Ingestion Guide

Worked examples for pushing content into Reaktly from TypeScript, Python, and cURL.

This guide gets data into a knowledge base. For the exact field list and every endpoint, see the Ingestion API reference.

What you need

ValueWhere to find it
API key with iq:importDashboard → Settings → API keys (Authentication)
integrationIdDashboard → the integration (connector) the data belongs to
knowledgeBaseIdDashboard → Knowledge base. Optional — omit to use the tenant's default

The flow

  1. Extract — read items from your source system
  2. Transform — map to the ingestion shape: sourceType, externalId, data.title, data.content
  3. Load — POST /ingest for one item, POST /ingest/bulk for batches
  4. Clean up — after a full sync, POST /ingest/cleanup removes items deleted at the source

First request (cURL)

curl -X POST https://api.reaktly.com/ingest \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "integrationId": "your-integration-id",
    "knowledgeBaseId": "your-kb-id",
    "sourceType": "ARTICLE",
    "externalId": "my-first-article",
    "data": {
      "title": "Getting Started Guide",
      "content": "The text the AI will answer from…",
      "url": "https://your-site.com/getting-started"
    }
  }'

A 200 with { "status": "queued", "jobId": "…" } means the item is accepted. Processing (chunking, embedding, indexing) happens in the background — allow a short delay before the assistant can answer from it.

TypeScript

const response = await fetch('https://api.reaktly.com/ingest', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-api-key': process.env.REAKTLY_API_KEY!,
  },
  body: JSON.stringify({
    integrationId: process.env.REAKTLY_INTEGRATION_ID,
    sourceType: 'ARTICLE',
    externalId: `post-${post.id}`,
    data: {
      title: post.title,
      content: post.body,
      url: `https://your-site.com/blog/${post.slug}`,
      hash: contentHash(post),
    },
    options: { priority: 'high' },
  }),
});

if (!response.ok) throw new Error(`Ingestion failed: ${response.status}`);
const result = await response.json();
console.log('Queued as', result.jobId);

Python

import os
import requests

response = requests.post(
    "https://api.reaktly.com/ingest",
    json={
        "integrationId": os.environ["REAKTLY_INTEGRATION_ID"],
        "sourceType": "ARTICLE",
        "externalId": f"post-{post_id}",
        "data": {
            "title": title,
            "content": body,
            "url": url,
        },
    },
    headers={"x-api-key": os.environ["REAKTLY_API_KEY"]},
    timeout=30,
)
response.raise_for_status()
print(response.json()["jobId"])

Batching an initial load

Send 50–100 items per request with /ingest/bulk. Keep externalIds stable across syncs — they are the deduplication key, and re-sending the same item updates it rather than creating a duplicate.

const chunk = items.slice(0, 100).map(toIngestionItem);
await fetch('https://api.reaktly.com/ingest/bulk', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-api-key': process.env.REAKTLY_API_KEY!,
  },
  body: JSON.stringify({ items: chunk }),
});

Keeping in sync

GoalApproach
Skip unchanged contentSend data.hash; unchanged items are skipped (Change detection)
Update prices or URLs onlyoptions.metadataOnly: true updates metadata without re-embedding
Remove deleted itemsPOST /ingest/cleanup with the full list of surviving externalIds
Prioritise user-triggered importsoptions.priority: "high"

Next steps

On this page