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.
List Libraries
Section titled “List Libraries”Before ingesting, you need the target library’s ID. Use the library listing endpoint to discover available libraries and check embedding compatibility:
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.
If your API key is restricted to a single library, only that library’s endpoints will accept it. Which visitors can retrieve what you ingest is governed separately by audience labels.
Ingest Endpoint
Section titled “Ingest Endpoint”Send a POST request with the URL of the file to ingest, or raw text content for text-native sources:
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 Northwind brief?\n**Bob:** Yes, shared it in #northwind-internal...", "contentType": "text/markdown", "fileName": "#general - May 27 2026", "externalId": "slack-C01234-2026-05-27" }'Request Body
Section titled “Request Body”| Field | Type | Required | Description |
|---|---|---|---|
url |
string | One of | HTTPS URL of the file to download and ingest. |
content |
string | One of | Raw text content to ingest directly without downloading a file. |
contentType |
string | No | MIME type for content. Defaults to text/plain. Text-only values are allowed. |
fileName |
string | No | Display name for the source. Inferred from URL or content type if omitted. |
externalId |
string | No | Caller-provided identifier for upsert semantics. Max 255 chars. |
latitude |
number | No | Optional source latitude in WGS84 decimal degrees. |
longitude |
number | No | Optional source longitude in WGS84 decimal degrees. |
keywords |
string[] | No | Domain keywords for this source, up to 5, each 64 characters or fewer. Replaces automatic keyword extraction. An empty array means no keywords. Omit the field to keep automatic extraction. |
Coordinates are optional, but when you provide them you must send both latitude and longitude together. Ragtime copies these values to the stored chunks so later retrieval can filter by location.
Each source is extracted and embedded in the background after the request returns. That processing spends your organization’s embedding credits.
Upsert with externalId
Section titled “Upsert with externalId”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.
Supported File Types
Section titled “Supported File Types”| MIME Type | Extension |
|---|---|
application/pdf |
|
text/plain |
.txt |
text/markdown |
.md |
text/csv |
.csv |
text/html |
.html |
application/vnd.openxmlformats-officedocument.wordprocessingml.document |
.docx |
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet |
.xlsx |
application/vnd.ms-excel.sheet.macroEnabled.12 |
.xlsm |
application/vnd.openxmlformats-officedocument.presentationml.presentation |
.pptx |
application/vnd.openxmlformats-officedocument.presentationml.slideshow |
.ppsx |
application/vnd.ms-powerpoint.presentation.macroEnabled.12 |
.pptm |
Spreadsheets are converted to Markdown tables, one section per visible sheet, with the
column header repeated on every chunk. Workbooks over 20,000 data rows (counted across
all sheets) are rejected — the source is marked failed with an explanatory message.
Presentations are converted to one Markdown section per visible slide, headed by the slide number and title, including tables and speaker notes. Slides whose content is only imagery yield no text; if a whole deck is image-based it is rejected — export it to PDF and upload that instead, so the text is read via OCR.
Responses
Section titled “Responses”// 201 Created — queued for processing{ "sourceId": "a1b2c3d4-...", "status": "queued", "message": "Source queued for processing"}
// 409 Conflict: the same content is already in this library{ "code": "conflict", "error": "This content already exists in the library.", "retryable": false, "hint": "Use the existing source in `details.sourceId`. Requests that send an `externalId` skip this check.", "details": { "sourceId": "e5f6g7h8-...", "status": "duplicate" }}Duplicate detection compares the content within the library, and only runs when no externalId is sent. The existing source’s id is in details.sourceId. Errors use the standard v1 shape:
// 415 Unsupported Media Type{ "code": "unsupported_media_type", "error": "Unsupported file type: application/zip. Allowed: application/pdf, …", "retryable": false}| Status | Code | Meaning |
|---|---|---|
201 |
Source accepted and queued for processing. | |
400 |
invalid_request |
Invalid request (missing URL/content, bad format, blocked URL, invalid contentType, or remote URL unreachable/timed out). error names the field. |
404 |
not_found |
Library not found or not linked to the project. |
409 |
conflict |
Duplicate content already exists (when no externalId). details.sourceId names the existing source. |
413 |
payload_too_large |
File or inline content exceeds the maximum size (default: 1 MB for content). |
415 |
unsupported_media_type |
Unsupported file type. |
503 |
unavailable |
Storage not configured for this organization. |
Authentication, scope and project refusals (401, 403) and rate limiting (429) work the same on every endpoint. See Errors and Rate limits.
Completion Webhook
Section titled “Completion Webhook”Subscribe to the source_ingested webhook event to be notified when a source finishes processing. Configure this in Dashboard → Integrations → Webhooks.
Location-aware RAG
Section titled “Location-aware RAG”Location-aware RAG lets you attach optional GPS coordinates to ingested sources and use the chat user’s location at retrieval time. This is useful for branch finders, regional support, delivery coverage, and any assistant where proximity matters as part of the answer.
When to use it
Section titled “When to use it”Use this feature when:
- your knowledge varies by region, branch, store, campus, or service area
- you want the assistant to prefer nearby sources over distant ones
- you need a hard location filter, but still want semantic relevance to matter
If the assistant does not have Require GPS location enabled in the dashboard, any location payload sent by the client is ignored and the chat will not request browser location permission.
Ingestion coordinates
Section titled “Ingestion coordinates”When you ingest a source, you can optionally attach:
latitudelongitude
Both values must be provided together and use WGS84 decimal degrees.
Chat request payload
Section titled “Chat request payload”When Require GPS location is enabled, the chat client sends the user’s location with each request:
{ "location": { "latitude": 52.3702, "longitude": 4.8952 }, "radius": 25000, "radiusUnit": "km"}locationis the user’s current GPS position.radiusis optional; the assistant falls back to the dashboard default when omitted.radiusUnitacceptskmormiles.- The browser must grant geolocation permission before the assistant can use this data.
Dashboard settings
Section titled “Dashboard settings”The Interaction settings expose four geo controls:
require_geolocation: turn on browser GPS requests and location-aware retrieval.geo_radius_default: default radius used when the chat request does not include one.geo_radius_unit: default radius unit.prioritize_by_distance: blend proximity into ranking instead of using proximity as a hard filter only.
Behavior
Section titled “Behavior”With location enabled, retrieval filters knowledge to the configured radius and can optionally favor closer matches when prioritize_by_distance is on. Without it, Ragtime behaves like standard semantic retrieval.
Batch Ingest
Section titled “Batch Ingest”To ingest multiple files at once, send an items array instead of a single url. Up to 20 items per request:
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, latitude, longitude, keywords). 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.
Source Status
Section titled “Source Status”After ingesting a source, poll its processing status to track progress. This endpoint requires the ingest scope. A key restricted to a single library can poll the sources in its own library; any other source returns 404.
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", "keywords": [], "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", ...}| Status | Description |
|---|---|
pending |
Source uploaded, waiting in queue. |
processing |
Worker is extracting and embedding chunks. Check progress for details. |
completed |
All chunks processed successfully. |
partial |
Completed with warnings — some chunks could not be processed. See warnings array. |
failed |
Processing failed entirely. See error field. |
keywords lists the keywords the source contributes to the assistant’s topic list. It is empty until ingestion finishes, unless you supplied keywords at ingest time.
Using with N8N
Section titled “Using with N8N”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 }}"}