Generated from the API's OpenAPI document — every endpoint, grouped by resource.
/v1/agentsList agent profiles — each row carries its resolved `defaultSaveTarget` (`{ connectionId, provider, name }`, or null when the agent names none and when the connection it names is revoked or deleted)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
X-Project-Id | header | string (uuid) | No |
Responses
| Status | Description |
|---|---|
200 | Agent profiles |
401 | Error |
/v1/agentsCreate an agent profile (profile + version 1) — a phone preset also provisions the provider-side voice agent (needs `manage_phone` / `phone:manage`, and accepts a top-level `language`). `config.defaultSaveTarget` must be the id of an active connection of this workspace, or null for download-only
Parameters
| Name | In | Type | Required |
|---|---|---|---|
X-Project-Id | header | string (uuid) | No |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Created |
400 | Error |
401 | Error |
403 | Forbidden — `project_required` (a project member named no project), `project_role_forbidden` (their role in the project does not allow this) or `workspace_level_only` (a workspace-level surface) |
/v1/agents/{id}Get an agent profile, including its current version config and its resolved `defaultSaveTarget`
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Agent profile |
404 | Error |
/v1/agents/{id}Rename an agent profile (`name`), or change who can see it (`private`: `false` shares it with the workspace, `true` makes it the caller's own — its owner, whoever shared it, or a workspace owner/admin only; a signed-in user, never an API key). Does not create a new version
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | Agent profile |
400 | Error |
403 | Error |
404 | Error |
/v1/agents/{id}Delete an agent profile, its versions and their runs (one transaction) — a phone agent is deleted from the VoiceProvider first
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Deleted |
404 | Error |
/v1/agents/{id}/definitionThe agent definition `afb-runner` pulls before a local batch — config and effective config; `effective.instructions` and `effective.datasets` (the linked saved tables' queries/object keys and preview snapshots, never the connection) only for a key that also holds `runner:run`. Carries a signed, time-limited `licence` ({ alg, keyId, seatId, workspaceId, validUntil, signature }: Ed25519 over the canonical JSON of the claims, `validUntil` = `fetchedAt` + AFB_DEFINITION_VALIDITY_DAYS, `seatId` = the calling API key's id) — `null` on a deployment with no AFB_DEFINITION_SIGNING_KEY
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Agent definition |
404 | Error |
/v1/agents/{id}/evalsList this agent's eval run batches, newest first
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Eval runs |
404 | Error |
/v1/agents/{id}/evalsRun every eval case for this agent through the kernel (as an evals.run job)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
202 | Queued |
404 | Error |
409 | Error |
/v1/agents/{id}/evals/{runId}Get one eval run batch's per-case detail
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
runId | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Eval run |
404 | Error |
/v1/agents/{id}/preset-defaultsThe preset's profileDefaults (goal, customInstructions, guidelines) beside this agent's current values, with a per-field `differs` flag — docs/plan/39 follow-up
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Preset defaults |
400 | Error |
404 | Error |
/v1/agents/{id}/proposalsList this agent's improvement proposals, newest first
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Proposals |
404 | Error |
/v1/agents/{id}/proposalsManually create an improvement proposal (proposedConfig + rationale)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Created |
400 | Error |
404 | Error |
409 | Error |
/v1/agents/{id}/proposals/{pid}/acceptAccept a proposal — creates a new immutable version (base ⊕ diff) and makes it current
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
pid | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Accepted |
404 | Error |
409 | Error |
/v1/agents/{id}/proposals/{pid}/rejectReject a proposal
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
pid | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Rejected |
404 | Error |
409 | Error |
/v1/agents/{id}/proposals/suggestEnqueue improvements.suggest on demand, from the agent's most recent failing eval cases
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
202 | Queued |
404 | Error |
409 | Error |
/v1/agents/{id}/tutor/sessionsList this workspace's tutor conversations with an agent, most recently active first (at most 50)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Tutor sessions |
404 | Error |
/v1/agents/{id}/tutor/sessionsOpen a tutor conversation with a learning agent (400 family_mismatch for any other family); spends credits per turn, hence runs:write
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Created |
400 | Error |
401 | Error |
404 | Error |
/v1/agents/{id}/versionsList an agent profile's versions, newest first
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Versions |
404 | Error |
/v1/agents/{id}/versionsCreate a new immutable profile version (becomes current) — for a phone agent the config is compiled and pushed to the VoiceProvider before the version is written, and a top-level `language` is accepted. Answers with the resolved `defaultSaveTarget` of the new version
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Created |
404 | Error |
/v1/agents/{id}/versions/{a}/diff/{b}JSON diff between two profile versions' configs, per docs/specs/phase-3.md §3.5
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
a | path | integer | Yes |
b | path | integer | Yes |
Responses
| Status | Description |
|---|---|
200 | Diff |
404 | Error |
/v1/agents/{id}/versions/{version}Get one specific agent profile version
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
version | path | integer | Yes |
Responses
| Status | Description |
|---|---|
200 | Agent profile version |
404 | Error |
/v1/agents/{id}/versions/{version}/activateMake an already-existing version current again (rollback/forward), per docs/specs/phase-3.md §3.5 — for a phone agent that version's config is pushed to the VoiceProvider first
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
version | path | integer | Yes |
Responses
| Status | Description |
|---|---|
200 | Activated |
404 | Error |
/v1/agents/{id}/versions/from-preset-defaultsAppend a version replacing the named fields (goal | customInstructions | guidelines) with the preset's defaults, leaving the rest of the config untouched — docs/plan/39 follow-up
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Created |
400 | Error |
404 | Error |
409 | Error |
/v1/api-keysList API keys
Responses
| Status | Description |
|---|---|
200 | API keys |
/v1/api-keysCreate an API key (plaintext key returned once)
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Created |
/v1/api-keys/{id}Set or clear an API key's monthly spend cap
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | Updated |
400 | Error |
404 | Error |
/v1/api-keys/{id}Revoke an API key
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
204 | Revoked |
404 | Error |
/v1/app-templatesList the static published-app template gallery (drop_and_extract, quote_request), per docs/plan/phase-6-ux-checklist.md §6.6
Responses
| Status | Description |
|---|---|
200 | App templates |
401 | Error |
/v1/appsList published apps
Responses
| Status | Description |
|---|---|
200 | Published apps |
401 | Error |
/v1/appsCreate a published app from an agent profile
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Created |
400 | Error |
404 | Error |
409 | Error |
/v1/apps/{id}Get a published app
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Published app |
404 | Error |
/v1/apps/{id}Update a published app's template/layout/slug/theme/access/caps
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | Updated |
400 | Error |
404 | Error |
409 | Error |
/v1/apps/{id}Delete a published app
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
204 | Deleted |
404 | Error |
/v1/apps/{id}/domainSet a custom domain, returning the TXT record to publish for verification
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Domain set |
400 | Error |
404 | Error |
409 | Error |
/v1/apps/{id}/domain/verifyVerify the custom domain's TXT record
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Verified |
404 | Error |
409 | Error |
422 | Error |
/v1/apps/{id}/pausePause a live app (status -> paused)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Paused |
404 | Error |
/v1/apps/{id}/publishPublish a draft/paused app (status -> live)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Published |
404 | Error |
/v1/apps/{id}/usageToday's and recent daily usage against this app's caps
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Usage |
404 | Error |
/v1/apps/slug-availabilityCheck whether a slug is free to use for a new/renamed published app (global, not workspace-scoped)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
slug | query | string | Yes |
Responses
| Status | Description |
|---|---|
200 | Availability |
401 | Error |
/v1/builder/sessionsStart a conversational agent-builder session, per docs/plan/phase-6-ux-checklist.md §6.5
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Created |
400 | Error |
401 | Error |
/v1/builder/sessions/{id}Get a builder session, including its transcript and current draft config
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Builder session |
404 | Error |
/v1/builder/sessions/{id}/cancelAbandon a builder session without creating an agent (idempotent; 409 if already completed)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Builder session |
404 | Error |
409 | Error |
/v1/builder/sessions/{id}/createValidate the session's draft config and create the agent profile + version 1 from it
Parameters
| Name | In | Type | Required |
|---|---|---|---|
X-Project-Id | header | string (uuid) | No |
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
201 | Created |
400 | Error |
403 | Forbidden — `project_required` (a project member named no project), `project_role_forbidden` (their role in the project does not allow this) or `workspace_level_only` (a workspace-level surface) |
404 | Error |
409 | Error |
/v1/builder/sessions/{id}/messagesSend a message in a builder session; the control model replies and may update the draft config
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | Builder session |
400 | Error |
404 | Error |
409 | Error |
/v1/calendarThe built-in booking calendar's settings, plus appointments within an optional [from, to) range
Parameters
| Name | In | Type | Required |
|---|---|---|---|
from | query | string (date) | No |
to | query | string (date) | No |
Responses
| Status | Description |
|---|---|
200 | Calendar |
401 | Error |
/v1/calendarUpdate the built-in booking calendar's timezone and/or opening hours
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | Updated |
400 | Error |
401 | Error |
403 | Error |
/v1/chatMarketing-site assistant — one message in, one grounded reply out. No auth, nothing stored, per-IP rate limit plus a process-wide daily cap; 503 when the cap is spent or the model is unavailable
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | Reply |
400 | Error |
429 | Error |
503 | Error |
/v1/connectionsList save-output delivery connections (email/webhook/s3/sftp/gdrive/sharepoint)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
X-Project-Id | header | string (uuid) | No |
Responses
| Status | Description |
|---|---|
200 | Connections |
/v1/connectionsCreate a connection — secret config fields are sealed at rest, never returned
Parameters
| Name | In | Type | Required |
|---|---|---|---|
X-Project-Id | header | string (uuid) | No |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Created |
400 | Error |
403 | Forbidden — `project_required` (a project member named no project), `project_role_forbidden` (their role in the project does not allow this) or `workspace_level_only` (a workspace-level surface) |
501 | Error |
/v1/connections/{id}Delete a connection
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
204 | Deleted |
404 | Error |
/v1/connections/{id}/testConnectivity/credential check for one connection (an email one sends one short test email, an sftp one stats its folder); answers { ok, code, status?, message, testedAt } and keeps it on the connection as lastTest
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Test result |
404 | Error |
/v1/console/assistant/messagesOne turn of the console's in-app assistant ({ text, messages?, route?, sectionId? }); metered against the workspace's credits and rate limited per workspace. A project member needs a project where they are editor or admin (else 403 project_role_forbidden); for them it proposes profile changes only and points only at the pages their role shows
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | Assistant reply |
400 | Error |
401 | Error |
402 | Error |
403 | Error |
429 | Error |
/v1/console/auth/meCurrent session user + workspaces — each with the organisation `role` (null for a workspace the user reaches only through its projects) and `access`: `{ kind: "workspace", role }` for a workspace-wide person, or `{ kind: "projects", roles: { <projectId>: admin | editor | runner | viewer } }` for a project member. A person who reaches no workspace gets `workspaces: []`, `currentWorkspaceId: null` and `lostAccess` ({ workspace, project } of their last removal, or null); a workspace named in X-Workspace-Id that they cannot reach is a 403
Responses
| Status | Description |
|---|---|
200 | Current user |
401 | Error |
403 | Error |
404 | Error |
/v1/console/auth/meUpdate the session user's own profile preferences (name, theme, locale)
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | Current user |
400 | Error |
401 | Error |
/v1/console/auth/meGDPR basics: delete the signed-in account ({ password }). Every session ends; refused with 409 sole_owner (details.workspaces) while the person is the only owner of an organisation with a live workspace
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
204 | Deleted |
400 | Error |
401 | Error |
409 | Error |
429 | Error |
/v1/console/auth/password/forgotEmail a password-reset token, if the address has an account (enumeration-safe)
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
204 | Sent (or a no-op) |
400 | Error |
429 | Error |
/v1/console/auth/password/resetRedeem a password-reset token, set a new password, and revoke every session
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
204 | Reset |
400 | Error |
429 | Error |
/v1/console/auth/password/reset/checkRead-only: is this password-reset token still valid? (does not consume it)
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | { valid } |
400 | Error |
429 | Error |
/v1/console/auth/sign-inSign in and start a session
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | Signed in |
401 | Error |
/v1/console/auth/sign-outEnd the current session
Responses
| Status | Description |
|---|---|
204 | Signed out |
/v1/console/auth/sign-upCreate an account (user + organization + workspace) and start a session — or, with `invitationToken` in place of `organizationName`, an account born from an invitation: verified, with the invitation's own address (a different `email` is 403), no organisation of its own, and the invitation accepted in the same step ({ user, workspace, invitation }). Both require `acceptedTerms: true` and the `termsVersion` accepted (the version /termini and /privacy print), stored on the account; without them, 400 `terms_not_accepted`
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Created |
400 | Error |
403 | Error |
404 | Error |
409 | Error |
/v1/console/auth/verifyRedeem an email-verification token
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
204 | Verified |
400 | Error |
429 | Error |
/v1/console/auth/verify/checkRead-only: is this email-verification token still valid? (does not consume it)
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | { valid } |
400 | Error |
429 | Error |
/v1/console/auth/verify/requestEmail the signed-in user a verification token
Responses
| Status | Description |
|---|---|
204 | Sent |
401 | Error |
429 | Error |
/v1/console/billingBalance, plan, entitlements, credit packs, and recent ledger rows
Responses
| Status | Description |
|---|---|
200 | Billing |
401 | Error |
/v1/console/billing/checkoutCreate a Stripe Checkout session — `{ packId }` for a credit pack (paid plans only), or `{ planId }` to subscribe to a plan (plan 39 Wave 8 W8-049). Owner only.
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Checkout session |
400 | Error |
403 | Error |
503 | Error |
/v1/console/billing/invoicesThe organization's own Stripe invoices, newest first, each with the hosted invoice page and its PDF (owner only) — plan 39 Wave 8 W8-048. An empty list with `stripeConfigured` / `customer` says why when there is nothing to show.
Responses
| Status | Description |
|---|---|
200 | Invoices |
401 | Error |
403 | Error |
/v1/console/invitations/acceptRedeem an invitation token for the signed-in user: a workspace invitation grants an organisation membership ({ kind: organization, organizationId, role }), a project invitation a project role and no organisation membership ({ kind: project, organizationId, workspaceId, projectId, projectRole }) — unless the deployment sets AFB_PROJECT_INVITATIONS=0, then 404 feature.project_invitations_disabled
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | Membership granted |
400 | Error |
401 | Error |
403 | Error |
404 | Error |
409 | Error |
429 | Error |
/v1/console/invitations/checkRead-only: is this invitation token still valid? A valid one also says what it opens — { valid: true, kind, email, workspace: { name }, project: { name } | null, role, invitedBy, expiresAt }; a dead one (unknown, used, expired, cancelled) only { valid: false }
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | { valid, … } |
400 | Error |
429 | Error |
/v1/console/membersList the workspace's organisation's members and roles
Responses
| Status | Description |
|---|---|
200 | Members |
401 | Error |
/v1/console/members/{userId}Remove a member from this workspace's organisation, together with their rows in the organisation's projects (owner/admin only)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
userId | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
204 | Removed |
403 | Error |
404 | Error |
409 | Error |
/v1/console/members/inviteCreate a pending invitation (by email) into this workspace's organisation and email the invitee a token (owner/admin only; only an owner may invite an owner) — see POST /v1/console/invitations/accept
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Invitation created |
400 | Error |
403 | Error |
404 | Error |
409 | Error |
/v1/console/notificationsThis reader's notifications, newest first, with the unread count — query: limit, before (ISO), unread=true
Responses
| Status | Description |
|---|---|
200 | Notifications |
400 | Error |
/v1/console/notifications/{id}One notification's detail
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Notification |
404 | Error |
/v1/console/notifications/{id}/readMark one notification read
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Notification |
404 | Error |
/v1/console/notifications/read-allMark every notification this reader can see as read
Responses
| Status | Description |
|---|---|
200 | Marked count |
/v1/console/outboxDev-only: lists this workspace's outbound_messages (what DevEmailSender "sent") — 404s outside development
Responses
| Status | Description |
|---|---|
200 | Outbox |
401 | Error |
404 | Error |
/v1/console/request-logsPaginated, filterable request log for this workspace
Parameters
| Name | In | Type | Required |
|---|---|---|---|
from | query | string (date-time) | No |
to | query | string (date-time) | No |
path | query | string | No |
status | query | integer | No |
cursor | query | string | No |
limit | query | integer | No |
Responses
| Status | Description |
|---|---|
200 | Request logs |
401 | Error |
/v1/console/workspaceGet the current workspace's name and settings (allowed data regions, retention days, brand colour), its effective country, its deletion state, and retentionSweep (read-only: on | dry-run | off — whether the daily retention sweep deletes)
Responses
| Status | Description |
|---|---|
200 | Workspace |
401 | Error |
404 | Error |
/v1/console/workspaceUpdate workspace name / allowed data regions / retention days / brand colour
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | Updated |
400 | Error |
401 | Error |
403 | Error |
404 | Error |
/v1/console/workspace/deletionGDPR basics: the organisation owner deletes this workspace, typing its name ({ confirmName }). It is closed (423 workspace_pending_deletion everywhere but restore, export and /me), its Stripe renewals stopped, its owners emailed, and purged after 14 days unless restored
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | Deletion scheduled: { deletion: { requestedAt, dueAt } } |
400 | Error |
401 | Error |
403 | Error |
409 | Error |
502 | Error |
/v1/console/workspace/deletionGDPR basics: the organisation owner restores a workspace that is being deleted (before its due date)
Responses
| Status | Description |
|---|---|
200 | Restored |
401 | Error |
403 | Error |
409 | Error |
/v1/console/workspace/exportsGDPR basics: the workspace's recent exports — status, size, until when each downloads (owner only)
Responses
| Status | Description |
|---|---|
200 | Exports |
401 | Error |
403 | Error |
/v1/console/workspace/exportsGDPR basics (art. 20): the organisation owner asks for an export of the whole workspace — one ZIP of JSON built by the worker; the owner is notified when it is ready. One at a time: while one is in flight, it is returned
Responses
| Status | Description |
|---|---|
202 | Export queued: { export } |
401 | Error |
403 | Error |
/v1/console/workspace/exports/{id}/downloadGDPR basics: download a ready export (application/zip), within 7 days of it being ready (owner only)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | The ZIP |
401 | Error |
403 | Error |
404 | Error |
/v1/data-sourcesList read-only data sources (databases, object storage, file servers, spreadsheets, uploaded files)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
X-Project-Id | header | string (uuid) | No |
Responses
| Status | Description |
|---|---|
200 | Data sources |
401 | Error |
/v1/data-sourcesCreate a data source — secret config fields are sealed at rest, never returned
Parameters
| Name | In | Type | Required |
|---|---|---|---|
X-Project-Id | header | string (uuid) | No |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Created |
400 | Error |
401 | Error |
403 | Forbidden — `project_required` (a project member named no project), `project_role_forbidden` (their role in the project does not allow this) or `workspace_level_only` (a workspace-level surface) |
404 | Error |
/v1/data-sources/{id}Get a data source (metadata plus the names of its sealed secret fields, never their values)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Data source |
404 | Error |
/v1/data-sources/{id}Update a data source's name and/or config (omitted secret fields keep their sealed value)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | Updated |
400 | Error |
404 | Error |
/v1/data-sources/{id}Delete a data source
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
204 | Deleted |
404 | Error |
/v1/data-sources/{id}/filesUpload a file to a "file" data source (multipart or raw body + X-Filename)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
multipart/form-data | object |
application/octet-stream | string (binary) |
Responses
| Status | Description |
|---|---|
201 | Uploaded |
400 | Error |
404 | Error |
413 | Error |
422 | Error |
/v1/data-sources/{id}/objectsList a data source's readable objects (tables, views, blobs, sheets), optionally under a prefix
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
prefix | query | string | No |
Responses
| Status | Description |
|---|---|
200 | Objects |
404 | Error |
429 | Error |
502 | Error |
/v1/data-sources/{id}/readRun one read (SQL query for SQL sources, or an objectId) — read-only, row/byte capped, and returned with a per-column summary
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | Capped result rows plus summary |
400 | Error |
404 | Error |
408 | Error |
429 | Error |
502 | Error |
/v1/data-sources/{id}/schemaGet one object's column schema
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
object | query | string | Yes |
Responses
| Status | Description |
|---|---|
200 | Object schema |
400 | Error |
404 | Error |
429 | Error |
502 | Error |
/v1/data-sources/{id}/testProbe a data source's connectivity (an sftp one also checks its folder); answers { ok, latencyMs, error?, code? } — a failed probe is a 200 { ok: false } with a datasources.* code, not an error status
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Test result |
404 | Error |
429 | Error |
/v1/datasetsList this workspace's saved tables (issue #48: a named, replayable read against a data source)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
X-Project-Id | header | string (uuid) | No |
Responses
| Status | Description |
|---|---|
200 | Datasets |
401 | Error |
/v1/datasetsSave a query (SQL sources) or a picked object (non-SQL sources) on a data source as a named table — stores the definition only, never the rows
Parameters
| Name | In | Type | Required |
|---|---|---|---|
X-Project-Id | header | string (uuid) | No |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Created |
400 | Error |
401 | Error |
403 | Forbidden — `project_required` (a project member named no project), `project_role_forbidden` (their role in the project does not allow this) or `workspace_level_only` (a workspace-level surface) |
404 | Error |
/v1/datasets/{id}Get a saved table's definition and its last columns snapshot
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Dataset |
404 | Error |
/v1/datasets/{id}Delete a saved table
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
204 | Deleted |
404 | Error |
/v1/datasets/{id}/materializeReplay a saved table's read against its data source now (same caps and read-only guard as the workbench; spends the per-workspace read budget)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Rows |
400 | Error |
404 | Error |
429 | Error |
/v1/datasource-copilot/sessionsStart a data-source copilot session for one wizard/workbench step (choose, details, test, query, analysis)
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Created |
400 | Error |
401 | Error |
404 | Error |
/v1/datasource-copilot/sessions/{id}Get a copilot session, including its transcript and masked draft fields
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Copilot session |
404 | Error |
/v1/datasource-copilot/sessions/{id}Move a copilot session along the wizard (step, draftType, dataSourceId, draftFields) — secret field values are stored masked
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | Copilot session |
400 | Error |
404 | Error |
409 | Error |
/v1/datasource-copilot/sessions/{id}/cancelAbandon a copilot session (idempotent; 409 if already completed)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Copilot session |
404 | Error |
409 | Error |
/v1/datasource-copilot/sessions/{id}/messagesSend a message; the copilot replies and may return fieldFills, a suggestedType, a suggestedQuery or an analysis (query/analysis steps run a bounded server-side tool loop)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | Copilot session plus this turn's reply and proposals |
400 | Error |
404 | Error |
409 | Error |
429 | Error |
/v1/filesList the workspace's uploads library (newest first) — one folder's files with ?folderId=<uuid>|root, or a filename search across the whole library with ?q= — with its storage usage and quota
Parameters
| Name | In | Type | Required |
|---|---|---|---|
X-Project-Id | header | string (uuid) | No |
folderId | query | string | No |
q | query | string | No |
limit | query | integer | No |
offset | query | integer | No |
Responses
| Status | Description |
|---|---|
200 | Files |
401 | Error |
404 | Error |
/v1/filesUpload a file into the workspace's uploads library (multipart or raw body + X-Filename), optionally straight into a folder (?folderId=)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
X-Project-Id | header | string (uuid) | No |
projectId | query | string (uuid) | No |
folderId | query | string (uuid) | No |
Request body
| Content type | Schema |
|---|---|
multipart/form-data | object |
application/octet-stream | string (binary) |
Responses
| Status | Description |
|---|---|
201 | Stored |
402 | Error |
403 | Forbidden — `project_required` (a project member named no project), `project_role_forbidden` (their role in the project does not allow this) or `workspace_level_only` (a workspace-level surface) |
404 | Error |
413 | Error |
415 | Error |
/v1/files/{id}Rename and/or move an uploaded file ({ filename?, folderId? }; folderId null = the root)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | File |
400 | Error |
404 | Error |
/v1/files/{id}Delete an uploaded file, freeing its storage quota (past runs keep their own copy)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
204 | Deleted |
404 | Error |
/v1/files/{id}/contentDownload an uploaded file's bytes
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | File bytes |
404 | Error |
/v1/files/foldersList the workspace's upload folders (flat, sorted by name) with each folder's direct file count and size
Parameters
| Name | In | Type | Required |
|---|---|---|---|
X-Project-Id | header | string (uuid) | No |
Responses
| Status | Description |
|---|---|
200 | Folders |
401 | Error |
/v1/files/foldersCreate an upload folder ({ name, parentId? }); 409 folder_exists for a same-named sibling
Parameters
| Name | In | Type | Required |
|---|---|---|---|
X-Project-Id | header | string (uuid) | No |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Folder |
400 | Error |
403 | Forbidden — `project_required` (a project member named no project), `project_role_forbidden` (their role in the project does not allow this) or `workspace_level_only` (a workspace-level surface) |
404 | Error |
409 | Error |
/v1/files/folders/{id}Rename and/or move an upload folder ({ name?, parentId? }); 400 folder_cycle when moved into itself or a descendant, 409 folder_exists for a same-named sibling
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | Folder |
400 | Error |
404 | Error |
409 | Error |
/v1/files/folders/{id}Delete an upload folder recursively — every sub-folder and every file inside them (past runs keep their copies)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
204 | Deleted |
404 | Error |
/v1/files/recentList this workspace's recently used run input files (for reuse via input.artifactIds)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
X-Project-Id | header | string (uuid) | No |
Responses
| Status | Description |
|---|---|
200 | Recent input files |
/v1/finance/categoriesThis workspace's effective finance category taxonomy (platform defaults, workspace overrides win by key)
Responses
| Status | Description |
|---|---|
200 | Categories |
401 | Error |
/v1/finance/exportStreams bank transactions as CSV over an optional [from, to] range (400 on a malformed from/to) and the same category/anomaly/uncategorised/q filters GET /v1/finance/transactions supports — ?format=journal (default) or ?format=datev (behind AFB_FEATURE_DATEV, 404 otherwise)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
from | query | string (date) | No |
to | query | string (date) | No |
category | query | string | No |
anomaly | query | enum(true | false) | No |
uncategorised | query | enum(true | false) | No |
q | query | string | No |
format | query | enum(journal | datev) | No |
Responses
| Status | Description |
|---|---|
200 | CSV |
400 | Error |
404 | Error |
/v1/finance/importsList this workspace's bank CSV imports, newest first
Responses
| Status | Description |
|---|---|
200 | Bank imports |
401 | Error |
/v1/finance/importsUpload a bank CSV export and create a finance/categorisation run (202, Idempotency-Key supported)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
Idempotency-Key | header | string | No |
accountLabel | query | string | No |
Request body
| Content type | Schema |
|---|---|
multipart/form-data | object |
text/csv | string |
application/octet-stream | string (binary) |
Responses
| Status | Description |
|---|---|
202 | Queued |
400 | Error |
402 | Error |
413 | Error |
/v1/finance/reconciliationCreate a finance/reconciliation run matching open invoices against transactions over {from, to}
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
202 | Queued |
400 | Error |
402 | Error |
403 | Error |
/v1/finance/reportsCreate a finance/cashflow-report run over {from, to} (optional template)
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
202 | Queued |
400 | Error |
402 | Error |
403 | Error |
/v1/finance/rulesList this workspace's transaction_rules (created via PATCH /v1/finance/transactions/:id's own makeRule)
Responses
| Status | Description |
|---|---|
200 | Rules |
401 | Error |
/v1/finance/rules/{id}Delete one of this workspace's transaction_rules
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
204 | Deleted |
401 | Error |
403 | Error |
404 | Error |
/v1/finance/summaryBy-month and by-category totals, plus anomaly/uncategorised counts, over an optional [from, to] range
Parameters
| Name | In | Type | Required |
|---|---|---|---|
from | query | string (date) | No |
to | query | string (date) | No |
Responses
| Status | Description |
|---|---|
200 | Summary |
401 | Error |
/v1/finance/transactionsList/filter this workspace's imported bank transactions (cursor-paginated)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
from | query | string (date) | No |
to | query | string (date) | No |
category | query | string | No |
anomaly | query | enum(true | false) | No |
uncategorised | query | enum(true | false) | No |
q | query | string | No |
cursor | query | string | No |
limit | query | integer | No |
Responses
| Status | Description |
|---|---|
200 | Transactions |
401 | Error |
/v1/finance/transactions/{id}Correct one transaction's category (source becomes human), optionally creating a categorisation rule
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | Updated |
400 | Error |
403 | Error |
404 | Error |
/v1/flow-approvalsList the approval steps flow runs in your scope are waiting on, oldest first — answer one with POST /v1/flow-runs/{id}/approvals/{nodeId}
Parameters
| Name | In | Type | Required |
|---|---|---|---|
X-Project-Id | header | string (uuid) | No |
Responses
| Status | Description |
|---|---|
200 | Pending flow approvals |
/v1/flow-hooks/{token}Public webhook trigger for an active webhook-triggered flow — no auth (the token is the credential), rate limited per IP, 64 KB body cap; the body becomes the run's trigger payload, and an unknown token, a paused flow, and a non-webhook flow are all the same 404
Parameters
| Name | In | Type | Required |
|---|---|---|---|
token | path | string | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
202 | Flow run queued |
400 | Error |
404 | Error |
413 | Error |
429 | Error |
/v1/flow-runs/{id}Get one flow run with its execution state, its approval steps, its wall-clock duration, and — from one join of flow_node_runs and runs — the child run every agent step launched
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Flow run |
404 | Error |
/v1/flow-runs/{id}/approvals/{nodeId}Approve or reject the approval step a flow run is waiting on
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
nodeId | path | string | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
202 | Answer accepted; the flow resumes asynchronously |
400 | Error |
404 | Error |
409 | Error |
/v1/flowsList saved workflows (flows)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
X-Project-Id | header | string (uuid) | No |
include | query | enum(recentRuns) | No |
Responses
| Status | Description |
|---|---|
200 | Flows |
/v1/flowsCreate a flow — its graph is validated before it is stored
Parameters
| Name | In | Type | Required |
|---|---|---|---|
X-Project-Id | header | string (uuid) | No |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Created |
400 | Error |
403 | Forbidden — `project_required` (a project member named no project), `project_role_forbidden` (their role in the project does not allow this) or `workspace_level_only` (a workspace-level surface) |
409 | Error |
/v1/flows/{id}Get a flow
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Flow |
404 | Error |
/v1/flows/{id}Update a flow's name, status, or graph (optimistic-locked by expectedGraphVersion)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | Updated |
400 | Error |
404 | Error |
409 | Error |
/v1/flows/{id}Delete a flow
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
204 | Deleted |
404 | Error |
/v1/flows/{id}/folder-filesA folder-triggered flow's watch: the folder, since when, the last check and why it started nothing, and the files it started runs for (newest first)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Watched folder |
404 | Error |
/v1/flows/{id}/runStart a flow run manually
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
202 | Flow run queued |
404 | Error |
/v1/flows/{id}/runsList a flow's runs
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Flow runs |
404 | Error |
/v1/flows/{id}/webhook-tokenRegenerate the flow's webhook trigger URL token
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Webhook token |
404 | Error |
/v1/flows/from-templateCreate a draft flow from a template, bound to a family-matching agent — 409 flow_template_no_agent when the workspace has none
Parameters
| Name | In | Type | Required |
|---|---|---|---|
X-Project-Id | header | string (uuid) | No |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Created |
400 | Error |
403 | Forbidden — `project_required` (a project member named no project), `project_role_forbidden` (their role in the project does not allow this) or `workspace_level_only` (a workspace-level surface) |
404 | Error |
409 | Error |
/v1/flows/templatesList the worked example flows on offer (a read-only catalogue), each with the workspace agent it would be bound to and how well that agent fits
Parameters
| Name | In | Type | Required |
|---|---|---|---|
X-Project-Id | header | string (uuid) | No |
Responses
| Status | Description |
|---|---|
200 | Flow templates |
/v1/flows/templates/{key}One flow template inside out: its summary, the read-only preview graph (agent nodes carry a placeholder id; email and approval nodes the caller's own address) and every step's facts in canvas order, for the client to put into words — 404 for an unknown key
Parameters
| Name | In | Type | Required |
|---|---|---|---|
key | path | string | Yes |
Responses
| Status | Description |
|---|---|
200 | Flow template |
404 | Error |
/v1/healthHealth check
Responses
| Status | Description |
|---|---|
200 | OK |
/v1/knowledgeList this workspace's knowledge documents
Parameters
| Name | In | Type | Required |
|---|---|---|---|
X-Project-Id | header | string (uuid) | No |
Responses
| Status | Description |
|---|---|
200 | Knowledge documents |
/v1/knowledgeUpload a knowledge document (txt/csv/md/pdf); indexed asynchronously via a knowledge.index job
Parameters
| Name | In | Type | Required |
|---|---|---|---|
X-Project-Id | header | string (uuid) | No |
Request body
| Content type | Schema |
|---|---|
multipart/form-data | object |
application/octet-stream | string (binary) |
Responses
| Status | Description |
|---|---|
201 | Stored |
403 | Forbidden — `project_required` (a project member named no project), `project_role_forbidden` (their role in the project does not allow this) or `workspace_level_only` (a workspace-level surface) |
413 | Error |
415 | Error |
/v1/knowledge/{id}Delete a knowledge document (and its indexed chunks)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
204 | Deleted |
404 | Error |
/v1/knowledge/{id}/contentRead a knowledge document's original bytes (served inline, for preview)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Document bytes |
404 | Error |
/v1/knowledge/{id}/previewRender a knowledge document as a self-contained HTML preview (CSV/XLSX tables, DOCX, email, text)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Preview page |
404 | Error |
/v1/knowledge/from-templateCreate a knowledge document from a starter template, indexed asynchronously via a knowledge.index job
Parameters
| Name | In | Type | Required |
|---|---|---|---|
X-Project-Id | header | string (uuid) | No |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Stored |
400 | Error |
403 | Forbidden — `project_required` (a project member named no project), `project_role_forbidden` (their role in the project does not allow this) or `workspace_level_only` (a workspace-level surface) |
404 | Error |
/v1/knowledge/from-uploadCopy a workspace uploads-library file into a knowledge document, indexed asynchronously via a knowledge.index job
Parameters
| Name | In | Type | Required |
|---|---|---|---|
X-Project-Id | header | string (uuid) | No |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Stored |
400 | Error |
403 | Forbidden — `project_required` (a project member named no project), `project_role_forbidden` (their role in the project does not allow this) or `workspace_level_only` (a workspace-level surface) |
404 | Error |
415 | Error |
/v1/knowledge/searchSearch this workspace's indexed knowledge chunks
Parameters
| Name | In | Type | Required |
|---|---|---|---|
X-Project-Id | header | string (uuid) | No |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | Search results |
400 | Error |
/v1/knowledge/templatesList the starter knowledge documents on offer (a read-only catalogue, without their bodies)
Responses
| Status | Description |
|---|---|
200 | Knowledge templates |
/v1/local-runsList the batches `afb-runner` executed on the client's own machines, newest first
Parameters
| Name | In | Type | Required |
|---|---|---|---|
X-Project-Id | header | string (uuid) | No |
limit | query | integer | No |
cursor | query | string | No |
agentId | query | string (uuid) | No |
Responses
| Status | Description |
|---|---|
200 | Local run batches |
/v1/local-runsRecord one local batch's metadata (counts, durations, per-model tokens, test accuracy, plus the licence's `seatId` and `licence` state — `valid`/`grace`/`dev`) — requires `runner:run`, idempotent on (workspace, batchId), never billed
Parameters
| Name | In | Type | Required |
|---|---|---|---|
X-Project-Id | header | string (uuid) | No |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | Already recorded — updated |
201 | Recorded |
400 | Error |
403 | Error |
426 | Error |
/docsHTML API reference viewer
Responses
| Status | Description |
|---|---|
200 | HTML |
/v1/modelsList the model catalogue, filtered by the workspace's allowed data regions
Responses
| Status | Description |
|---|---|
200 | Models |
401 | Error |
/v1/openapi.jsonThis OpenAPI document
Responses
| Status | Description |
|---|---|
200 | OpenAPI document |
/v1/phone/agentsList phone agents
Responses
| Status | Description |
|---|---|
200 | Phone agents |
401 | Error |
/v1/phone/agentsCreate a phone agent from a phone preset — compiles and pushes it to the configured VoiceProvider
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Created |
400 | Error |
401 | Error |
403 | Error |
/v1/phone/agents/{id}Get a phone agent, including its current version config
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Phone agent |
404 | Error |
/v1/phone/agents/{id}Create a new profile version and recompile + push the update to the VoiceProvider — the config may carry `providerSettings` (ElevenLabs agent settings, docs/plan/WAVE5-ELEVENLABS-SPEC-2026-09-05.md §2)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | Updated |
400 | Error |
404 | Error |
/v1/phone/agents/{id}Delete a phone agent from the VoiceProvider and this workspace, together with its agent profile
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
204 | Deleted |
404 | Error |
/v1/phone/agents/{id}/rotate-secretsRotates this phone agent's tool + webhook secrets, recompiles, and pushes the update to the VoiceProvider (the response never echoes the new secret values)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Rotated |
401 | Error |
403 | Error |
404 | Error |
/v1/phone/callsList calls (paginated), filterable by agentId/direction/status
Parameters
| Name | In | Type | Required |
|---|---|---|---|
agentId | query | string | No |
direction | query | enum(inbound | outbound) | No |
status | query | enum(live | completed | failed) | No |
cursor | query | string | No |
limit | query | integer | No |
Responses
| Status | Description |
|---|---|
200 | Calls |
401 | Error |
/v1/phone/calls/{id}Get a call: transcript, summary, collected data, actions, audio link, run id, and retentionDays (when it is deleted automatically)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Call |
404 | Error |
/v1/phone/calls/{id}GDPR basics: delete a finished call — the recording and transcript at the provider first (a refusal is a 502 and nothing is deleted), then its run (transcript turns, analysis) and the row. A live call is refused (409 call_live)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
204 | Deleted |
404 | Error |
409 | Error |
502 | Error |
/v1/phone/calls/outboundStart an outbound call, or (for a requiresApproval preset) create a needs_approval run — approve via the existing POST /v1/runs/{id}/approve
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Call started |
202 | Needs approval |
400 | Error |
404 | Error |
/v1/phone/compile-previewCompile a phone agent draft (preset + config + language) the way POST /v1/agents will, and return the compiled view — the builder's live preview of the defaults the provider agent is created with
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | Phone compile preview |
400 | Error |
401 | Error |
/v1/phone/modelsThe provider's TTS and LLM model catalogues for the phone agent's ElevenLabs settings (static catalogue when the provider cannot be reached; fake fixtures without ELEVENLABS_API_KEY)
Responses
| Status | Description |
|---|---|
200 | Model catalogue |
401 | Error |
/v1/phone/numbersList imported phone numbers (Twilio, SIP trunk, or Exotel)
Responses
| Status | Description |
|---|---|
200 | Phone numbers |
401 | Error |
/v1/phone/numbersImport a phone number from Twilio, a SIP trunk, or Exotel (`provider`, default "twilio") and optionally assign it to an agent
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Created |
400 | Error |
404 | Error |
/v1/phone/numbers/{id}Assign/unassign an agent (`agentId`, string or null) and/or edit the label of an imported phone number
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | Updated |
400 | Error |
401 | Error |
403 | Error |
404 | Error |
/v1/phone/numbers/{id}Delete an imported phone number
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
204 | Deleted |
404 | Error |
/v1/phone/simulateDev-only: simulates an inbound call end-to-end via FakeVoiceProvider (404 outside development)
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Simulated |
400 | Error |
404 | Error |
409 | Error |
/v1/phone/suppressionsThe workspace's do-not-call list (numbers that opted out on a call, or were added by hand)
Responses
| Status | Description |
|---|---|
200 | Suppressed numbers |
/v1/phone/suppressionsAdds a number to the do-not-call list — outbound calls to it are refused
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Added |
400 | Error |
/v1/phone/suppressions/{id}Removes a number from the do-not-call list (audited)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string | Yes |
Responses
| Status | Description |
|---|---|
204 | Removed |
404 | Error |
/v1/phone/tools/{tool}Live, mid-call server-tool endpoint called by the voice provider (bearer tool secret)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
tool | path | string | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | Tool result |
401 | Error |
404 | Error |
/v1/phone/voicesThe provider account's voice catalogue (id, name, labels, preview URL) plus the account-default synthesis settings — what the phone agent's Voice tab renders (served from a short in-process cache)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
pageSize | query | integer | No |
pageToken | query | string | No |
search | query | string | No |
category | query | enum(premade | professional | cloned | generated | famous | high_quality) | No |
Responses
| Status | Description |
|---|---|
200 | Voice catalogue page |
400 | Error |
401 | Error |
/v1/phone/voices/{id}/settingsOne voice's stored synthesis settings (stability, similarityBoost, style, useSpeakerBoost, speed)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Voice settings |
401 | Error |
404 | Error |
/v1/phone/webhooks/elevenlabsPost-call webhook (HMAC-signed) — completes the call and enqueues phone.postcall
Parameters
| Name | In | Type | Required |
|---|---|---|---|
ElevenLabs-Signature | header | string | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | Received |
401 | Error |
404 | Error |
/v1/phone/webhooks/elevenlabs/initiationInbound-call start gate (bearer platform secret): answers whether a call may be taken, or the opening that turns it away — 404 unless AFB_PHONE_INITIATION_WEBHOOK_SECRET is set
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | Client data for the call |
401 | Error |
404 | Error |
/v1/presetsList the preset catalogue — every registered preset a new agent can be created from, each with its gallery copy, sector and code (plan 57); `include=retired` adds the retired presets too, flagged `retired: true`, for a client showing an existing agent
Parameters
| Name | In | Type | Required |
|---|---|---|---|
include | query | enum(retired) | No |
Responses
| Status | Description |
|---|---|
200 | Presets |
/v1/price-listsList this workspace's price lists
Responses
| Status | Description |
|---|---|
200 | Price lists |
/v1/price-listsImport a price list from CSV (columns sku,description,unit,unit_price,category,labor_minutes); all-or-nothing with a row-level validation report
Parameters
| Name | In | Type | Required |
|---|---|---|---|
name | query | string | No |
currency | query | string | No |
Request body
| Content type | Schema |
|---|---|
multipart/form-data | object |
text/csv | string |
application/octet-stream | string (binary) |
Responses
| Status | Description |
|---|---|
201 | Imported |
400 | Error |
413 | Error |
/v1/price-lists/{id}Delete a price list (cascades its items)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
204 | Deleted |
404 | Error |
/v1/price-lists/{id}/itemsSearch a price list's items by a simple token index
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
q | query | string | No |
limit | query | integer | No |
Responses
| Status | Description |
|---|---|
200 | Price list items |
404 | Error |
/v1/price-lists/analyzeRead a price-list file (CSV deterministically; PDF/image through one metered model call) and return the table it appears to contain, without saving anything — plan 36
Request body
| Content type | Schema |
|---|---|
multipart/form-data | object |
text/csv | string |
application/pdf | string (binary) |
application/octet-stream | string (binary) |
Responses
| Status | Description |
|---|---|
200 | Analysis |
400 | Error |
402 | Error |
413 | Error |
/v1/pricing-rulesGet the effective pricing rules (a profile's own override, else the workspace default, else the unconfigured defaults with configured:false)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
profileId | query | string (uuid) | No |
Responses
| Status | Description |
|---|---|
200 | Pricing rules |
/v1/pricing-rulesReplace the workspace default pricing rules, or a per-profile override when ?profileId= is given
Parameters
| Name | In | Type | Required |
|---|---|---|---|
profileId | query | string (uuid) | No |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | Pricing rules |
400 | Error |
/v1/projectsList projects in the workspace, each with its member count
Responses
| Status | Description |
|---|---|
200 | Projects |
401 | Error |
/v1/projectsCreate a project (name + optional monthly spend cap)
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Created |
400 | Error |
401 | Error |
/v1/projects/{id}Get one project
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Project |
404 | Error |
/v1/projects/{id}Update a project's name and/or spend cap
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | Updated |
400 | Error |
404 | Error |
/v1/projects/{id}Delete a project (refuses the default project or one that still owns rows)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
204 | Deleted |
404 | Error |
409 | Error |
/v1/projects/{id}/invitationsInvite an e-mail into this project with a project role ({ email, role: admin | editor | runner | viewer }) — the project's own admins, or the workspace's owners and admins (manage_project_team). Accepting (POST /v1/console/invitations/accept) grants the project role and no organisation membership; an e-mail already in the organisation is added to the project directly (status added, no mail). On unless the deployment sets AFB_PROJECT_INVITATIONS=0: then 404 feature.project_invitations_disabled
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | { status: invited | added, projectId, role, … } |
400 | Error |
401 | Error |
403 | Error |
404 | Error |
/v1/projects/{id}/invitations/{invitationId}Cancel a pending invitation into this project: its link stops working and it leaves the team list — manage_project_team in this project; 404 for another project's or an accepted invitation
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
invitationId | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
204 | Cancelled |
401 | Error |
403 | Error |
404 | Error |
/v1/projects/{id}/invitations/{invitationId}/resendSend a pending invitation again: a new link valid seven days from now (the old link stops working), mailed to the same address — manage_project_team in this project; 404 for another project's or an accepted invitation
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
invitationId | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | { status: invited, id, projectId, email, role, expiresAt } |
401 | Error |
403 | Error |
404 | Error |
/v1/projects/{id}/membersList a project's team: `members` (this project's rows, each with its project role and `workspaceRole` — the organisation role of a member who is also workspace-wide, else null), `workspaceMembers` (everyone who sees every project, with their organisation role; empty for a project member) and the project's pending `invitations` (each with its `id` and `invitedByName`, the name of who sent it); each member carries `onlyProject` — true when this project is their one way into the workspace
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Members |
404 | Error |
/v1/projects/{id}/membersAdd a member to a project, or change their role ({ userId, role: admin | editor | runner | viewer }; the organisation names owner, member and consultant are still read as admin, editor and runner) — manage_project_team in this project; the user must already be in the organisation or in one of the workspace's projects; never the caller's own row (403 own_membership)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Added |
400 | Error |
403 | Error |
404 | Error |
/v1/projects/{id}/members/{userId}Remove a member from a project — manage_project_team in this project; never the caller's own row (403 own_membership)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
userId | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
204 | Removed |
403 | Error |
404 | Error |
/v1/public/apps/{slug}Public app metadata: name, theme, template, layout, access mode, locale, inputSpec, owner, caps, settings (e.g. quote_request's showPricesToEndUser), dataInfo
Parameters
| Name | In | Type | Required |
|---|---|---|---|
slug | path | string | Yes |
Responses
| Status | Description |
|---|---|
200 | Public app |
404 | Error |
429 | Error |
/v1/public/apps/{slug}/filesUpload a file for a public-app run (requires an app session)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
slug | path | string | Yes |
Request body
| Content type | Schema |
|---|---|
multipart/form-data | object |
application/octet-stream | string (binary) |
Responses
| Status | Description |
|---|---|
201 | Stored |
401 | Error |
404 | Error |
413 | Error |
415 | Error |
422 | Error |
429 | Error |
/v1/public/apps/{slug}/logoStream the app's branding logo, if one was uploaded
Parameters
| Name | In | Type | Required |
|---|---|---|---|
slug | path | string | Yes |
Responses
| Status | Description |
|---|---|
200 | Logo image |
404 | Error |
429 | Error |
/v1/public/apps/{slug}/redirectResolve a slug an app was renamed away from to its current slug (issue #53); 404 unless the target is live and the slug actually changed
Parameters
| Name | In | Type | Required |
|---|---|---|---|
slug | path | string | Yes |
Responses
| Status | Description |
|---|---|
200 | Current slug |
404 | Error |
/v1/public/apps/{slug}/runsThe caller's own run history on this app, newest first (issue #52): every run of a signed-in end user, or the anonymous session's own runs
Parameters
| Name | In | Type | Required |
|---|---|---|---|
slug | path | string | Yes |
Responses
| Status | Description |
|---|---|
200 | Runs |
401 | Error |
404 | Error |
/v1/public/apps/{slug}/runsCreate a run in the app owner's workspace (requires an app session). For quote_request apps, input.fields.customer.{name,email} are required and validated, and at least one file (the drawing).
Parameters
| Name | In | Type | Required |
|---|---|---|---|
slug | path | string | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
202 | Queued |
400 | Error |
401 | Error |
404 | Error |
429 | Error |
503 | Error |
/v1/public/apps/{slug}/runs/{id}Get a public-app run (only visible to the app session that created it). For quote_request apps, returns a reduced shape: status, stage (preparing|awaiting_approval|sent|failed), sentTo (masked email), and quote only when the app's settings.showPricesToEndUser is on.
Parameters
| Name | In | Type | Required |
|---|---|---|---|
slug | path | string | Yes |
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Run |
401 | Error |
404 | Error |
429 | Error |
/v1/public/apps/{slug}/runs/{id}/eventsLive public-app run events (SSE) — same semantics as the workspace-scoped run events endpoint
Parameters
| Name | In | Type | Required |
|---|---|---|---|
slug | path | string | Yes |
id | path | string (uuid) | Yes |
Last-Event-ID | header | string | No |
Responses
| Status | Description |
|---|---|
200 | text/event-stream |
401 | Error |
404 | Error |
429 | Error |
/v1/public/apps/{slug}/runs/{id}/explainerMake the visitor's run's explainer (or a follow-up's) — Claude Opus 5.5 only; 503 explainer_unavailable when it cannot be made or paid for
Parameters
| Name | In | Type | Required |
|---|---|---|---|
slug | path | string | Yes |
id | path | string | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | The clip, already made |
201 | The clip |
401 | Error |
404 | Error |
429 | Error |
503 | Error |
/v1/public/apps/{slug}/runs/{id}/explainer/{n}/audioThe voice of the visitor's run's clip n
Parameters
| Name | In | Type | Required |
|---|---|---|---|
slug | path | string | Yes |
id | path | string | Yes |
n | path | integer | Yes |
Responses
| Status | Description |
|---|---|
200 | The narration |
401 | Error |
404 | Error |
/v1/public/apps/{slug}/runs/{id}/lessonMake the visitor's run's «Percorso» and «Verifica» once
Parameters
| Name | In | Type | Required |
|---|---|---|---|
slug | path | string | Yes |
id | path | string | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | The lesson, already made |
201 | The lesson |
401 | Error |
404 | Error |
429 | Error |
503 | Error |
/v1/public/apps/{slug}/runs/{id}/outputGet a public-app run's output (JSON, or CSV via ?format=csv). `?locale=` renders the CSV for a reader in that language — schema column titles, enum values and yes/no in that language's words, that locale's decimals and list separator, a BOM (plan 39 Wave 8 W8-038, plan 63); omitted, it is the raw export, every code byte for byte for API clients that parse it.
Parameters
| Name | In | Type | Required |
|---|---|---|---|
slug | path | string | Yes |
id | path | string (uuid) | Yes |
format | query | enum(csv) | No |
locale | query | string | No |
Responses
| Status | Description |
|---|---|
200 | Output |
401 | Error |
404 | Error |
409 | Error |
429 | Error |
/v1/public/apps/{slug}/runs/{id}/reportA finished public-app run rendered as its agent's report (text/html, sanitized) — plan 39 Wave 8 W8-039. Only visible to the app session that created the run; 404 when the agent has no report template (`hasReport` on GET /v1/public/apps/{slug} says so up front), 409 before the run has output.
Parameters
| Name | In | Type | Required |
|---|---|---|---|
slug | path | string | Yes |
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | text/html |
401 | Error |
404 | Error |
409 | Error |
429 | Error |
/v1/public/apps/{slug}/runs/{id}/tutor-extrasThe visitor's own tutor run: its explainer clips, path and quiz (no costs)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
slug | path | string | Yes |
id | path | string | Yes |
Responses
| Status | Description |
|---|---|
200 | Clips, lesson, canGenerate |
401 | Error |
404 | Error |
/v1/public/apps/{slug}/sessionStart a public-app session (public/link/password immediately; magic_link emails a token)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
slug | path | string | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Session |
202 | Magic link sent |
400 | Error |
401 | Error |
404 | Error |
429 | Error |
/v1/public/apps/{slug}/session/verifyRedeem a magic-link token, starting a session
Parameters
| Name | In | Type | Required |
|---|---|---|---|
slug | path | string | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Session |
400 | Error |
401 | Error |
404 | Error |
429 | Error |
/v1/public/apps/{slug}/tutor/sessionsStart a tutor conversation on a training_tutor app (requires an app session; the thread belongs to that session)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
slug | path | string | Yes |
Responses
| Status | Description |
|---|---|
201 | Tutor session |
401 | Error |
404 | Error |
/v1/public/apps/{slug}/tutor/sessions/{sid}The visitor's own tutor conversation, messages oldest first
Parameters
| Name | In | Type | Required |
|---|---|---|---|
slug | path | string | Yes |
sid | path | string | Yes |
Responses
| Status | Description |
|---|---|
200 | Tutor session with its messages |
401 | Error |
404 | Error |
/v1/public/apps/{slug}/tutor/sessions/{sid}/messagesAsk the tutor one question (20 per 10 minutes per app session); answers with the user turn and the assistant turn with its citations
Parameters
| Name | In | Type | Required |
|---|---|---|---|
slug | path | string | Yes |
sid | path | string | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | The user and assistant messages |
400 | Error |
401 | Error |
404 | Error |
409 | Error |
429 | Error |
503 | Error |
/v1/public/apps/{slug}/tutor/sessions/{sid}/messages/{mid}/explainerMake the explainer of one answer in the visitor's own conversation — Claude Opus 5.5 only; 503 explainer_unavailable when it cannot be made or paid for
Parameters
| Name | In | Type | Required |
|---|---|---|---|
slug | path | string | Yes |
sid | path | string | Yes |
mid | path | string | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | The clip, already made |
201 | The clip |
401 | Error |
404 | Error |
429 | Error |
503 | Error |
/v1/public/apps/{slug}/tutor/sessions/{sid}/messages/{mid}/explainer/audioThe voice of an answer's explainer in the visitor's own conversation
Parameters
| Name | In | Type | Required |
|---|---|---|---|
slug | path | string | Yes |
sid | path | string | Yes |
mid | path | string | Yes |
Responses
| Status | Description |
|---|---|
200 | The narration |
401 | Error |
404 | Error |
/v1/public/apps/by-hostResolve a verified custom domain's Host header to its app's slug
Parameters
| Name | In | Type | Required |
|---|---|---|---|
host | query | string | Yes |
Responses
| Status | Description |
|---|---|
200 | Slug |
404 | Error |
429 | Error |
/v1/public/betaWhether a new account may sign up now (`{ open }`) — the market beta's account cap, never the count
Responses
| Status | Description |
|---|---|
200 | Open or full |
/v1/public/dash/{token}Public, token-gated run dashboard — { templateId, title, generatedAt, data }; no auth, rate limited per IP, 404 for an unknown token
Parameters
| Name | In | Type | Required |
|---|---|---|---|
token | path | string | Yes |
Responses
| Status | Description |
|---|---|
200 | Dashboard |
404 | Error |
429 | Error |
/v1/public/demo/catalogThe demo cases a stranger may see: reviewed anonymisation checklist and a real, succeeded recording. `enabled` says one thing — can a run start (i.e. is the demo workspace provisioned). The cases come back either way, because the window replays a recording when it cannot run; an empty `cases` is what makes the landing page leave its Demo window out. `agents` says what each offered agent has — the fields it extracts, its tools, the demo model, the checks it must pass, the paper that comes with the result, the file types it reads, and `labels`, each output field path (`supplier.name`, `lines[].amount`) mapped to its display label (the schema's title, a nested one as parent · child) so a check names its field in words, and `visitorQuestion` — `{ minLength, maxLength }` for an agent offered live that takes the visitor's own question (its cases then carry their own `question`), else `null` — and `limits` the visitor's allowance: runs a day, the upload cap, how long an uploaded document is kept, what a visitor's own file may hold (`maxPdfPages`, `maxTableRows`, `maxAudioBytes`) and `noTraining`, true only while every model call of a demo run asks the provider not to store or train on it. Never 503.
Parameters
| Name | In | Type | Required |
|---|---|---|---|
locale | query | enum(it | en | de) | No |
Responses
| Status | Description |
|---|---|
200 | Catalogue |
429 | Error |
/v1/public/demo/catalog/{caseId}/inputs/{index}Stream one prepared input's bytes, with its own mime and filename
Parameters
| Name | In | Type | Required |
|---|---|---|---|
caseId | path | string | Yes |
index | path | integer | Yes |
Responses
| Status | Description |
|---|---|
200 | The sample file |
404 | Error |
429 | Error |
/v1/public/demo/catalog/{caseId}/inputs/{index}/preview/{name}One file of a prepared input's preview, rendered when the catalogue was built (plan 55 step 4): a page, the strip's or the card's WebP, or a spreadsheet's or a text's `preview.json` (its first rows or lines). Only a name the input's `preview` lists (the catalogue's answer carries them), from its own folder; a browser may keep it an hour.
Parameters
| Name | In | Type | Required |
|---|---|---|---|
caseId | path | string | Yes |
index | path | integer | Yes |
name | path | string | Yes |
Responses
| Status | Description |
|---|---|
200 | image/webp or application/json |
404 | Error |
429 | Error |
/v1/public/demo/catalog/{caseId}/recordingThe recorded real run the window replays past the quota: `{ timeline, output, report, durationMs, credits, real, status, recordedAt }` — and for a phone case's recorded call (plan 55 step 5) `kind: "call"`, `direction`, `caller`, `audio` (its type and size; the bytes at `…/recording/audio`), 128 `peaks` and the `transcript`
Parameters
| Name | In | Type | Required |
|---|---|---|---|
caseId | path | string | Yes |
Responses
| Status | Description |
|---|---|
200 | Recording |
404 | Error |
429 | Error |
/v1/public/demo/catalog/{caseId}/recording/audioA phone case's recorded call (plan 55 step 5, `recording.kind = "call"`): its audio, whole or by `Range` (206 with `Content-Range`, 416 past the end) as an audio element asks for it; a browser may keep it an hour. 404 for a case without a call.
Parameters
| Name | In | Type | Required |
|---|---|---|---|
caseId | path | string | Yes |
Range | header | string | No |
Responses
| Status | Description |
|---|---|
200 | The whole call, in the recording's own audio type |
206 | The bytes asked for, with `Content-Range` |
404 | Error |
416 | The range starts past the end: no body, `Content-Range: bytes */<size>` |
429 | Error |
/v1/public/demo/catalog/{caseId}/recording/explainer/audioThe tutor case's saved explainer voice (plan 64 phase 5), whole or by `Range` (206, 416 past the end); a browser may keep it an hour. 404 for a case without one.
Parameters
| Name | In | Type | Required |
|---|---|---|---|
caseId | path | string | Yes |
Range | header | string | No |
Responses
| Status | Description |
|---|---|
200 | The whole narration |
206 | The bytes asked for, with `Content-Range` |
404 | Error |
416 | The range starts past the end |
429 | Error |
/v1/public/demo/catalog/{caseId}/recording/reportThe recorded run's report PDF, when it produced one
Parameters
| Name | In | Type | Required |
|---|---|---|---|
caseId | path | string | Yes |
Responses
| Status | Description |
|---|---|
200 | application/pdf |
404 | Error |
429 | Error |
/v1/public/demo/phoneWhether the live phone demo is on and, when it is, the demo line's number, the sector doors (the persona that answers), the longest call, how many days a call is kept and the consent version. `{ enabled: false }` while the owner has not configured it, or while the demo line's agent does not yet carry the demo's settings at the provider — the landing then shows the recorded call.
Responses
| Status | Description |
|---|---|
200 | Phone demo |
429 | Error |
/v1/public/demo/phone/sessionsOpens a phone demo session for this visitor, behind a Turnstile token (action `public_demo_phone`): a six-digit code valid for a few minutes, the visitor's only waiting one. Calling the demo line from a visible Italian number and saying the code links the call to this visitor's page only. Mints the signed `afb_demo_visitor` cookie when the request carries none this server issued. 400 `bot_check_failed`, 404 `demo_phone_off`, 429 `demo_phone_cap_reached` (sessions a visitor or a network opens a day), 503 `demo_phone_busy`.
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Phone demo session |
400 | Error |
404 | Error |
429 | Error |
503 | Error |
/v1/public/demo/phone/sessions/{id}The visitor's own phone demo session — its code or its call: the live events, the transcript and the record the agent wrote, the demo calendar (the visitor's booking in full, others as busy slots) and whether a call-back may be asked for. Never a phone number in clear. 404 for any other visitor.
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Phone demo session |
401 | Error |
404 | Error |
429 | Error |
/v1/public/demo/phone/sessions/{id}/callback"Ti chiamiamo noi": the demo line calls the visitor. Only an Italian mobile or landline, never a special range, and only the number that rang in on this session's linked call within the verify window (the call-back proof of ownership); consent must be `true` and the Turnstile token valid; one call per session, per visitor and per number a day, capped per network and by the site's daily count and budget. Refusals: 400 `demo_phone_consent_required` / `bot_check_failed` / `demo_phone_number_refused`, 403 `demo_phone_not_verified`, 404 `demo_phone_outbound_off`, 409 `demo_phone_already_called`, 429 `demo_phone_cap_reached`, 502 `demo_phone_call_failed`, 503 `demo_phone_unavailable`.
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
202 | Phone demo session, calling |
400 | Error |
401 | Error |
403 | Error |
404 | Error |
409 | Error |
429 | Error |
502 | Error |
503 | Error |
/v1/public/demo/runsRun a demo case for real. JSON `{ caseId, inputIndex }` uses one of the case's prepared inputs; multipart `{ caseId, file }` takes the visitor's own document. Requires the `afb_demo_visitor` cookie. 429 `demo_quota` (with `reason`, `resetsAt` and a top-level `replay`) past a cap, 503 `demo_budget_exhausted` (same `replay`) when the credits are gone, 503 `demo_agent_missing` when the demo workspace has no agent for the case's preset. A visitor's own file is refused before any run with 422 `demo_file_refused`, `details: { reason, max?, actual? }` — `reason` one of `pdf_pages`, `table_rows`, `audio_bytes` (over the catalogue's `limits`), `heic`, `pdf_locked`, `pdf_unreadable`, `table_unreadable`. With a valid recorder pass (the `afb_demo_recorder` cookie) the run is counted on the pass's own allowance instead of the visitor's and the network's — past it 429 `demo_quota` with `reason: recorder_quota` — and the site's caps still apply; a pass that is present and not valid is 403 `demo_recorder_pass_invalid`. A visitor's own file within those bounds gets one cheap look at its first page first: when it is clearly not what the agent reads, 422 `demo_wrong_document`, `details: { looksLike, reads?, suggestion: { presetId, caseId, title } | null }`, and no run is created or counted; the form's `force=true` runs the same file unchecked. The JSON body's optional `question` is the visitor's own question, for an agent whose catalogue summary has a `visitorQuestion` (the onboarding tutor): it replaces the case's own question on the case's prepared document and counts like any run; out of bounds once cleaned, 400 `demo_question_invalid` with `details: { reason, minLength, maxLength }`; on any other agent, or on the multipart form, 400 `invalid_request` — both before anything is counted.
Request body
| Content type | Schema |
|---|---|
application/json | object |
multipart/form-data | object |
Responses
| Status | Description |
|---|---|
201 | Run id and the remaining quota |
400 | Error |
401 | Error |
403 | Error |
404 | Error |
413 | Error |
415 | Error |
422 | Error |
429 | Error |
503 | Error |
/v1/public/demo/runs/{id}A demo run's status, timings, settled credits and output — only for the visitor whose id is stamped on it
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Demo run |
401 | Error |
404 | Error |
429 | Error |
503 | Error |
/v1/public/demo/runs/{id}/eventsThe demo run's events as plain JSON — `{ status, events: [{ seq, type, payload, createdAt }] }`, for the visitor who started it. Polled, not streamed (unlike every other event endpoint here): the marketing window must not hold an open connection per visitor, and its proxy buffers. `?after=<seq>` trims the answer to what the caller has not seen.
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
after | query | integer | No |
Responses
| Status | Description |
|---|---|
200 | Run events |
401 | Error |
404 | Error |
429 | Error |
503 | Error |
/v1/public/demo/runs/{id}/offerThe offer PDF a quote demo run produced (plan 57 P1: `document/quote-from-drawing`'s `documents.pdfArtifactId`); 404 for a run whose answer names none, until it exists, and for any other visitor
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | application/pdf |
401 | Error |
404 | Error |
429 | Error |
503 | Error |
/v1/public/demo/runs/{id}/reportThe PDF the demo run produced; 404 until it exists, and for any other visitor
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | application/pdf |
401 | Error |
404 | Error |
429 | Error |
503 | Error |
/v1/public/demo/sessionStart an anonymous demo session: verifies a Turnstile token for the marketing origin, sets the `afb_demo_visitor` cookie (a random id, one year) and returns the day's remaining allowance. An existing visitor keeps their id — reloading the landing page is not a fresh allowance. 503 `demo_disabled` when the demo is not configured on this deployment. A recorder pass signed on the server (the `afb_demo_recorder` cookie, for the owner's recording rig) replaces the Turnstile token and answers the pass's own allowance; a pass that is present and not valid is 403 `demo_recorder_pass_invalid`.
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | Visitor id and quota |
400 | Error |
403 | Error |
429 | Error |
503 | Error |
/v1/runner/releasePublic: the current `afb-runner` version and the oldest one this API still accepts, and the published desktop installers
Responses
| Status | Description |
|---|---|
200 | Runner release line |
/v1/runsList runs (paginated)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
X-Project-Id | header | string (uuid) | No |
cursor | query | string | No |
limit | query | integer | No |
status | query | string | No |
agentId | query | string | No |
Responses
| Status | Description |
|---|---|
200 | Runs |
/v1/runsCreate (queue) a run — its input files may be fresh uploads (`input.fileIds`), earlier runs' inputs (`input.artifactIds`), knowledge documents (`input.knowledgeDocIds`), a saved table (`input.datasetId`) and/or documents read straight out of a connected data source (`input.sourceObjects`)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
X-Project-Id | header | string (uuid) | No |
Idempotency-Key | header | string | No |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
202 | Queued |
400 | Invalid request. `error.code` is `invalid_request`; `error.details.code` names the specific failure, including plan 51's document reads: `source_object_unsupported` (the source's type has no documents to give — SQL, BigQuery, Google Sheets), `source_object_too_large` (the object is over `AFB_DS_MAX_DOC_BYTES`, 25 MB by default) and `input_mime_rejected` (an uploaded file in `input.fileIds`, or a source object, is not an accepted type, either platform-wide or for this agent's effective `inputSpec.files.accept`; `details` names the `filename`, its `mime` and the `accept` list). |
402 | Error |
403 | Forbidden — `project_required` (a project member named no project), `project_role_forbidden` (their role in the project does not allow this) or `workspace_level_only` (a workspace-level surface) |
404 | Something the request named does not exist in this workspace: the agent, a file/knowledge/table id, a data source (`not_found`), or — plan 51 — an object that is no longer on its source (`source_object_not_found`). |
/v1/runs/{id}Get a run, with its cost, any pending human request, its output schema and rules, and where it delivered
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Run |
404 | Error |
/v1/runs/{id}/approveApprove or reject a needs_approval run and resume it
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
202 | Resuming |
404 | Error |
409 | Error |
/v1/runs/{id}/artifactsList a run's input and output artifacts (id, kind, filename, mime, size, createdAt)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Artifacts |
404 | Error |
/v1/runs/{id}/artifacts/{artifactId}Download a run artifact
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
artifactId | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | File bytes |
404 | Error |
410 | Error |
/v1/runs/{id}/cancelCancel a queued/paused run — or a running one whose worker is gone (no live execution job and a lock past the recovery grace), which is cancelled with error code `interrupted` and its reservation refunded. A running run a worker is still executing stays 409 `run_currently_running`.
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Cancelled |
404 | Error |
409 | Error |
/v1/runs/{id}/dashboardGet a run's shared dashboard (templateId, title, shareToken, publicPath, revokedAt, expiresAt); 404 until materialized
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Dashboard |
404 | Error |
/v1/runs/{id}/eventsLive run events (SSE): replays stored events (from Last-Event-ID), then streams live; heartbeats; ends on terminal status
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Last-Event-ID | header | string | No |
Responses
| Status | Description |
|---|---|
200 | text/event-stream |
404 | Error |
/v1/runs/{id}/explainerMake the answer's narrated explainer (or a follow-up's, with `question`) — Claude Opus 5.5 only, no fallback (503 explainer_unavailable); read back for free once made (200), charged when made (201)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | The clip, already made |
201 | The clip |
400 | Error |
402 | Error |
404 | Error |
409 | Error |
429 | Error |
503 | Error |
/v1/runs/{id}/feedbackSubmit feedback on a run
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Created |
404 | Error |
/v1/runs/{id}/inputAnswer a needs_input run and resume it
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
202 | Resuming |
404 | Error |
409 | Error |
/v1/runs/{id}/lessonMake the run's «Percorso» and «Verifica» once (Claude Opus 5.5); the quiz's key and score are computed in code
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | The lesson, already made |
201 | The lesson |
400 | Error |
402 | Error |
404 | Error |
429 | Error |
503 | Error |
/v1/runs/{id}/outputGet a run's final output (JSON, or a CSV/XLSX download via ?format=). Without ?locale= the CSV/XLSX is the raw machine export for an ERP or integration: JSON paths as headers and every code exactly as the JSON carries it (`complete`, `true`). ?locale= renders the download for a person instead — schema column titles, enum values and yes/no in that language's words (`Completa`, `Sì`), that locale's numbers, dates and list separator, UTF-8 BOM. The JSON never changes.
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
format | query | enum(csv | xlsx) | No |
locale | query | string | No |
Responses
| Status | Description |
|---|---|
200 | Output |
404 | Error |
409 | Error |
/v1/runs/{id}/reportThe run on paper: a PDF of its result in its agent type's design — the same blocks the console's Risultato shows — rendered on demand in ?locale= (else the afb_locale cookie, else Accept-Language; it/en/de, default it), served inline. For report/generate and report/generate-monthly-summary it is the PDF the run itself produced, 404 report_not_available when there is none; 409 output_not_available before the run has output
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
locale | query | enum(it | en | de) | No |
Responses
| Status | Description |
|---|---|
200 | application/pdf |
404 | Error |
409 | Error |
/v1/runs/{id}/reviewAccept or reject a needs_review run and resume it
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
202 | Resuming |
404 | Error |
409 | Error |
/v1/runs/{id}/stepsGet a run's ordered steps
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
include | query | enum(io) | No |
Responses
| Status | Description |
|---|---|
200 | Steps |
404 | Error |
/v1/runs/{id}/tutor-extrasAn onboarding tutor run's explainer clips, its path and quiz, whether more may be made, and a clip's usual cost in credits
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Clips, lesson, canGenerate, estimateCredits |
400 | Error |
404 | Error |
/v1/runs/{id}/verificationMark a finished run's result as checked by a person — body `{ verified: true }` — or take the mark back (`false`). Answers `{ verification: { verifiedAt, verifiedBy: { userId, name } } | null }`; `GET /v1/runs` and `GET /v1/runs/{id}` carry the same field. A session only: an API key has no person to name.
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | The run's verification after the change |
400 | Error |
404 | Error |
409 | Error |
/v1/searchGlobal search across agents, runs, phone calls, finance transactions, and static console pages, per docs/plan/phase-6-ux-checklist.md §6.7
Parameters
| Name | In | Type | Required |
|---|---|---|---|
X-Project-Id | header | string (uuid) | No |
q | query | string | No |
Responses
| Status | Description |
|---|---|
200 | Search results |
401 | Error |
429 | Error |
/v1/stripe/webhookStripe webhook receiver (signature-verified)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
Stripe-Signature | header | string | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | Handled |
400 | Error |
503 | Error |
/v1/toolsList the tool catalogue (name, description, safety) an agent's config may enable, per docs/plan/16 §1
Responses
| Status | Description |
|---|---|
200 | Tools |
401 | Error |
/v1/tutor/sessions/{sid}Get a tutor conversation with its whole transcript, oldest message first
Parameters
| Name | In | Type | Required |
|---|---|---|---|
sid | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Tutor session and messages |
404 | Error |
/v1/tutor/sessions/{sid}Delete a tutor conversation and its messages
Parameters
| Name | In | Type | Required |
|---|---|---|---|
sid | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Deleted |
404 | Error |
/v1/tutor/sessions/{sid}/messagesAsk the tutor one question (1–4000 chars); one turn at a time per session (409 turn_in_progress), gated on credits (402), answered from the agent's knowledge with citations
Parameters
| Name | In | Type | Required |
|---|---|---|---|
sid | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | The session, the user message and the assistant message |
400 | Error |
402 | Error |
404 | Error |
409 | Error |
429 | Error |
/v1/tutor/sessions/{sid}/messages/{mid}/explainerMake the narrated explainer of one answer in a tutor conversation — Claude Opus 5.5 only (503 explainer_unavailable); kept on the message, read back for free
Parameters
| Name | In | Type | Required |
|---|---|---|---|
sid | path | string (uuid) | Yes |
mid | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | The clip, already made |
201 | The clip |
402 | Error |
404 | Error |
429 | Error |
503 | Error |
/v1/tutor/sessions/{sid}/messages/{mid}/explainer/audioThe voice of an answer's explainer (404 while it has none)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
sid | path | string (uuid) | Yes |
mid | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | The narration |
404 | Error |
/v1/usageUsage totals and current balance
Parameters
| Name | In | Type | Required |
|---|---|---|---|
from | query | string (date-time) | No |
to | query | string (date-time) | No |
Responses
| Status | Description |
|---|---|
200 | Usage |
/v1/webhooksList webhook subscriptions
Responses
| Status | Description |
|---|---|
200 | Webhooks |
/v1/webhooksCreate a webhook subscription
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Created |
400 | Error |
/v1/webhooks/{id}Delete a webhook subscription
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
204 | Deleted |
404 | Error |
/v1/whatsapp/accountsList connected WhatsApp Business numbers, each carrying its `provider` (`meta` | `twilio`) and, for Twilio, the `webhookUrl` to paste into Twilio. Never echoes a sealed credential (Meta's accessToken, Twilio's authToken).
Responses
| Status | Description |
|---|---|
200 | WhatsApp accounts |
401 | Error |
/v1/whatsapp/accountsConnect a WhatsApp Business number and optionally assign it to an agent. `provider: "meta"` (the default) takes `phoneNumberId` + `displayNumber` + `accessToken`; `provider: "twilio"` (plan 40) takes `accountSid` + `authToken` + `senderNumber` (E.164). Either way the credentials are sealed and never echoed back; a Twilio account's response carries `webhookUrl`, the URL to paste into Twilio's sandbox settings.
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Created |
400 | Error |
404 | Error |
409 | Error |
/v1/whatsapp/accounts/{id}Assign/unassign an agent (`agentId`, string or null), relabel, or enable/disable a WhatsApp account and/or the number's `providerSettings` (WhatsApp channel settings, same spec §2.11)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | Updated |
400 | Error |
401 | Error |
403 | Error |
404 | Error |
/v1/whatsapp/accounts/{id}Delete a WhatsApp account (cascades its conversations/messages) and its sealed connection
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
204 | Deleted |
404 | Error |
/v1/whatsapp/accounts/{id}/requestsThe last 50 inbound messages a number's quote-request agent (P2) took, newest first — each with its outcome and the run it started (runId, runStatus, projectId)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Requests |
401 | Error |
404 | Error |
/v1/whatsapp/conversationsList WhatsApp conversations (paginated), most-recently-active first
Parameters
| Name | In | Type | Required |
|---|---|---|---|
cursor | query | string | No |
limit | query | integer | No |
Responses
| Status | Description |
|---|---|
200 | Conversations |
401 | Error |
/v1/whatsapp/conversations/{id}Get a WhatsApp conversation and its messages (each carrying runId when set)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
id | path | string (uuid) | Yes |
Responses
| Status | Description |
|---|---|
200 | Conversation |
404 | Error |
/v1/whatsapp/simulateDev-only: simulates an inbound WhatsApp message end-to-end via FakeWhatsAppProvider (404 outside development)
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
201 | Simulated |
400 | Error |
404 | Error |
409 | Error |
/v1/whatsapp/webhooks/metaMeta's subscription-verification handshake (hub.mode/hub.verify_token/hub.challenge)
Parameters
| Name | In | Type | Required |
|---|---|---|---|
hub.mode | query | string | No |
hub.verify_token | query | string | No |
hub.challenge | query | string | No |
Responses
| Status | Description |
|---|---|
200 | Echoes hub.challenge |
403 | Forbidden |
/v1/whatsapp/webhooks/metaInbound message/status webhook (HMAC-signed) — stores messages and enqueues whatsapp.reply
Parameters
| Name | In | Type | Required |
|---|---|---|---|
X-Hub-Signature-256 | header | string | Yes |
Request body
| Content type | Schema |
|---|---|
application/json | object |
Responses
| Status | Description |
|---|---|
200 | Received |
401 | Error |
/v1/whatsapp/webhooks/twilioTwilio inbound-message webhook (plan 40): form-encoded, signed with the account's own Auth Token over the request URL plus the sorted parameters. Stores the message and enqueues whatsapp.reply. Always answers empty TwiML so Twilio sends no reply of its own — including for an unknown or non-Twilio number, which is indistinguishable from a known one. 401 only for a failed signature.
Parameters
| Name | In | Type | Required |
|---|---|---|---|
X-Twilio-Signature | header | string | Yes |
Request body
| Content type | Schema |
|---|---|
application/x-www-form-urlencoded | object |
Responses
| Status | Description |
|---|---|
200 | Received (empty TwiML) |
401 | Error |
429 | Error |