Ingram Cloud

Documentation

API at a glance

API at a glance

Conventions and the endpoint map. The machine-readable OpenAPI spec is the field-by-field reference; these docs teach the flows.

Conventions

  • Base URL https://api.cloud.ingram.tech: everything under /v1.
  • Headers: Authorization: Bearer <token> (Auth & tokens), plus IC-Api-Version: 2026-05-01 to pin the request/response vocabulary. 2026-05-01 is the only live version today. Omit the header and you get the latest; send one we don't know and the request is refused with unsupported_api_version. Every response echoes the version it served.
  • Errors: the OpenAI-standard envelope, always — so the openai SDK and any OpenAI-compatible client parse our failures unchanged:
{ "error": { "message": "…", "type": "invalid_request_error",
             "param": null, "code": "model_key_missing" } }

Match on code (our stable slug); type is the OpenAI category (invalid_request_error, authentication_error, permission_error, rate_limit_error, api_error). Every possible code is enumerated on the Error schema in the OpenAPI spec — the catalog to generate exhaustive client handling from. The request id is the X-Request-Id response header — log it; show message to humans.

  • Idempotency: send an Idempotency-Key header on creates; replays return the original response instead of duplicating. This covers streaming run creation too: a retried key returns a run.duplicate pointer rather than starting a second run. Resources with a natural key also upsert on it: re-POST /v1/smiths with an existing live external_id returns that smith (200) rather than erroring.
  • One turn per smith: a smith runs one turn at a time, on every run surface — its memory is a single doc shared by all its conversations. A second concurrent run returns 400 conversation_locked; retry in a few seconds. See one run at a time.
  • Two dialects, one rule: OpenAI-mirrored resources (/v1/files, /v1/vector_stores, /v1/conversations, /v1/embeddings, and the model surfaces) speak the OpenAI dialect end-to-end — unix-second timestamps, 200 on create, 200 with a *.deleted ack on delete, and the OpenAI list envelope. Every other resource is native — ISO-8601 timestamps, 201 on create, 204 on delete, and the keyset list envelope.
  • Pagination, native dialect: list endpoints take limit + cursor and return { data, next_cursor, has_more }, newest first. The cursor is opaque — pass the previous page's next_cursor straight back; never parse it. Pull the next page while has_more is true. The run and event feeds add their own filters (since, status, external_id_prefix, …) on top of the same cursor. Fixed-size config lists (providers, model keys, the catalogs) return bare { data } — they are bounded by construction.
  • Pagination, OpenAI dialect: lists take limit + order + after (an object id) and return { object: "list", data, first_id, last_id, has_more }; pass last_id back as after while has_more is true.
  • Filtering: GET /v1/smiths filters by exact external_id, customer_id, or agent_id, and segments by external_id_prefix (matches one namespace, e.g. anon:). GET /v1/runs takes the same external_id_prefix to pull one segment's conversation history (plus smith_id, agent_id — every run across one agent's smiths — and status).
  • Ids: prefixed and sortable: smt_ (smith), agt_ (agent), run_, thr_, cnv_ (conversation), apr_, evt_, cus_, trc_. A run and its trace share a suffix (run_Xtrc_X). Thread ids are yours if you pass them, minted with thr_ if you don't.
  • Limits: no published rate limits yet (fair use); synchronous runs hold the connection for the whole turn, so prefer streaming for long ones.

Endpoint map

