Skip to content

7. Use the HTTP API ​

This guide covers calling the DIP API directly. The dip CLI and the SDK wrap these same calls.

Base URL and headers ​

bash
export DIP_URL="https://<your-dip-server>"
export DIP_API_KEY="<your-api-key>"

Send JSON, and authenticate with a Bearer key:

Authorization: Bearer <api-key>
Content-Type: application/json

The full description of every route is in docs/api/openapi.json. Load it in any OpenAPI viewer.

Keys and scopes ​

Each API key belongs to one principal, with one tenant, and carries zero or more scopes.

ScopeLets the key
(none)Publish and read authorities, normalize and authorize requests, execute, read evidence, verify bundles
approverRequest approvals, and approve, reject or revoke them
adminRead the ledger and verify it

Keys are tenant-bound. A request for another tenant's data is refused with TENANT_FORBIDDEN, and evidence from another tenant appears as EVIDENCE_NOT_FOUND, so existence is not revealed.

Routes ​

Method and pathPurpose
GET /v1/healthLiveness. Public, no key needed. Returns {"status":"ok"}
POST /v1/authoritiesPublish a signed authority
GET /v1/authorities/:idRead a published authority
POST /v1/authorities/:id/revokePublish a signed revocation
POST /v1/requests/normalizeCanonicalize a request and compute its digest
POST /v1/authorizeAuthorize a request. Returns ALLOW or DENY
POST /v1/approvalsRequest an approval (approver scope)
GET /v1/approvals/:idRead an approval's state
POST /v1/approvals/:id/approveApprove (approver scope)
POST /v1/approvals/:id/rejectReject (approver scope)
POST /v1/approvals/:id/revokeRevoke an approval (approver scope)
POST /v1/executeExecute an authorized request with its decision
GET /v1/evidence/:idRead one evidence record
POST /v1/verifyVerify an exported bundle
GET /v1/ledgerList evidence (admin scope)
POST /v1/ledger/verifyVerify the ledger (admin scope). Body may include expectedHead

A complete call ​

bash
curl -sS -X POST "$DIP_URL/v1/authorize" \
  -H "Authorization: Bearer $DIP_API_KEY" \
  -H "Content-Type: application/json" \
  --data @request.json

A successful call returns 200 with result set to ALLOW or DENY.

A DENY is a successful call. It returns 200. Check result, not the HTTP status, to learn the answer.

Errors ​

Every error has the form {"error": "<CODE>", "message": "<text>"}.

StatusCodeMeaningWhat to do
400INVALID_BODYThe body is missing fields or is malformedFix the request. Do not retry unchanged
401UNAUTHORIZEDThe key is missing or invalidCheck the key and the header
403FORBIDDENThe key lacks the required scopeUse a key with the right scope
403TENANT_FORBIDDENThe request or authority belongs to another tenantUse a key for that tenant
404NOT_FOUND, AUTHORITY_NOT_FOUND, EVIDENCE_NOT_FOUNDThe item does not exist, or is not visible to your tenantCheck the ID
405METHOD_NOT_ALLOWEDWrong HTTP method for the routeCheck the route table
409a protocol codeThe request conflicts with recorded state, for example an idempotency key reused with different contentUse a new idempotency key for a new action
422a protocol codeThe request is well formed, but breaks a protocol rule. The error field names the ruleRead the rule and fix the request
429RATE_LIMITEDToo many requests from this key in the windowWait, then retry
500INTERNAL_ERRORThe server failedRetry later. If it persists, report it with the time and the request ID

A 500 does not tell you whether an action ran. For execution, check the attempt state (see 04-authorize-and-execute.md) before you do anything else.

Rate limits ​

Limits are per key and per window. They are shared across server processes when the server has a database. A 429 is a normal response under load, so back off and retry rather than retrying immediately.

Health ​

bash
curl -sS "$DIP_URL/v1/health"

Expected: {"status":"ok"}. Use this for load balancer checks.

Released under the Apache License 2.0.