REST API
All API endpoints are under /api/v1 and require authentication. How the caller is identified depends on the authentication mode: a bearer JWT in verify mode, or X-User-ID and companion headers in trust mode. Every call is scoped to a tenant.
The full contract is published as OpenAPI in the repository at api/openapi.yaml and served by every Quorum at /openapi.yaml. The test suite validates real server traffic against it, so it is never out of date.
Endpoints
Section titled “Endpoints”| Method | Path | Purpose |
|---|---|---|
POST |
/api/v1/requests |
Create a request. Send an Idempotency-Key header to make retries safe. |
GET |
/api/v1/requests |
List requests, with status and type filters and pagination. |
GET |
/api/v1/requests/{id} |
Get a request, including viewer_can_act for the caller. |
POST |
/api/v1/requests/{id}/approve |
Record an approval vote on the current stage. |
POST |
/api/v1/requests/{id}/reject |
Record a rejection vote on the current stage. |
POST |
/api/v1/requests/{id}/cancel |
Cancel a pending request. Only the maker may cancel. |
GET |
/api/v1/requests/{id}/audit |
The audit trail of a request. |
GET |
/api/v1/requests/{id}/events |
Server-Sent Events stream of state changes for a request. |
POST |
/api/v1/policies |
Create a policy. One policy per request type per tenant. |
GET |
/api/v1/policies |
List policies. |
GET |
/api/v1/policies/{id} |
Get a policy. |
PUT |
/api/v1/policies/{id} |
Update a policy. Applies to requests created from then on. |
DELETE |
/api/v1/policies/{id} |
Delete a policy. |
POST |
/api/v1/webhooks |
Subscribe a webhook to one or more events. |
GET |
/api/v1/webhooks |
List webhooks. |
DELETE |
/api/v1/webhooks/{id} |
Delete a webhook. |
GET |
/health |
Component health and the running version. No authentication. |
The request lifecycle in three calls
Section titled “The request lifecycle in three calls”The wire transfer walkthrough shows the lifecycle end to end. In short:
# Maker createscurl -X POST http://localhost:8080/api/v1/requests \ -H "Content-Type: application/json" -H "X-User-ID: alice" \ -d '{"type": "wire_transfer", "payload": {"amount": 50000, "destination": "IBAN-12345"}}'
# Checker approvescurl -X POST http://localhost:8080/api/v1/requests/{id}/approve \ -H "X-User-ID: bob" -H "X-User-Roles: manager" \ -d '{"comment": "Funds available."}'
# Anyone in the tenant reads the trailcurl http://localhost:8080/api/v1/requests/{id}/audit -H "X-User-ID: auditor"Errors
Section titled “Errors”A decision that fails a permission guard returns 403. A request for a resource that does not exist in the caller’s tenant returns 404, so one tenant cannot discover another’s IDs. A duplicate pending request for the same fingerprint returns 409, as does a vote on a request that is no longer pending or a second vote by the same checker on one stage. Validation failures return 400 with a message naming the field.
Clients
Section titled “Clients”Rather than calling the API by hand, use the Go client, which shares the server’s own types, or the @oluwavader/quorum-embed package, which exposes a small browser client alongside the widgets.
Quorum is built by Olawale Lawal.