Overview
The Corsair REST API provides programmatic access to CPOE signing and verification. All endpoints follow a consistent JSON envelope with request IDs for tracing.
Base URL: https://api.grcorsair.com
Versioning: Current public endpoints are unversioned. A /v1 namespace is planned.
Every response includes:
X-Request-Idheader for tracingX-Corsair-Versionheader with the API version- CORS headers (
Access-Control-Allow-Origin: *)
Persistence
The hosted API requires Postgres for key storage, SCITT entries, and audit trails. Set DATABASE_URL in production. CLI-only usage is file-based and does not require a database.
Authentication
Protected endpoints require a Bearer token in the Authorization header. Use an API key or an OIDC token (when OIDC is configured).
OIDC issuers are configured via CORSAIR_OIDC_CONFIG and may include claimMapping and requireJti.
curl -X POST https://api.grcorsair.com/sign \
-H "Authorization: Bearer <api-key-or-oidc-token>" \
-H "Content-Type: application/json" \
-d '{"evidence": {...}}'
Public endpoints (verify, health) require no authentication.
| Endpoint | Auth Required |
|---|---|
GET /health | No |
POST /sign | Yes |
POST /verify | No |
POST /issue | Yes |
POST /onboard | Yes |
GET /scitt/entries | No |
POST /scitt/entries | Yes |
POST /ssf/streams | Yes |
Response Envelope
{
"ok": true,
"data": { ... }
}
Error responses use the same envelope:
{
"ok": false,
"error": {
"code": "validation_error",
"message": "Missing required field: \"evidence\""
}
}
POST /sign
Sign evidence into a CPOE (JWT-VC). Accepts raw tool output via mapping packs or generic format. Requires authentication (API key or OIDC token).
To support additional tools without code changes, configure the mapping registry on the API server via CORSAIR_MAPPING_DIR, CORSAIR_MAPPING_FILE, or corsair mappings add. Build packs with corsair mappings pack and sign them with corsair mappings sign. Mappings are evaluated by priority (higher wins), then filename order. Signed packs are verified when CORSAIR_MAPPING_PACK_PUBKEY is set.
curl -X POST https://api.grcorsair.com/sign \
-H "Authorization: Bearer $AUTH_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"evidence": {
"metadata": { "title": "S3 Controls", "issuer": "Acme", "scope": "AWS Production" },
"controls": [
{ "id": "S3-001", "description": "Bucket versioning enabled", "status": "pass" }
]
},
"scope": "AWS Production - S3 Controls",
"expiryDays": 90
}'
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
evidence | object or string | Yes | Raw tool output (mapping pack or generic) |
format | string | No | Force generic format (bypasses mapping registry) |
did | string | No | Override issuer DID (defaults to did:web:<CORSAIR_DOMAIN>) |
scope | string | Conditional | Required if evidence.metadata.scope is missing |
expiryDays | number | No | CPOE validity in days (default: 7) |
dryRun | boolean | No | Parse without signing |
dependencies | array | No | Dependency proofs to attach (trust graph) |
registerScitt | boolean | No | Register signed CPOE in SCITT log (default: false). Also accepts header x-corsair-register-scitt: true. |
Response (issuer defaults to did:web:<CORSAIR_DOMAIN> if not provided):
{
"ok": true,
"data": {
"cpoe": "eyJhbGciOiJFZERTQSIsInR5cCI6InZjK2p3dCIs...",
"marqueId": "marque-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"detectedFormat": "generic",
"summary": {
"controlsTested": 24,
"controlsPassed": 22,
"controlsFailed": 2,
"overallScore": 91
},
"provenance": {
"source": "tool",
"sourceIdentity": "Acme",
"sourceDate": "2026-02-13T00:00:00Z"
},
"extensions": {
"mapping": { "id": "toolx-evidence-only", "evidenceOnly": true },
"passthrough": { "summary": { "passed": 12, "failed": 2 } }
},
"warnings": [],
"expiresAt": "2026-05-14T00:00:00.000Z",
"scittEntryId": "entry-acde1234-..."
}
}
Note: registerScitt is also supported by POST /issue and returns scittEntryId when enabled.
POST /onboard
Generate machine-actionable onboarding artifacts (did.json, jwks.json, trust.txt) for your domain.
Requires authentication (API key or OIDC token).
curl -X POST https://api.grcorsair.com/onboard \
-H "Authorization: Bearer $AUTH_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"contact": "[email protected]",
"frameworks": ["SOC2", "ISO27001"],
"includeDefaults": true
}'
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
domain | string | No | Domain for onboarding (must match server domain) |
did | string | No | DID override (must match domain; no path support) |
cpoes | array | No | CPOE URLs to list in trust.txt |
scitt | string | No | SCITT endpoint override |
catalog | string | No | Catalog snapshot URL |
policy | string | No | Policy artifact URL |
flagship | string | No | FLAGSHIP stream endpoint override |
frameworks | array | No | Compliance frameworks in scope |
contact | string | No | Compliance contact |
expiryDays | number | No | trust.txt expiry window in days (default: 365) |
includeDefaults | boolean | No | Populate default SCITT/FLAGSHIP URLs (default: true) |
Response (machine-actionable files):
{
"domain": "acme.com",
"did": "did:web:acme.com",
"urls": {
"didJson": "https://acme.com/.well-known/did.json",
"jwksJson": "https://acme.com/.well-known/jwks.json",
"trustTxt": "https://acme.com/.well-known/trust.txt"
},
"files": {
"didJson": {
"path": "/.well-known/did.json",
"mediaType": "application/did+ld+json",
"content": { "@context": ["https://www.w3.org/ns/did/v1"] }
},
"jwksJson": {
"path": "/.well-known/jwks.json",
"mediaType": "application/jwk-set+json",
"content": { "keys": [] }
},
"trustTxt": {
"path": "/.well-known/trust.txt",
"mediaType": "text/plain",
"content": "DID: did:web:acme.com\\n...",
"parsed": { "did": "did:web:acme.com", "cpoes": [], "frameworks": [] },
"validation": { "valid": true, "errors": [] }
}
}
}
POST /verify
Verify a CPOE signature and extract attestation details. No authentication required. Optional policy checks and process receipt verification are supported.
Policy fields include:
requireSource(self|tool|auditor)requireSourceIdentity(array of allowed identities)requireToolAttestation(boolean)requireInputBinding(boolean, requiressourceDocumentHash)requireEvidenceChain(boolean, CLI-only because it needs the JSONL evidence file)requireReceipts(boolean)requireScitt(boolean)
curl -X POST https://api.grcorsair.com/verify \
-H "Content-Type: application/json" \
-d '{
"cpoe": "eyJhbGciOiJFZERTQSIsInR5cCI6InZjK2p3dCIs...",
"policy": {
"requireIssuer": "did:web:grcorsair.com",
"requireFramework": ["SOC2"],
"maxAgeDays": 30,
"minScore": 90,
"requireSource": "tool",
"requireSourceIdentity": ["Scanner v1.2"],
"requireReceipts": true,
"requireScitt": true,
"requireInputBinding": true
},
"receipts": [],
"sourceDocumentHash": "a2b4c6d8..."
}'
Response:
{
"ok": true,
"data": {
"valid": true,
"issuer": "did:web:grcorsair.com",
"trustTier": "corsair-verified",
"scope": "SOC 2 Type II - AWS Production Controls",
"summary": {
"controlsTested": 24,
"controlsPassed": 22,
"controlsFailed": 2,
"overallScore": 91
},
"provenance": {
"source": "tool",
"sourceIdentity": "Scanner v1.2",
"sourceDate": "2026-01-15"
},
"extensions": {
"mapping": { "id": "toolx-evidence-only", "evidenceOnly": true },
"passthrough": { "summary": { "passed": 12, "failed": 2 } }
},
"timestamps": {
"issuedAt": "2026-02-13T00:00:00.000Z",
"expiresAt": "2026-05-14T00:00:00.000Z"
},
"policy": { "ok": true, "errors": [] },
"process": { "chainValid": true, "receiptsVerified": 2, "receiptsTotal": 2 },
"inputBinding": { "ok": true, "errors": [] }
}
}
sourceDocumentHash should be the SHA-256 of canonical JSON (sorted keys), matching provenance.sourceDocument.