Skip to content

Ingest API

Programmatically add knowledge sources to your assistant’s libraries by providing a URL or raw text content. Ideal for automating content sync from CMS, documentation platforms, Slack exports, webhooks, or N8N workflows.

Before ingesting, you need the target library’s ID. Use the library listing endpoint to discover available libraries and check embedding compatibility:

Terminal window
curl https://your-ragtime-instance.com/api/v1/projects/{projectId}/libraries \
-H "Authorization: Bearer rt_live_YOUR_KEY_HERE"
# Response:
{
"libraries": [
{
"id": "lib-uuid-...",
"name": "Product Docs",
"embeddingProvider": "openai",
"embeddingModel": "text-embedding-3-large",
"compatible": true,
"createdAt": "2026-01-15T10:00:00Z"
}
]
}

Libraries marked compatible: true use the same embedding model as your organization’s current settings. Ingesting into incompatible libraries still works, but those sources won’t appear in search results until the models are aligned.

Send a POST request with the URL of the file to ingest, or raw text content for text-native sources:

Terminal window
curl -X POST https://your-ragtime-instance.com/api/v1/projects/{projectId}/libraries/{libraryId}/ingest \
-H "Authorization: Bearer rt_live_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/docs/guide.pdf",
"fileName": "guide.pdf",
"externalId": "guide-v2"
}'
curl -X POST https://your-ragtime-instance.com/api/v1/projects/{projectId}/libraries/{libraryId}/ingest \
-H "Authorization: Bearer rt_live_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{
"content": "# #general - May 27\n\n**Alice:** Has anyone seen the Cenitex brief?\n**Bob:** Yes, shared it in #cenitex-internal...",
"contentType": "text/markdown",
"fileName": "#general - May 27 2026",
"externalId": "slack-C01234-2026-05-27"
}'
FieldTypeRequiredDescription
urlstringOne ofHTTPS URL of the file to download and ingest.
contentstringOne ofRaw text content to ingest directly without downloading a file.
contentTypestringNoMIME type for content. Defaults to text/plain. Text-only values are allowed.
fileNamestringNoDisplay name for the source. Inferred from URL or content type if omitted.
externalIdstringNoCaller-provided identifier for upsert semantics. Max 255 chars.

When you provide an externalId, the API uses upsert semantics: if a source with the same externalId already exists in the target library, the old source and all its chunks are deleted and replaced with the new content. This applies to both URL-based and inline content ingest.

Without externalId, standard content-hash deduplication applies — uploading the exact same file returns 409 Conflict.

MIME TypeExtension
application/pdf.pdf
text/plain.txt
text/markdown.md
text/csv.csv
text/html.html
application/vnd.openxmlformats-officedocument.wordprocessingml.document.docx
// 201 Created — queued for processing
{
"sourceId": "a1b2c3d4-...",
"status": "queued",
"message": "Source queued for processing"
}
// 409 Conflict — duplicate content
{
"sourceId": "e5f6g7h8-...",
"status": "duplicate",
"message": "File already exists in this library"
}
StatusMeaning
201Source accepted and queued for processing.
400Invalid request (missing URL/content, bad format, blocked URL, invalid contentType, or remote URL unreachable/timed out).
401Missing or invalid API key.
403Key doesn’t match the project or lacks ingest scope.
404Library not found or not linked to the project.
409Duplicate content already exists (when no externalId).
413File or inline content exceeds the maximum size (default: 1 MB for content).
415Unsupported file type.
429Rate limit exceeded. Check Retry-After header.
503Storage not configured for this organization.

The ingest endpoint is rate-limited per API key. Default: 30 requests per minute. Rate limit headers are included in every response:

HeaderDescription
X-RateLimit-LimitMaximum requests per window.
X-RateLimit-RemainingRemaining requests in current window.
X-RateLimit-ResetUnix timestamp when the window resets.
Retry-AfterSeconds to wait (only on 429).

