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
| format | kind:id, optionally @version | |
| kinds | user, agent, model, rule, system, connection | |
| required on | Every request that is not GET or HEAD. Missing: 400 ACTOR_REQUIRED. Malformed or unknown kind: 400 ACTOR_INVALID. | |
| on reads | Optional. 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 UNAUTHENTICATED | No key, unknown key, revoked key | |
| 404 COMPANY_NOT_FOUND | Your partner holds no grant on the company. It is not distinguishable from a company that does not exist. | |
| 403 SCOPE_MISSING | The grant exists but lacks the scope this endpoint needs; scope names it |
Headers on every request
| Authorization | all requests | Bearer vx_… |
| X-Actor | POST, PATCH, DELETE | Who inside your software acts. See above. |
| Idempotency-Key | POST | Unique per logical request. Missing: 400 IDEMPOTENCY_KEY_REQUIRED. See Idempotency. |
| Content-Type | with a body | application/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.