API Reference
The InformedAI API is a REST API that uses JSON request/response bodies and Server-Sent Events (SSE) for streaming AI responses.
Base URL:
https://api.informedai.app/api/v1
Authentication#
All authenticated endpoints require a Bearer token in the Authorization header:
curl -H "Authorization: Bearer wsk_your_key" \
https://api.informedai.app/api/v1/document-typesKey Types#
InformedAI uses four key types, each scoped to specific operations:
| Prefix | Name | Scope |
|--------|------|-------|
| wsk_ | Workspace Secret Key | Full server-side access (document types, documents, sessions, knowledge library) |
| pak_ | Public Access Key | Client-side widget authentication (domain-validated) |
| ssk_ | Sync Secret Key | Data sync operations (one key per sync source) |
| aak_ | Admin Access Key | Admin chatbot access (domain-validated) |
Keep wsk_ and ssk_ keys on your server. Only pak_ keys are safe for client-side use. Website agents and smart questionnaires use domain-based auth instead of API keys.
Document Types#
All document type endpoints require a wsk_ key.
Create Document Type#
POST /document-types
{
"name": "blog_post",
"displayName": "Blog Post",
"schema": {
"fields": {
"title": {
"type": "string",
"label": "Title",
"description": "The blog post title"
},
"body": {
"type": "richtext",
"label": "Body",
"description": "Main content"
}
}
}
}Field types: string, number, boolean, richtext, array, image
Each field in the schema becomes a task the AI assistant can work on. The description tells the AI what kind of content to generate for that field.
List Document Types#
GET /document-types
Returns all document types in the workspace.
Get Document Type#
GET /document-types/:id
Returns a single document type with its schema and task configurations.
Update Document Type#
PUT /document-types/:id
Update the schema, display name, or task configs. Accepts partial updates.
{
"displayName": "Updated Name",
"schema": { "fields": { "..." : "..." } },
"taskConfigs": {
"title": {
"enabled": true,
"templateId": "template_abc",
"quickActions": [
{ "label": "Write title", "prompt": "Write a compelling title" }
],
"greeting": "Let me help you write a title."
}
}
}Task config fields:
| Field | Type | Description |
|-------|------|-------------|
| enabled | boolean | Whether the AI can work on this field (default: true) |
| templateId | string | Custom prompt template ID |
| quickActions | array | One-click action buttons shown to the user |
| greeting | string | Custom greeting when this task starts |
Discover Document Type (AI)#
POST /document-types/discover
{
"query": "I need a schema for electrical bid proposals"
}Uses AI to search the knowledge library and generate a suggested document type schema. Returns a JSON object with discovered fields.
Delete Document Type#
DELETE /document-types/:id
Returns 204 No Content.
Documents#
All document endpoints require a wsk_ key.
Create Document#
POST /documents
{
"documentTypeId": "dt_abc123",
"data": {}
}List Documents#
GET /documents
Query parameters:
| Parameter | Type | Description |
|-----------|------|-------------|
| documentTypeId | string | Optional. Filter by document type |
Returns all documents in the workspace, optionally filtered by document type.
Get Document#
GET /documents/:id
Returns the document with its current data and associated document type.
Update Document Field#
PATCH /documents/:id/field
{
"field": "title",
"value": "My New Title"
}Updates a single field and creates a version history entry.
Get Document History#
GET /documents/:id/history
Returns version history for the document, ordered by version descending.
Restore Document Version#
POST /documents/:id/restore/:version
Restores the document data to a specific version from history.
Delete Document#
DELETE /documents/:id
Returns 204 No Content.
Widget Sessions#
Widget endpoints require a Pool Access Key (pak_ prefix) in the Authorization header. The API also validates the request origin against your environment's allowed domains.
Create Session#
POST /widget/sessions
{
"documentTypeId": "dt_abc123",
"externalId": "your-record-id",
"initialData": {
"title": "Draft Title"
}
}| Field | Type | Description |
|-------|------|-------------|
| documentTypeId | string | Required. Document type to create a session for |
| externalId | string | Optional. Your object's ID for idempotent document linking |
| initialData | object | Optional. Current field values to sync |
When externalId is provided, the API returns the existing session if one already exists for that external ID, making the call idempotent.
Response:
{
"session": { "id": "sess_abc", "status": "active", "..." : "..." },
"document": { "id": "doc_abc", "data": {}, "..." : "..." },
"documentType": { "id": "dt_abc", "name": "blog_post", "..." : "..." }
}Get Session#
GET /widget/sessions/:id
Returns the session with its messages formatted for the widget.
Send Message (SSE)#
POST /widget/sessions/:id/message
{
"message": "Write a compelling introduction",
"currentFieldValues": { "title": "My Post" }
}| Field | Type | Description |
|-------|------|-------------|
| message | string | Required. The user's message |
| currentFieldValues | object | Optional. Current form values for context |
Returns a Server-Sent Events stream. See SSE Streaming below.
Send Quick Action#
POST /widget/sessions/:id/quick-action
{
"action": "task_action:write_title",
"currentFieldValues": {}
}| Action format | Description |
|---------------|-------------|
| select_task:field_name | Switches the active task to the specified field |
| task_action:action_id | Triggers a quick action defined in the task config |
Returns either a JSON response (for select_task) or an SSE stream (for task_action).
Apply Pending Value#
POST /widget/sessions/:id/apply
Applies the AI-suggested value to the document field. After applying, automatically advances to the next task that has a pending value.
Response:
{
"session": { "..." : "..." },
"appliedField": "title",
"appliedValue": "10 Tips for Better Writing"
}Skip Task#
POST /widget/sessions/:id/skip
Skips the current task and advances to the next field. If there are pending values on other tasks, auto-advances to the next task with a pending value.
Resume Session#
POST /widget/sessions/:id/resume
Resumes an abandoned or timed-out session. Preserves the full conversation history and document state.
Heartbeat#
POST /widget/sessions/:id/heartbeat
Sends a heartbeat to keep the session active. Updates the lastActivityAt timestamp used for session timeout tracking.
Response:
{ "success": true }Get Analytics Run#
GET /widget/sessions/:id/analytics-runs/:runId
Returns the results of an analytics run performed during the session, including the structured breakdown and matched results.
End Session#
POST /widget/sessions/:id/end
Marks the session as ended. Ended sessions cannot be resumed.
Response:
{ "success": true }Knowledge Library#
All library endpoints require a wsk_ key.
Add Document#
POST /library
{
"name": "Product Guide",
"content": "Full text content to ingest...",
"category": "guides",
"description": "Complete product documentation",
"tags": ["product", "guide"],
"metadata": { "version": "2.0" }
}| Field | Type | Description |
|-------|------|-------------|
| name | string | Required. Document name |
| content | string | Required. Full text content |
| category | string | Optional. Category for organization |
| description | string | Optional. Brief description |
| tags | string[] | Optional. Searchable tags |
| metadata | object | Optional. Custom metadata |
The content is automatically chunked, embedded (via Voyage AI), and indexed for semantic search. The AI assistant uses this knowledge when generating content.
List Documents#
GET /library
Query parameters:
| Parameter | Type | Description |
|-----------|------|-------------|
| category | string | Optional. Filter by category |
Returns all documents in the knowledge library.
Get Document#
GET /library/:id
Returns a single knowledge library document with its metadata.
Update Document#
PATCH /library/:id
{
"name": "Updated Name",
"category": "new-category",
"description": "Updated description",
"tags": ["updated"],
"metadata": { "version": "3.0" }
}Updates document metadata. All fields are optional.
Delete Document#
DELETE /library/:id
Deletes the document and asynchronously cleans up its knowledge chunks. Returns 204 No Content.
List Categories#
GET /library/categories
Returns distinct categories with document counts.
Get Library Stats#
GET /library/stats
Returns statistics about the knowledge library.
Response:
{
"totalDocuments": 42,
"totalCategories": 5
}List Chunks#
GET /library/chunks
Query parameters:
| Parameter | Type | Description |
|-----------|------|-------------|
| sourceType | string | Required. Source type (e.g., kb_document, sync_category) |
| sourceId | string | Required. Source ID |
Returns the knowledge chunks for a specific source.
Response:
{
"chunks": [{ "id": "...", "content": "...", "..." : "..." }],
"totalCount": 15
}Get Document Chunks#
GET /library/:id/chunks
Returns the knowledge chunks for a specific knowledge library document.
Get Retrieval Logs#
GET /library/retrieval-logs
Query parameters:
| Parameter | Type | Description |
|-----------|------|-------------|
| sourceId | string | Required. Source ID to filter by |
| limit | number | Optional. Max results (default: 50) |
Returns retrieval logs showing which chunks were retrieved for AI queries against a specific source.
Sync API#
The Sync API is used by the @informedai/sync SDK to push data from your backend into the InformedAI knowledge library. All sync endpoints require an ssk_ key.
See the Sync SDK documentation for the recommended way to use these endpoints.
Get Source#
GET /sync/source
Returns the sync source details, including categories and their stats. Also updates the heartbeat timestamp.
Register Category#
POST /sync/categories
{
"name": "projects",
"displayName": "Projects",
"columns": ["title", "description", "tech_stack"]
}Creates or updates a sync category. Categories organize your synced data by type.
List Categories#
GET /sync/categories
Returns all categories for this sync source.
Push Data#
POST /sync/categories/:category/data
{
"records": [
{ "id": "proj_1", "title": "My Project", "description": "..." },
{ "id": "proj_2", "title": "Other Project", "description": "..." }
]
}Push one or more records to a sync category. Records are cached and converted into knowledge chunks for RAG queries.
Response:
{
"stored": 2,
"skipped": 0,
"category": "projects",
"totalShards": 4,
"totalChars": 1250,
"totalRows": 2
}Delete Record#
DELETE /sync/categories/:category/data/:externalId
Deletes a single record from the sync category. Returns 204 No Content.
Rebuild Category#
POST /sync/categories/:category/rebuild
Force rebuild knowledge chunks for a category. Useful after bulk changes or if data gets out of sync.
Poll Recovery Requests#
GET /sync/requests
Query parameters:
| Parameter | Type | Description |
|-----------|------|-------------|
| limit | number | Optional. Max requests to return |
Returns pending recovery requests. When the system needs data that's missing from cache, it creates recovery requests that the SDK polls for and resends.
Fulfill Recovery Request#
POST /sync/requests/:requestId/fulfill
Marks a recovery request as fulfilled after the data has been re-synced.
Heartbeat#
POST /sync/heartbeat
Sends a heartbeat to indicate the sync SDK is active and connected.
Admin Chatbot#
Send messages to your workspace's knowledge library chatbot. Requires an aak_ key. The API also validates the request origin against the admin agent's allowed domains.
Send Message (SSE)#
POST /admin-chatbot/message
Authorization: Bearer aak_your_key
{
"message": "What products do we offer?",
"history": [],
"systemPrompt": "You are a helpful assistant that answers questions about our products."
}| Field | Type | Description |
|-------|------|-------------|
| message | string | Required. The user's message |
| history | array | Optional. Previous conversation messages ({ role, content }) |
| systemPrompt | string | Optional. Custom system prompt for the chatbot |
Returns a Server-Sent Events stream. See SSE Streaming below.
Get Status#
GET /admin-chatbot/status
Returns whether the admin chatbot is configured for the workspace.
Response:
{
"configured": true,
"environmentId": "env_abc123"
}Website Agent#
Send messages to a website agent. Uses domain-based authentication — no API key required, but the request origin must match the agent's allowed domains.
Send Message (SSE)#
POST /website-agent/:agentId/message
{
"message": "How do I reset my password?",
"history": []
}| Field | Type | Description |
|-------|------|-------------|
| message | string | Required. The user's message |
| history | array | Optional. Previous conversation messages ({ role, content }) |
Returns a Server-Sent Events stream.
Smart Questionnaire#
Guide users through step-by-step questionnaires that match answers against the knowledge base. Uses domain-based authentication — no API key required.
Get Steps#
GET /smart-questionnaire/:questionnaireId/steps
Returns the questionnaire step definitions (only enabled steps).
Response:
[
{
"name": "budget",
"question": "What is your budget range?",
"options": ["Under $500", "$500-$1000", "Over $1000"],
"multiSelect": false,
"answerKey": "budget"
}
]Submit Step Answer#
POST /smart-questionnaire/:questionnaireId/step/:stepName
{
"message": "I need something waterproof",
"history": []
}Submit a free-text answer for a specific step. Option-based answers are handled client-side with zero API calls.
Response:
{
"message": "Great, waterproof it is!",
"answer": "waterproof",
"action": "advance"
}Match Answers#
POST /smart-questionnaire/:questionnaireId/match
{
"answers": {
"budget": { "value": "mid-range", "type": "option" },
"requirements": { "value": "waterproof and durable", "type": "free-text" }
}
}Matches collected answers against the knowledge base and returns ranked results.
Get Results (SSE)#
POST /smart-questionnaire/:questionnaireId/results
{
"matches": [],
"message": "Tell me more about the first option",
"history": []
}Returns initial results from matched answers. When message and history are included, the response is an SSE stream for follow-up conversation about the results.
SSE Streaming#
Message and quick-action endpoints return a Server-Sent Events stream. Each event has a type field:
| Event Type | Description |
|------------|-------------|
| content | AI response text chunk |
| session_update | Updated session state (task changes, pending values) |
| done | Stream complete |
| error | Error occurred during processing |
Streaming Endpoints#
The following endpoints return SSE streams:
POST /widget/sessions/:id/messagePOST /widget/sessions/:id/quick-action(fortask_actiontype)POST /admin-chatbot/messagePOST /website-agent/:agentId/messagePOST /smart-questionnaire/:id/results(whenmessageis included)
Example: Consuming the Stream#
const response = await fetch(`${API_URL}/widget/sessions/${id}/message`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer pak_your_key',
},
body: JSON.stringify({
message: 'Write a title',
currentFieldValues: { body: 'Article content...' },
}),
});
const reader = response.body!.getReader();
const decoder = new TextDecoder();
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n');
buffer = lines.pop()!;
for (const line of lines) {
if (line.startsWith('data: ')) {
const event = JSON.parse(line.slice(6));
switch (event.type) {
case 'content':
// Append AI text to your UI
appendText(event.content);
break;
case 'session_update':
// Update session state (new pending values, task changes)
updateSession(event.session);
break;
case 'done':
// Stream finished
break;
case 'error':
console.error(event.error);
break;
}
}
}
}The React SDK handles SSE parsing automatically. You only need to consume the stream directly if you're building a custom integration.
Error Responses#
All errors follow a consistent JSON format:
{
"error": "Human-readable error message",
"code": "ERROR_CODE",
"status": 400
}Common Error Codes#
| Status | Code | Description |
|--------|------|-------------|
| 400 | VALIDATION_ERROR | Invalid request body or parameters |
| 401 | UNAUTHORIZED | Missing or invalid API key |
| 403 | FORBIDDEN | Key lacks permission for this operation or domain not allowed |
| 404 | NOT_FOUND | Resource does not exist |
| 409 | CONFLICT | Resource already exists (duplicate externalId) |
| 429 | RATE_LIMITED | Too many requests (billing limit exceeded) |
| 500 | INTERNAL_ERROR | Server error |