Docs

Cloud API

How the Cloud API works: base path, sessions and management API keys, pagination, errors, rate limits and the route families.

The Cloud API is the HTTP JSON API behind the dashboard. Everything you do in the dashboard (creating agents, editing policies, deciding approvals, reading receipts) is a Cloud API request. You can also call it yourself, with a signed-in session or with a management API key, to automate setup and read results.

This page explains the concepts every request shares and lists the route families with the permission each needs. It is not a full schema of every request and response body.

Base URL and request format

All routes live under the base path /api/v1 of the Cloud API. The dashboard calls the same API on its own address, for example https://cloud.example.com/api/v1/.... A script calls the Cloud API at the base URL that K-Block gives you, for example https://api.example.com/api/v1/... for the base URL https://api.example.com. If you do not have the Cloud API's base URL, contact K-Block support.

RuleBehaviour
Body formatJSON only. Another Content-Type answers 415 UNSUPPORTED_MEDIA_TYPE.
Body sizeAt most 1 MiB; larger bodies answer 413 PAYLOAD_TOO_LARGE.
Unknown fieldsBodies and query strings are strict: an unknown member answers 400 VALIDATION_FAILED.
Malformed IDsAn ID in the path that is not well formed answers 404, never 400.
CachingEvery response carries Cache-Control: no-store unless a route sets its own.
Request IDsEvery response carries X-Request-Id: yours if you sent a well-formed one, otherwise a new one. Quote it when you report a problem.
Cross-originNo CORS headers are sent. Browsers use the API only through the dashboard's origin.

Authentication

A request is authenticated in one of two ways: a person's session cookie, or a management API key. Some routes accept only one of them.

Sessions (people)

A person signs in with POST /api/v1/auth/signin and an e-mail address and password. The answer sets the kb_session cookie and contains the session, including a csrf_token. GET /api/v1/auth/session returns the same token later.

  • The cookie is HttpOnly, SameSite=Lax and Secure.

  • A session ends after 12 hours without activity, and 7 days after sign-in at the latest.

  • Every request with a session and an unsafe method (POST, PUT, PATCH, DELETE) must carry both:

    • an Origin header equal to the dashboard's own origin, the address you open the dashboard at (for example https://cloud.example.com), and
    • the header X-KBlock-CSRF with the session's csrf_token.

    Otherwise it answers 403 CSRF_FAILED.

  • Sign-in, sign-up and the other unauthenticated POST routes refuse a foreign Origin header with 403 CSRF_FAILED. A request without Origin (a non-browser client) passes.

  • An account must have a verified e-mail address to sign in; an unverified one gets the same 401 INVALID_CREDENTIALS as a wrong password. A session whose account has no verified address (for example, one created before this rule) gets 403 EMAIL_NOT_VERIFIED everywhere except the routes that serve verification, e-mail change, sign-out, the session itself and password changes.

The dashboard does all of this for you. Sessions are what people use; for automation, use a management API key.

Management API keys (automation)

A management API key authenticates a script or service on behalf of an organization. Send it as a bearer token to the Cloud API's own address:

GET /api/v1/orgs/<org-id>/agents HTTP/1.1
Host: api.example.com
Authorization: Bearer kb_live_…
  • Only owners and admins create management keys, in the dashboard (see API keys). The full key is shown once.
  • Each key has one or more scopes: read, agents:write, tools:write, policies:write, approvals:read, receipts:read.
  • A key belongs to one organization. A request for another organization's ID answers 404.
  • A key without the scope a route needs answers 403 FORBIDDEN naming the missing scope.
  • Many routes never accept keys, for example deciding approvals, members, invitations, API keys, the audit log, webhooks, organization settings, policy activation and rollback, emergency stop, delegations, cancellations and billing checkout. A key there answers 403 FORBIDDEN. These need a signed-in person. The tables in Route families mark every one.
  • Requests with a key need no CSRF token; they carry no cookies.
  • Gateway API keys (the ones agents use) are not accepted by the Cloud API: on routes that take management keys they answer 401 UNAUTHENTICATED. On routes that never take keys, any bearer token answers 403 FORBIDDEN before it is checked.
  • A key stops working when it is revoked or expires, and also when the member who created it leaves the organization, is disabled, or loses the role needed to create that kind of key.

Roles and permissions

Every route under /orgs/<org-id> checks the caller against the organization in the path, never against the organization selected in the dashboard. For a session, the member's role is read again on each request. A non-member gets 404; a member whose role is not enough gets 403 FORBIDDEN.

PermissionRolesManagement key scope
Read organization dataowner, admin, approver, developer, viewerread (approvals: approvals:read; receipts: receipts:read)
Manage resources (agents, MCP servers, tools, policy drafts, gateway keys, webhooks)owner, admin, developeragents:write, tools:write or policies:write, on the routes that accept keys
Decide approvalsowner, admin, approvernever
Administer (activate policies, members, invitations, management keys, settings, delegations, cancellations)owner, adminnever
Read the audit logowner, adminnever
Owner actions (billing checkout and portal, owner changes, organization principal)ownernever