ResourceEndpoints
SmithsPOST/GET /v1/smiths · GET/PATCH/DELETE /v1/smiths/{sid}
Config revisionsGET /v1/smiths/{sid}/revisions · POST …/revisions/{n}/restore
AgentsPOST/GET /v1/agents · GET/PATCH/DELETE /v1/agents/{aid} · POST/GET …/versions · POST …/rollout · POST …/attach · POST /v1/agents/import · POST/GET …/{aid}/ui · GET/DELETE …/ui/{name} · GET …/ui/{name}/content (MCP Apps UI templates, multipart upload; /content serves the bundle bytes with a content-hash ETag — see MCP Apps)
RunsPOST/GET /v1/smiths/{sid}/runs · GET …/runs/{rid} · GET …/runs/{rid}/events (SSE) · POST …/runs/{rid}/submit · POST …/runs/{rid}/replay · GET /v1/runs
EmbeddingsPOST /v1/embeddings (OpenAI-compatible text→vector; runs on your OpenAI key, scope embeddings:write — see embeddings)
OpenAI-compatiblePOST /v1/chat/completions · POST /v1/responses · GET /v1/responses/{id} · POST /v1/responses/{id}/cancel (retrieve or stop a response — the path to background: true, see openai-compat) (stream + non-stream; smith token = the smith, the user field = its external_id, or IC-Smith-Id header; user + an IC-Agent-Id header lazily provisions the (external_id, agent) smith). Honors the standard request fields: model (inference LLM override), system/instructions (appended per turn), tools (client-side function-call loop, or a hosted {"type":"file_search"} declaration — see retrieval) with tool_choice (auto/none/required/a named function), reasoning_effort / reasoning.effort (reasoning depth, mapped to each provider's native control — see models), include (file_search_call.results), response_format/text.format (enforced json_schema structured outputs — alone against a toolless agent it's a stateless one-shot, otherwise it types the final message only and the turn keeps its tools), and multimodal image and file parts. A cut-off turn finishes length on Chat Completions and incomplete (with incomplete_details) on Responses — see openai-compat.
ConversationsPOST/GET /v1/conversations · GET/POST/DELETE /v1/conversations/{cnvId} · GET …/{cnvId}/items (OpenAI Conversations API over a thread of runs; pass the cnv_ id as conversation on /v1/responses — see conversations)
FilesPOST/GET /v1/files (multipart upload · list uploads) · GET/DELETE /v1/files/{fid} · GET …/files/{fid}/content (bytes; inline conversation files stay reachable by id but unlisted; scopes files:read/files:write)
Vector storesPOST/GET /v1/vector_stores · GET/POST/DELETE /v1/vector_stores/{vsId} · POST/GET …/files · GET/POST/DELETE …/files/{fid} · GET …/files/{fid}/content · POST/GET …/file_batches, POST …/file_batches/{bid}/cancel, GET …/file_batches/{bid}/files · POST …/search (scopes vector_stores:read/vector_stores:write — see retrieval)
MemoryGET/PUT /v1/smiths/{sid}/memory (working-memory doc) · POST …/memory/recall (semantic recall over past messages)
Tools (MCP)GET /v1/tenant/mcp · GET/PUT/DELETE /v1/tenant/mcp/{name} · POST …/mcp/{name}/refresh · GET /v1/tenant/hosted_tools
SandboxGET /v1/tenant/sandbox_secrets · PUT/DELETE …/sandbox_secrets/{name} (environment the run_command box is launched with; values are never echoed, admin-only — see sandbox)
CatalogGET /v1/catalog · GET /v1/catalog/{slug} (curated MCP integration presets)
ApprovalsGET /v1/approvals[?status=] · GET /v1/approvals/{id}
ConnectionsGET/POST /v1/smiths/{sid}/connections · GET/PATCH/DELETE …/{cid} · POST …/{cid}/refresh · POST …/connections/authorize (start OAuth) · GET /v1/oauth/callback/{provider} (browser redirect)
DeploymentsGET/POST /v1/deployments · GET/PATCH/DELETE /v1/deployments/{depid} (target: a smith or an agent catch-all) · POST /v1/deployments/{depid}/mcp (the deployment's MCP server, JSON-RPC 2.0 over Streamable HTTP; every method past initialize runs as one smith — a smith token is that smith, a tenant-admin token names one with IC-Smith-Id, optional only on a smith target) · GET /v1/hosted/{depid} · POST /v1/hosted/{depid}/chat (public hosted-page metadata + chat, no auth) · GET/PUT/DELETE /v1/tenant/telegram · GET/PUT/DELETE /v1/tenant/slack · GET /v1/slack/oauth/{tenant} (browser redirect) · GET/PUT/DELETE /v1/tenant/whatsapp · GET/POST /v1/whatsapp/webhook (Meta verify + inbound, app-level) · GET/PUT/DELETE /v1/tenant/discord · POST /v1/discord/webhook/{tenant} (Ed25519-verified interactions) · GET/PUT/DELETE /v1/tenant/email · GET/POST/DELETE /v1/tenant/email/suppressions
Inbound eventsGET /v1/inbound_events[?source=&smith_id=&since=] · GET /v1/inbound_events/{ievid} (what arrived on a channel, before interpretation — read-only)
Connector OAuthGET /.well-known/oauth-protected-resource/v1/deployments/{depid}/mcp · GET /.well-known/oauth-authorization-server · GET /.well-known/jwks.json · POST /oauth/register · GET/POST /oauth/authorize (consent page, or a 302 to the tenant's authorize_url) · POST /oauth/token · GET /v1/oauth/authorize-requests/{rid} · POST …/{rid}/complete · POST …/{rid}/decline (delegated consent, tenant-admin) — see Connectors
SchedulesGET/POST /v1/smiths/{sid}/schedules · PATCH/DELETE …/{schid} · POST …/{schid}/run_now
Events & webhooksGET /v1/events · GET/POST /v1/tenant/webhooks · PATCH/DELETE …/{wid} · POST …/{wid}/rotate_secret · POST …/{wid}/test · GET …/{wid}/deliveries · POST …/{wid}/deliveries/{did}/redeliver
Usage & costGET /v1/tenant/usage · GET /v1/usage?group_by= · POST/GET /v1/usage/events
BudgetsPOST/GET /v1/budgets · GET/PATCH/DELETE /v1/budgets/{bid} · GET …/{bid}/status
CustomersPOST/GET /v1/customers · GET/PATCH/DELETE /v1/customers/{cid}
TokensPOST/GET /v1/tenant/tokens · DELETE …/tokens/{tid}
Projects (org key)POST/GET /v1/organization/projects · GET/DELETE …/projects/{pid} · POST …/projects/{pid}/tokens (mint a project tenant:* token)
Credits (org key)GET /v1/organization/billing/balance · GET …/billing/ledger · GET …/billing/usage (per-project draw this month) · GET …/billing/usage/series (daily draw per project) · POST …/billing/setup (add a card, unlock €10 free) · POST …/billing/checkout (Stripe top-up) · POST …/billing/confirm (credit a returned checkout session) · POST …/billing/redeem (redeem a credit code) · GET/PUT …/billing/autoreload · POST …/billing/reload (charge saved card) · GET …/billing/portal (Stripe billing portal)
Model keysGET /v1/tenant/model_keys · PUT/DELETE …/model_keys/{provider} · GET /v1/tenant/models · GET /v1/smiths/{sid}/model_keys · PUT/DELETE …/model_keys/{provider} (end-user keys)
Providers (OAuth)GET /v1/tenant/providers · GET/PUT/DELETE …/providers/{provider}
TracesGET /v1/traces[?smith_id=&app_id=&run_id=&status=&since=] · GET /v1/traces/{tid} · GET /v1/runs/{rid}/trace (the trace for one run) · POST /v1/traces:ingest

Early-access surfaces

One resource appears in scopes and usage breakdowns but is early access and not yet documented here: trace ingestion (POST /v1/traces:ingest: push your own spans from an external runtime, optionally tagged with an app_id that group_by=app then attributes usage by). Ask us before building on it.

Two things to know if you already do. Ingesting the same span_id twice is a no-op on the trace's totals, so an at-least-once exporter can retry safely. And a span you don't attribute to a smith produces a trace with smith_id: null — readable with a tenant-admin token, never with a smith token.

Using the OpenAPI spec

GET https://api.cloud.ingram.tech/openapi.json: feed it to your codegen or API client of choice. The spec is generated from the live API, so it's always in sync with the deployment. (https://cloud.ingram.tech/docs/openapi.json redirects here, if you have it wired up already.)

It covers every endpoint this table lists — including the ones that aren't plain JSON in and out. Streaming turns publish both bodies of the one response (text/event-stream and application/json, chosen by stream); uploads publish their multipart/form-data shape; downloads publish application/octet-stream; the browser endpoints publish their redirects; and the provider webhooks publish what a Slack, Meta, Discord, Telegram or Stripe request URL receives. If an endpoint answers it, the spec describes it.