Skip to content

The /v1 API

View as Markdown

The API the BatonDeck portal is built on, and the one a program talks to.

Two credentials. A browser sends the portal session cookie and, on anything that changes state, must be same-origin. A program sends Authorization: Bearer <key> — a workspace API key, minted in the portal, shown once. A key is never wider than the owner who minted it: its scopes narrow their permissions and can never widen them.

A key has no session, so it has no step-up: every operation marked as requiring one is refused to a key, whatever scopes it carries. Those are the irreversible ones — export, deletion, key rotation, changing who is in the workspace — and a person has to be present for them.

Webhooks. A workspace registers an endpoint with POST /v1/workspace/webhooks, naming the events it wants, and lists its endpoints with GET /v1/workspace/webhooks, which also answers the event names a filter may use. Each delivery is a JSON POST to the endpoint, signed in X-BatonDeck-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<body>" under the endpoint's secret> (two v1 values while a rotated secret is still accepted), and carrying X-BatonDeck-Event-Id, X-BatonDeck-Event-Type and X-BatonDeck-Delivery. Nothing is delivered while the workspace’s webhooks_enabled flag is off; the list says which it is, as enabled.

Server: https://api.batondeck.com · OpenAPI: 3.1.0 document (109 operations; the same document the API serves at https://api.batondeck.com/v1/openapi.json).

Scheme How it is sent Notes
session cookie __Host-bd_session
apiKey Authorization: Bearer … A workspace API key: bd_<id>_<secret>. Minted by a person on the portal’s Agents page (Agent keys), which calls POST /v1/workspace/keys with a session; a key cannot mint one, because minting needs step-up. Shown once, hashed at rest. Malformed, unknown and revoked keys answer identically.

Every refusal answers this body:

{
"type": "object",
"properties": {
"error": {
"type": "object",
"properties": {
"code": {
"description": "a stable machine-readable code; HDTP §12 names where a call maps to one",
"type": "string"
},
"message": {
"description": "what went wrong, in words a person can act on",
"type": "string"
},
"request_id": {
"description": "the same id that appears in our logs for this request",
"type": "string"
},
"retry_after": {
"description": "on a 429: seconds until the window closes, as the Retry-After header says",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
}
},
"required": [
"code",
"message",
"request_id"
],
"additionalProperties": false
}
},
"required": [
"error"
],
"additionalProperties": false
}

The API answers cross-origin (CORS) requests only on /mcp, /oauth/token, /oauth/register, /oauth/revoke, /.well-known/. /v1 is not among them, so a page on another origin — this one included — cannot call it, and this reference has no in-page “try it”. Each operation shows the curl call instead.