The Shadow-OS agent, as an API
Premium multi-agent reasoning at a fraction of the usual API cost. One REST endpoint, your API key, JSON in & out — with fully isolated conversations so every end-user of your app keeps their own private memory and files. A free monthly tier is included — no credit card required.
Your API keys
Quickstart
Send a POST request to the endpoint below with your API key in the Authorization header.
https://shadow-os-backend.onrender.com/api/v1/agentAuthentication
Every request must include your secret key — as a Bearer token, or via the X-Shadow-API-Key header. Keep it server-side; never expose it in client-side code.
Request body
inputstringrequiredThe prompt / instruction for the agent.session_idstringoptionalThe conversation id. Each distinct value is its OWN isolated conversation — separate memory & files. Reuse it to continue that conversation with full context. Defaults to "default".scopestringoptional"session" (default) isolates memory & files per session_id. "account" shares one memory/file space across all your calls (and enables your account's connected integrations).Response
Files the agent produces
When the agent builds something — a ZIP, a report, code, an image — the response carries it in files. There is no attachment and no multipart body: the signed download_url is the file. Fetch it to get the bytes.
filesis always present — an empty array when the turn produced nothing.download_urlat the top level is a shortcut to the first file, ornull.- Links are signed and time-limited (
exp+sig) — download promptly, or call again for a fresh link. - Files belong to the
session_idthat created them (or to your account underscope: "account").
Conversations & isolation
Building an app that serves many end-users? Every session_id is a fully isolated conversation — its own memory, its own uploaded files, its own context. Nothing bleeds between your users. This is the default; you don't have to do anything to get it.
Uploads follow the same rule — pass the matching session_id (form field) to /api/v1/upload, /api/v1/search and /api/v1/documents so a file is visible only inside its conversation.
Want one shared assistant instead (a single memory across all your calls, plus your account's connected Gmail/Calendar/integrations)? Add "scope": "account" to the body. An isolated conversation is a clean sandbox and intentionally has no access to your account integrations. Billing and quota always stay on your key, regardless of scope.
Endpoints
/api/v1/agentRun the agent on a prompt (chat, reasoning, tools). · 1 quota unit/api/v1/uploadUpload a document (pdf/txt/md/csv/docx) into your knowledge base. · 1 quota unit/api/v1/searchSemantic search over your uploaded documents. · 1 quota unit/api/v1/documentsList the documents in your knowledge base. · free/api/v1/usageYour current quota + lifetime usage statistics. · freeThe session_id matters: an upload is isolated to that conversation, so the agent can only use it when you send the same id. Omit it and the file lands in the default conversation. Use -F "scope=account" to share it across every call on your key instead.
Errors
Errors use standard HTTP status codes and return a JSON body with a machine-readable error and a human-readable detail.
invalid_keyMissing or invalid API key.quota_exceededFree monthly quota reached.rate_limitedToo many requests — retry after a short wait.bad_requestMalformed body, or the 'input' field is missing.Agent Platform API
session_id. The Agent Platform here is for a configured product: a persona + shared org knowledge + your connected integrations, driven by one token that doubles as a human magic-link, a WhatsApp chat, and a REST key. Each end-user still gets their own private memory.Configure an agent (persona, knowledge, rules) once, then run it for any number of end-users. Memory and chat history are isolated per member (via member_key) — the agent learns each person separately and never mixes two people — while knowledge and integrations are shared across the org. Strict per-agent, per-member isolation, fail-closed.
POST {API}/api/agent/run
Content-Type: application/json
{
"token": "sk-agent-…", // the agent token (manager or member)
"input": "Do you deliver to Florentin?",
"member_key": "user-42", // ← per-PERSON: private memory + history
"session_id": "main" // ← conversation id (multi-conversation orgs)
}GET /api/agent/info?token=….Full, durable history (members are not guests): every member’s conversations are saved server-side and listable —
GET /api/agent/threads?token=&member_key= lists a member’s conversations;GET /api/agent/history?token=&member_key=&thread_id= returns one conversation’s messages. Both are scoped to that member (fail-closed) — no one reads another member’s threads.POST {API}/api/v1/agents
Authorization: Bearer sk-shadow-…
{ "template": "support", "fields": { "business_name": "Acme" },
"config": { "webhook": "https://you.com/hook", "collect_contact": true } }
→ { "agent": {…}, "manager_token": "sk-agent-…" } // run it via /api/agent/runsk-shadow-…):·
POST /api/v1/agents — create · GET /api/v1/agents — list · PATCH /api/v1/agents/:id — persona, rules & full config· define your own end-users with
member_key (each gets private memory + a living profile) · separate chats with session_id·
GET /api/agent/threads · GET /api/agent/history — a user's conversations·
config.webhook — we POST escalation AND outcome events to your server in real time·
config.integrations — connect your own HTTP tools the agent calls mid-chat · config.collect_contact, config.fallback, config.tone, config.require_login, config.memory_mode·
POST /api/agents/:id/knowledge (text) · POST /api/agents/:id/knowledge/file (PDF/txt/md/csv/docx) · GET/DELETE …/knowledge·
POST /api/agents/:id/tokens (mint, limits) · POST /api/agents/:id/share (opaque links) · GET /api/agents/:id/members (with profiles)·
GET /api/agents/:id/appointments · GET /api/agents/:id/analytics (leads · bookings · quotes · resolved · handoffs)·
GET /api/agents/:id/escalations + stale-customer alerts · POST …/:eid/answer (the human-in-the-loop)