Subscribe to the source_ingested webhook event to be notified when a source finishes processing. Configure this in Dashboard → Assistant → Webhooks.

To ingest multiple files at once, send an items array instead of a single url. Up to 20 items per request:

Terminal window
curl -X POST https://your-ragtime-instance.com/api/v1/projects/{projectId}/libraries/{libraryId}/ingest \
-H "Authorization: Bearer rt_live_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{
"items": [
{ "url": "https://example.com/docs/guide.pdf", "externalId": "guide-v2" },
{
"content": "# Weekly sync\n\n- Slack thread summary",
"contentType": "text/markdown",
"fileName": "weekly-sync.md",
"externalId": "slack-C01234-2026-05-27"
},
{ "url": "https://example.com/docs/changelog.md" }
]
}'

Each item in the array accepts the same fields as a single ingest request (url, content, contentType, fileName, externalId). The response includes a result for every item:

{
"queued": 2,
"failed": 1,
"total": 3,
"results": [
{
"sourceId": "a1b2c3d4-...",
"status": "queued",
"message": "Source queued for processing",
"url": "https://example.com/docs/guide.pdf"
},
{
"sourceId": "e5f6g7h8-...",
"status": "queued",
"message": "Source queued for processing",
"fileName": "weekly-sync.md",
"contentType": "text/markdown"
},
{
"url": "https://example.com/docs/changelog.md",
"status": "error",
"error": "File already exists in this library"
}
]
}

Batch requests return 201 if at least one item was queued, or 422 if all items failed. Individual item errors (duplicates, unsupported types, etc.) are reported in the results array without failing the entire batch.

After ingesting a source, poll its processing status to track progress:

Terminal window
curl https://your-ragtime-instance.com/api/v1/projects/{projectId}/sources/{sourceId} \
-H "Authorization: Bearer rt_live_YOUR_KEY_HERE"
// Processing in progress
{
"sourceId": "a1b2c3d4-...",
"libraryId": "lib-uuid-...",
"name": "guide.pdf",
"type": "application/pdf",
"status": "processing",
"progress": { "current": 12, "total": 45 },
"fileSize": 2048576,
"externalId": "guide-v2",
"createdAt": "2026-03-25T12:00:00Z",
"updatedAt": "2026-03-25T12:00:05Z"
}
// Completed successfully
{
"sourceId": "a1b2c3d4-...",
"status": "completed",
"progress": { "current": 45, "total": 45 },
...
}
// Completed with warnings
{
"sourceId": "a1b2c3d4-...",
"status": "partial",
"warnings": ["Some chunks could not be processed"],
...
}
// Failed
{
"sourceId": "a1b2c3d4-...",
"status": "failed",
"error": "Unsupported file encoding",
...
}
StatusDescription
pendingSource uploaded, waiting in queue.
processingWorker is extracting and embedding chunks. Check progress for details.
completedAll chunks processed successfully.
partialCompleted with warnings — some chunks could not be processed. See warnings array.
failedProcessing failed entirely. See error field.

Use an HTTP Request node to post file URLs or raw text content to the ingest endpoint. Combine with a Schedule trigger or Webhook trigger to automate content sync:

// N8N HTTP Request node configuration:
// Method: POST
// URL: https://your-ragtime-instance.com/api/v1/projects/{projectId}/libraries/{libraryId}/ingest
// Authentication: Header Auth
// Header Name: Authorization
// Header Value: Bearer rt_live_YOUR_KEY_HERE
// Body (JSON):
// URL-based ingest:
{
"url": "{{ $json.fileUrl }}",
"fileName": "{{ $json.fileName }}",
"externalId": "{{ $json.docId }}"
}
// Inline content ingest:
{
"content": "{{ $json.markdown }}",
"contentType": "text/markdown",
"fileName": "{{ $json.title }}",
"externalId": "{{ $json.docId }}"
}