API reference
Every request below is real — this isn't illustrative pseudocode.
Authentication
Every request needs an Authorization: Bearer <api key> header. Create a key from Dashboard → API keys — it's shown once, at creation; only a one-way hash is stored afterward, so if it's lost you have to revoke it and create a new one.
curl https://your-domain/api/v1/agents \
-H "Authorization: Bearer YOUR_API_KEY"List agents
GET /api/v1/agents — returns every agent in the key's workspace.
{
"agents": [
{ "id": "…", "name": "Support Agent", "model": "gpt-4o-mini", "createdAt": "…" }
]
}Create an agent
POST /api/v1/agents — body { "name": string }, plus optional systemPrompt, model, temperature and websiteUrl. With websiteUrl the site is crawled and the agent is trained on it in the background. Returns the new agent (201).
curl -X POST https://your-domain/api/v1/agents -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" -d '{"name": "Support agent", "websiteUrl": "https://example.com"}'Get an agent
GET /api/v1/agents/{agentId} — the agent's full configuration.
{
"agent": {
"id": "…", "name": "…", "model": "gpt-4o-mini", "temperature": 0.2,
"systemPrompt": "…", "welcomeMessage": "…",
"suggestedMessages": ["…"], "messagePlaceholder": "…", "footerText": null,
"allowedDomains": ["https://example.com"],
"rateLimit": { "messages": 20, "seconds": 240, "message": "…" },
"creditsLimit": null,
"notifications": { "dailyLeads": false, "dailyConversations": false },
"appearance": {
"displayName": "…", "theme": "light", "accentColor": "#7c3aed",
"cornerRadius": "full", "fontFamily": "Inter", "fontSize": 16,
"bubblePosition": "right", "bubbleIcon": "chat", "bubbleColor": null,
"showToPercentOfVisitors": null,
"controls": { "copyMessage": true, "feedback": true,
"deleteConversation": true, "voiceDictation": true }
},
"chatBubbleEnabled": true, "autoRetrain": "off",
"lastTrainedAt": "…", "createdAt": "…"
}
}Update an agent
PATCH /api/v1/agents/{agentId} — send only what you want to change, in the same shape as above: name, systemPrompt, model, temperature, the chat messages, allowedDomains, rateLimit, creditsLimit, notifications, anything under appearance, and autoRetrain ("off", "daily", "weekly" or "monthly"; needs a plan with auto-resync). Unknown fields are rejected with a 400 that names them.
Delete an agent
DELETE /api/v1/agents/{agentId} — removes the agent with its sources, conversations and connected integrations. This can't be undone.
Clone an agent
POST /api/v1/agents/{agentId}/clone — optional body { "name": string }. Creates a complete copy: settings, sources (already trained, nothing is re-embedded), actions and procedures. Conversations, leads and channel connections stay with the original.
Sources
GET /api/v1/agents/{agentId}/sources lists sources with their status. POST adds one:
{ "type": "website", "url": "https://example.com", "autoRetrain": "weekly" }
{ "type": "text", "title": "Refund policy", "content": "…" }
{ "type": "qna", "question": "Do you ship abroad?", "answer": "Yes, to 40 countries." }Text and Q&A sources are trained before the call returns (201). A website is crawled in the background (202, status processing). DELETE /api/v1/agents/{agentId}/sources/{sourceId} removes a source.
Train an agent
POST /api/v1/agents/{agentId}/train starts a training run that re-fetches every website, sitemap, video and Google Doc source (202). GET on the same URL reports progress:
{
"training": {
"status": "training", // untrained | training | ready | failed
"sources": { "total": 3, "ready": 2, "processing": 1, "failed": 0 },
"characters": 182340,
"lastTrainedAt": "…"
}
}Send a message
POST /api/v1/agents/{agentId}/chat — the flagship endpoint. Same RAG pipeline as every other channel: retrieval, citations, and credits usage all behave identically to the widget.
curl -X POST https://your-domain/api/v1/agents/{agentId}/chat \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"message": "Hello", "conversationId": "optional-to-continue-a-thread"}'{
"conversationId": "…",
"message": {
"id": "…", "role": "assistant", "content": "…",
"citations": [{ "chunkId": "…", "fileName": "…", "score": 0.87 }]
}
}Omit conversationId to start a new thread; pass the one you got back to continue an existing one (up to the last 20 messages of history are sent to the model).
Sync Shopify products
POST /api/v1/agents/{agentId}/sources/shopify — adds or updates up to 100 products from a Shopify store as knowledge for the agent. The store appears as one source under Data sources. A product whose text hasn't changed is skipped. This is what the Zetra Shopify app calls.
curl -X POST https://your-domain/api/v1/agents/{agentId}/sources/shopify \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"shop": "your-store.myshopify.com", "docs": [
{"id": "gid://shopify/Product/1", "title": "Blue mug",
"url": "https://your-store.com/products/blue-mug", "text": "Blue mug\nHolds 350 ml.\nPrice: 12.00"}
]}'{ "ok": true, "documentId": "…", "upserted": 1, "unchanged": 0, "products": 1 }POST /api/v1/agents/{agentId}/sources/shopify/delete — body { "id": string, "shop"?: string }. Removes one product; returns { "ok": true, "deleted": 0 | 1 }.
Errors
A missing or invalid key returns 401. An agent not found (or not in your workspace) returns 404. Exceeding your plan's credits returns 402 with { "code": "CREDITS_EXCEEDED" }. A model whose vendor API key isn't configured returns 503 with { "code": "AI_NOT_CONFIGURED" } — never a fabricated answer.
See Channels for the iOS/Android guides that call this same endpoint from a mobile app, since no native Zetra SDK is published yet.