Some writes need more than the route's permission. For example, a developer can create a tool, but only an owner or admin can enable it. Those cases are noted in the tables below and explained on Roles and permissions.

Pagination

List routes return one page at a time (a few short, fixed lists, such as the policy templates, return all items at once):

{ "items": [], "next_cursor": null }
  • ?limit= sets the page size, from 1 to 100. The default is 50.
  • next_cursor is null on the last page. Otherwise pass it as ?cursor= to get the next page.
  • Cursors are opaque. Do not build or edit them.

Errors

Every error has the same JSON body:

{
  "error": {
    "code": "VALIDATION_FAILED",
    "message": "invalid request body",
    "details": { "location": "body", "issues": [] }
  }
}

code is stable and machine-readable; message is for people and may change. details is present only for some codes, for example issues for validation errors (each with path, code and message, never the submitted value) or retry_after_seconds for rate limits. A 500 INTERNAL_ERROR never includes details of what failed.

StatusCommon codesWhat to do
400VALIDATION_FAILED, INVALID_JSON, INVALID_INPUTFix the request; the issues name the fields.
401UNAUTHENTICATED, INVALID_CREDENTIALSSign in again or check the API key.
402PLAN_LIMIT_EXCEEDEDThe organization's plan limit is reached. See Billing.
403FORBIDDEN, ADMIN_REQUIRED, OWNER_REQUIRED, CSRF_FAILED, EMAIL_NOT_VERIFIEDA role, scope, CSRF token or verified address is missing.
404NOT_FOUNDThe resource does not exist, or you cannot see it.
409CONFLICT, NAME_TAKEN and othersThe state changed or the name is in use; reload and retry.
422VERIFICATION_FAILED, POLICY_NOT_FOUND and othersA signed object in the body did not verify, or the body names something that does not exist in the organization.
429RATE_LIMITED, DISCOVERY_BUSYWait for Retry-After seconds.
500INTERNAL_ERRORAn unexpected error on K-Block's side. Contact K-Block support with the code and the request ID.
503SERVICE_UNAVAILABLEK-Block is temporarily unavailable or busy; retry later, after Retry-After (5 seconds) when the answer carries it. If it continues, contact K-Block support with the code and the request ID.

A 5xx answer with a code that Error codes does not list, and a 503 without Retry-After, mean a problem on K-Block's side, for example when K-Block cannot send e-mail right now or plans cannot be bought or managed here (see Server-side problems). Their codes are for K-Block's own diagnosis. Retry later; if the problem continues, contact K-Block support with the request ID from the X-Request-Id response header.

The full list with meanings is on Error codes.

Rate limits

Every route under /api/v1 is rate limited per client IP address (1,200 requests per minute) and, when the request carries a session or an API key, per credential (600 requests per minute). Design your scripts for these numbers.

Sensitive routes have their own, lower limits, for example sign-in, sign-up, password reset, invitations, webhook tests, dry runs and policy analysis. The numbers are on Limits and supported versions.

A refused request answers 429 RATE_LIMITED with a Retry-After header and details.retry_after_seconds. Nothing was changed; repeat the same request after the wait.

Idempotency

The Cloud API has no Idempotency-Key header, and it does not deduplicate repeated writes. If a create request times out, list the resources before you retry it: a repeated create can create a second resource, or fail with a uniqueness error such as 409 NAME_TAKEN.

Idempotency keys exist for agent tool calls at the Gateway, where a call can carry kblock/idempotency-key. See Actions.

Route families

Paths below are relative to /api/v1. "Members" means every role; "Writers" means owner, admin and developer; "Approvers" means owner, admin and approver; "Admins" means owner and admin. "Key" names the scope a management key needs, or "no" when keys are refused.

Account and session

These routes act on the signed-in person, not on an organization.

Method and pathWhoKey
POST /auth/signupAnyone (202 whether or not the address already has an account)no
POST /auth/signinAnyoneno
POST /auth/signout, GET /auth/sessionSigned-in personno
POST /auth/passwordSigned-in person (current password required)no
POST /auth/email/verify, POST /auth/email/resendLink holder / anyoneno
POST /auth/email/change/approve, POST /auth/email/change/rejectLink holderno
POST /me/emailSigned-in person (password required)no
POST /auth/password-reset, POST /auth/password-reset/confirmAnyone / link holderno
POST /me/identity-challenges, GET /me/identities, POST /me/identities, DELETE /me/identities/<kid>Signed-in personno
POST /invitations/acceptSigned-in invitee whose verified address matchesno
GET /gateway/identityAny signed-in person or management keyany scope

Organizations, members and invitations

