Audience: Downstream integrators — teams building applications or services on top of the Credence API.
This document explains every scope your API key can carry, which endpoints each scope unlocks, and how to request the exact set of permissions your integration needs.
Every API key is issued with an explicit list of scopes. When the key is used on a request, the middleware checks whether the granted scopes satisfy the scope required by that endpoint. The check is deny-by-default: if the key does not carry the required scope, the request is rejected with 403 Forbidden before reaching any handler.
POST /api/attestations
Authorization: Bearer cr_a3f2b1c0...
│
┌──────▼───────────┐
│ requireApiKey │
│ (attestations: │
│ write) │
└──────┬───────────┘
key has scope? │
┌───────────────┴────────────────┐
│ yes │ no
▼ ▼
handler runs 403 Forbidden
{ requiredScope,
grantedScopes }
The 403 response always includes requiredScope and grantedScopes so you can diagnose the mismatch without contacting support:
{
"error": "Forbidden",
"message": "Insufficient scope: 'attestations:write' is required",
"requiredScope": "attestations:write",
"grantedScopes": ["trust:read", "attestations:read"]
}Request only the scopes your integration actually uses. Narrower keys reduce blast radius if a credential is compromised.
| Scope | What it unlocks |
|---|---|
trust:read |
Read trust scores and bond data (GET /api/trust/*) |
attestations:read |
List and count attestations (GET /api/attestations/*) |
attestations:write |
Create and revoke attestations (POST /api/attestations, DELETE /api/attestations/:id) |
payouts:write |
Initiate payout / settlement operations (POST /api/payouts) |
reports:generate |
Trigger and poll report generation jobs (POST /api/reports, GET /api/reports/:jobId) |
exports:read |
Download report artifacts and audit-log exports (GET /api/reports/download/:key) |
webhooks:admin |
Rotate and revoke webhook signing secrets (POST /api/admin/webhooks/:id/rotate, POST /api/admin/webhooks/:id/revoke-previous) |
outbox:reinject |
Reinsert fixed quarantined outbox events (operator use only) |
admin:read |
Read admin resources — users, audit logs, failed events |
admin:write |
Mutate admin resources — assign roles, revoke keys, replay events, impersonate |
flags:read |
Read feature flag state |
flags:write |
Modify feature flag state |
Keys issued before the granular model was introduced carry one of two tier strings. They continue to work and are automatically expanded at validation time — no migration is required.
| Legacy scope | Automatically expands to |
|---|---|
public |
trust:read, attestations:read |
enterprise |
All granular scopes (full access) |
Do not request enterprise for new integrations unless every operation listed above is genuinely needed. Issue per-operation keys instead.
| Endpoint | Required scope |
|---|---|
GET /api/trust/:address |
trust:read |
GET /api/attestations/:identity |
attestations:read |
GET /api/attestations/:identity/count |
attestations:read |
POST /api/attestations |
attestations:write |
DELETE /api/attestations/:id |
attestations:write |
POST /api/payouts |
payouts:write |
POST /api/reports |
reports:generate |
GET /api/reports/:jobId |
reports:generate |
GET /api/reports/download/:key |
(signed URL — no key) |
POST /api/admin/webhooks/:id/rotate |
webhooks:admin |
POST /api/admin/webhooks/:id/revoke-previous |
webhooks:admin |
Pass an explicit scopes array when creating a key. The raw key is returned exactly once in the 201 response — store it securely.
POST /api/api-keys
Content-Type: application/json
Authorization: Bearer cr_<your_key_here>
{
"ownerId": "service-account-payments",
"scopes": ["attestations:read", "attestations:write"],
"tier": "pro"
}Response:
{
"id": "3f8a1c2b",
"key": "cr_a3f2b1c0d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1",
"prefix": "a3f2b1c0",
"scopes": ["attestations:read", "attestations:write"],
"tier": "pro",
"createdAt": "2026-07-29T14:00:00.000Z"
}The raw key value is shown only once. After this response, only a SHA-256 hash is stored. If you lose the key, rotate it to get a new one.
Include the key in one of these headers (X-API-Key takes precedence when both are present):
X-API-Key: cr_a3f2b1c0d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1Authorization: Bearer cr_a3f2b1c0d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1# Issue a key with trust:read scope
KEY_RESPONSE=$(curl -s -X POST https://api.example.com/api/api-keys \
-H "Content-Type: application/json" \
-H "Authorization: Bearer cr_<admin_key>" \
-d '{"ownerId":"my-service","scopes":["trust:read"],"tier":"free"}')
API_KEY=$(echo "$KEY_RESPONSE" | jq -r '.key')
# Use the key
curl -s https://api.example.com/api/trust/GABCDE... \
-H "X-API-Key: $API_KEY"A few guidelines for new integrations:
- Read-only dashboards / monitoring —
trust:read,attestations:read - Attestation pipelines —
attestations:read,attestations:write - Settlement / payout automation —
payouts:write(addattestations:writeonly if the same service also writes attestations) - Report generation services —
reports:generate,exports:read - Webhook rotation scripts —
webhooks:adminonly - Full-access service accounts — prefer combining granular scopes over using
enterprise
| Operation | How | Effect |
|---|---|---|
| Issue | POST /api/api-keys |
Creates a new key; raw value returned once |
| List | GET /api/api-keys/:ownerId |
Returns metadata (no raw key) |
| Rotate | POST /api/api-keys/:id/rotate |
Revokes old key, issues new key with the same scopes |
| Revoke | DELETE /api/api-keys/:id |
Immediately invalidates key; subsequent requests get 401 |
Revocation is immediate. A revoked key cannot be reactivated — issue a new one if access needs to be restored.
| Status | Cause | Body (example) |
|---|---|---|
| 401 | No key in request headers | {"error":"Unauthorized","message":"API key is required"} |
| 401 | Key not found, bad format, or revoked | {"error":"Unauthorized","message":"Invalid API key"} |
| 403 | Key lacks the required scope | {"error":"Forbidden","message":"Insufficient scope: 'attestations:write' is required","requiredScope":"attestations:write","grantedScopes":["trust:read"]} |
- docs/api-keys.md — Full API key CRUD reference with request/response examples, rotation, and revocation.
- docs/SECURITY.md — Security architecture: deny-by-default enforcement, no scope escalation on rotation, audit trail on every 403.
- docs/JWT_CLAIMS.md — The
scopeclaim in JWTs and how consumer middleware validates it. - docs/rate-limiting.md — Per-tier rate limits (
free100 req/min ·pro1 000 req/min ·enterprise10 000 req/min).