HTTP Transport

HTTP is the primary transport for web-based consumers including the BEST web UI. The HTTP API surface is fully described by the capability endpoints arrays in the discovery manifest — no separate OpenAPI document is required from implementers.

HTTP is the baseline transport — every conformant service exposes it. All requests and responses are application/json (schemas are application/schema+json; SSE is text/event-stream).

POST /commands carries one BEST envelope in the CloudEvents structured content mode. Servers must accept Content-Type: application/cloudevents+json and, for compatibility, application/json; consumers should send the former. With it, a CloudEvents SDK's HTTP sender produces a valid BEST request unchanged.

Path resolution: every capability path is appended to the service's http.endpoint. The leading slash is a separator, not a root-relative indicator:

http.endpoint Path Resolved
https://app.example.com/ /commands https://app.example.com/commands
https://api.example.com/tenants/acme /commands https://api.example.com/tenants/acme/commands

http.endpoint must be the consumer-facing public address — never an internal backend or service-mesh URL.

Authentication: per the authentication block governing the service (its own, else the root's) — bearer → Authorization: Bearer <token>; apiKey → header or query parameter named in scheme. GET /.well-known/best, the capabilities of a service that declares "type": "none", and the deviceAuthorizationUrl and tokenUrl endpoints need no credential; everything else does when one is declared.

Errors: all endpoints use a consistent body (error.json):

{ "error": { "code": "SCHEMA_NOT_FOUND", "message": "Unknown command schema 'foo'", "details": {} } }

Status codes:

Status When
200 Success with body (queries, event lists, catalogues, schema documents)
201 Created — command accepted and durably queued
202 Accepted without durability guarantee (see Ingestion Semantics)
400 Invalid request body or parameters (schema validation failure), or a well-formed command the service cannot honour in its current state, with a code that names the condition
401 Missing/invalid credentials (only when the governing authentication.type is not none)
404 Unknown route, schema name, or version
409 Conflict — duplicate command id: with a different payload always, with the same payload when the service rejects a duplicate rather than ignoring it
413 Request body exceeds server limits
415 POST /commands with a Content-Type the server does not take; the error says which it takes
422 Semantic error (capability not supported)
429 A command past the server's pace; Retry-After says when to send again
500 Internal error

Behind a proxy

If the implementer routes traffic internally, http.endpoint is the outermost address consumers hit: the public or proxy address.

For a tenant's address, see Multi-Tenancy.

Sending credentials

For oauth2, obtain a token from authentication.tokenUrl, then send Authorization: Bearer <token>. An apiKey in a query parameter carries short-lived exchanged tokens only, never long-lived keys.

The security schemes are formally declared in the OpenAPI securitySchemes component. The constraints on the exchange are in Security — Token Exchange and Query-String Credentials.

OpenAPI Specs

spec/v0.9.21