Method and pathWhoKey
POST /orgsAny signed-in person with a verified address (becomes owner)no
GET /orgs/<org-id>Membersread
PATCH /orgs/<org-id>Admins; the observe settings: owner onlyno
POST /orgs/<org-id>/switchMembersno
GET /orgs/<org-id>/membersMembersno
PATCH /orgs/<org-id>/members/<user-id>Admins; granting or changing owner: owner onlyno
DELETE /orgs/<org-id>/members/<user-id>Yourself; others: admins; an owner: owner onlyno
GET, POST /orgs/<org-id>/invitations; DELETE …/invitations/<id>Adminsno
GET, POST /orgs/<org-id>/principalMembers read; owner setsread (GET only)

API keys and audit log

Method and pathWhoKey
GET /orgs/<org-id>/api-keysWriters; developers see gateway keys onlyno
POST /orgs/<org-id>/api-keysGateway keys: writers; management keys: adminsno
POST /orgs/<org-id>/api-keys/<key-id>/revokeSame as creating that kindno
GET /orgs/<org-id>/auditAdminsno

Agents, delegations and observe windows

Method and pathWhoKey
GET /orgs/<org-id>/agents, GET …/agents/<id>Membersread
POST /orgs/<org-id>/agentsWritersagents:write
PATCH /orgs/<org-id>/agents/<id>Writers; switching the policy: admins, signed inagents:write
GET …/agents/<id>/delegationsMembersread
POST …/agents/<id>/delegations, POST /orgs/<org-id>/delegations/<id>/revokeAdminsno
POST …/agents/<id>/dry-runMembersread
GET …/agents/<id>/observe, GET /orgs/<org-id>/observe-windows, GET …/observe-windows/<id>, GET …/observe-windows/<id>/reportMembersread
POST …/agents/<id>/observeAdminsno
POST …/agents/<id>/observe/end, POST /orgs/<org-id>/observe/end-allWritersagents:write

MCP servers and tools

Method and pathWhoKey
GET /orgs/<org-id>/mcp-servers, GET …/mcp-servers/<id>Membersread
POST /orgs/<org-id>/mcp-serversWriterstools:write
PATCH …/mcp-servers/<id>Writers; changing what an enabled tool is bound to: admins, signed intools:write
DELETE …/mcp-servers/<id>, POST …/mcp-servers/<id>/discoverWriterstools:write
GET /orgs/<org-id>/tools, GET …/tools/<id>Membersread
POST /orgs/<org-id>/tools, PATCH …/tools/<id>Writers; enabling a tool or changing what an enabled tool means: admins, signed intools:write
POST …/tools/<id>/authorizeAdmins, signed inno (a key with tools:write passes the scope check, then gets 403 ADMIN_REQUIRED)

Policies

Method and pathWhoKey
GET /orgs/<org-id>/policies, GET …/policies/<id>, GET /orgs/<org-id>/policy-templates, GET /orgs/<org-id>/policy-statusMembersread
POST /orgs/<org-id>/policies/validateMembersread
POST /orgs/<org-id>/policies, POST …/policies/from-template, POST …/policies/<id>/versionsWriterspolicies:write
POST …/policies/<id>/versions/<version-id>/activateAdminsno
POST …/policies/<id>/rollback, POST …/policies/<id>/emergency, POST …/policies/<id>/supersede-open-actionsAdminsno
PATCH …/policies/<id> (agent disclosure)Adminsno
PUT, DELETE …/policies/<id>/shadow; PUT …/policies/<id>/examplesWriterspolicies:write
POST …/policies/<id>/simulate; GET …/simulations, GET …/simulations/<id>, GET …/shadow/report, GET …/versions/<version-id>/decision-map, GET …/diffMembersread
POST …/policies/<id>/simulationsWriterspolicies:write
GET …/policies/<id>/evidenceAdminsno

Approvals, actions and receipts

Method and pathWhoKey
GET /orgs/<org-id>/approvals, GET …/approvals/<id>Membersapprovals:read
POST …/approvals/<id>/decisionApprovers listed for that requestno
GET /orgs/<org-id>/actions, GET …/actions/<id>Membersread
POST …/actions/<id>/cancelAdminsno
GET /orgs/<org-id>/receipts, GET …/receipts/<id>, GET …/receipts/<id>/decision-check, GET …/receipts/<id>/bundleMembersreceipts:read

An approval decision carries an object signed in the person's browser with their personal K-Block key. A cancellation carries one signed by the organization principal, the identity set with POST /orgs/<org-id>/principal. The dashboard creates both. See How approvals work.

Overview, webhooks and billing

Method and pathWhoKey
GET /orgs/<org-id>/overview, GET /orgs/<org-id>/usage, GET /orgs/<org-id>/billingMembersread
GET, POST /orgs/<org-id>/webhooks; GET, PATCH, DELETE …/webhooks/<id>Writersno
GET …/webhooks/<id>/deliveries, POST …/deliveries/<id>/redeliver, POST …/webhooks/<id>/testWritersno
POST …/billing/checkout, POST …/billing/portalOwnerno

The Cloud API also has a route that receives events from Creem, K-Block's billing provider. Only Creem calls it; it is not for your scripts.

What to do next