Developer essentials

Authentication

An API key says which partner is calling. An actor says who inside that partner acted. A grant says what the partner may do on a company.

API keys

Vexless issues your organisation, a partner, an API key. It starts with vx_, is shown once, and is sent as a bearer token on every request.

Authorization: Bearer vx_…

One key serves every company your partner holds a grant on, live and sandbox alike; there is no per-company key and no sandbox key. A request without a valid key, or with a revoked one, answers 401 UNAUTHENTICATED. Keep the key server-side. It is never appropriate in a browser or a mobile app.

Actors

Every write names who inside your software is acting. The ledger records it on everything the call produces: the interpretation and entry it posts, the payment it approves, the allocation it states, the change log behind all of them.

X-Actor: user:mikko
X-Actor: agent:billing@1.4
X-Actor: system:nightly-sync
formatkind:id, optionally @version
kindsuser, agent, model, rule, system, connection
required onEvery request that is not GET or HEAD. Missing: 400 ACTOR_REQUIRED. Malformed or unknown kind: 400 ACTOR_INVALID.
on readsOptional. Without it, the actor is your partner.

The actor is free text within the format. Use ids that mean something to you when you read them back a year later, and version your agents. When a model authors an interpretation it is model:name@version, an actor like any other; the chain already carries it.

Access to a company

The key identifies your partner. What you may do on a company is decided by the grant your partner holds on it. Creating a company grants the creator the standard scopes; a grant may be extended to other partners.

401 UNAUTHENTICATEDNo key, unknown key, revoked key
404 COMPANY_NOT_FOUNDYour partner holds no grant on the company. It is not distinguishable from a company that does not exist.
403 SCOPE_MISSINGThe grant exists but lacks the scope this endpoint needs; scope names it

Headers on every request

Authorizationall requestsBearer vx_…
X-ActorPOST, PATCH, DELETEWho inside your software acts. See above.
Idempotency-KeyPOSTUnique per logical request. Missing: 400 IDEMPOTENCY_KEY_REQUIRED. See Idempotency.
Content-Typewith a bodyapplication/json
POST /v1/companies/cmp_…/origins
Authorization: Bearer vx_…
X-Actor: agent:billing@1.4
Idempotency-Key: cmp_…-inv-2026-000117
Content-Type: application/json

{ "type": "SALES_INVOICE", … }

Base URL and versioning

https://api.vexless.io/v1          # reserved for the service; not live yet

The path carries the major version. Additive changes, new fields and new endpoints, arrive without a version change; every response is typed in the OpenAPI document, so read fields by name and tolerate ones you do not know.