API Reference¶
Complete reference for the Diogenes REST API. All endpoints are prefixed with /api/v1.
Interactive API Explorer
Try the API interactively using the Swagger UI or the ReDoc viewer.
Health¶
GET /api/v1/health¶
Check server status.
Response:
Authentication¶
Authentication uses a challenge-response protocol. The client requests a challenge nonce, signs it with their private key, and submits the signature to obtain a JWT.
POST /api/v1/auth/challenge¶
Request an authentication challenge.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
fingerprint |
string | Yes | Key fingerprint to authenticate as |
recovery |
boolean | No | Request a recovery challenge (default: false) |
purpose |
string | No | Challenge purpose: "general" or "login" (default: "general") |
Response:
{
"challenge_id": "abc123...",
"nonce": "random-nonce-value",
"expires_at": "2026-01-15T10:35:00Z"
}
POST /api/v1/auth/login¶
Authenticate and receive a JWT.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
challenge_id |
string | Yes | The challenge ID from /auth/challenge |
challenge_signature |
string | Yes | Signature of the challenge nonce |
password |
string | No | Password if one is registered for this key |
Response:
{
"token": "eyJ...",
"fingerprint": "sha256:...",
"pseudonym": "Alice Scholar",
"expires_at": "2026-01-15T11:00:00Z"
}
Error codes: 404 Challenge not found, 410 Challenge expired, 409 Challenge already used, 403 Invalid signature or password.
POST /api/v1/auth/renew¶
Renew an existing JWT before it expires.
Headers: Authorization: Bearer <token>
Response: Same as /auth/login.
POST /api/v1/auth/password¶
Set or change a password for a key.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
challenge_id |
string | Yes | Auth challenge ID |
challenge_signature |
string | Yes | Signed challenge nonce |
password |
string | Yes | New password to set |
current_password |
string | No | Current password (required when changing) |
Keys¶
GET /api/v1/keys¶
List all registered keys.
Response:
{
"keys": [
{
"fingerprint": "sha256:...",
"pseudonym": "Alice Scholar",
"algorithm": "ed25519",
"status": "active",
"registered_at": "2026-01-15T10:00:00Z",
"expires_at": null
}
]
}
GET /api/v1/keys/search¶
Search keys by pseudonym.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
pseudonym |
string | Partial pseudonym match (case-insensitive) |
Response: Same format as GET /api/v1/keys.
GET /api/v1/keys/{fingerprint}¶
Get details for a specific key.
Response:
{
"fingerprint": "sha256:...",
"public_key": "-----BEGIN PUBLIC KEY-----\n...",
"pseudonym": "Alice Scholar",
"algorithm": "ed25519",
"status": "active",
"registered_at": "2026-01-15T10:00:00Z",
"expires_at": null,
"log_entry_id": 1
}
GET /api/v1/keys/{fingerprint}/status¶
Quick key validity check (target: less than 500ms).
Response:
POST /api/v1/keys/register¶
Register a new public key on the transparency log.
Request body:
{
"payload": {
"public_key": "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----",
"pseudonym": "Alice Scholar",
"key_algorithm": "ed25519",
"expiration_date": "2027-01-15T00:00:00Z"
}
}
| Field | Type | Required | Description |
|---|---|---|---|
payload.public_key |
string | Yes | PEM-encoded public key |
payload.pseudonym |
string | Yes | Display name for the key holder |
payload.key_algorithm |
string | Yes | "ed25519", "ecdsa-p256", or "rsa-2048" |
payload.expiration_date |
string | No | ISO 8601 expiration date |
Response:
{
"fingerprint": "sha256:...",
"pseudonym": "Alice Scholar",
"algorithm": "ed25519",
"log_entry_id": 1,
"entry_hash": "sha256:..."
}
POST /api/v1/keys/succeed¶
Replace an active key with a new one (key succession).
Request body:
{
"payload": {
"old_fingerprint": "sha256:...",
"new_public_key": "-----BEGIN PUBLIC KEY-----\n...",
"new_algorithm": "ed25519"
},
"auth": {
"challenge_id": "...",
"challenge_signature": "..."
}
}
Accepts either JWT Bearer auth or legacy auth proof. For recovery succession of expired keys, include "recovery": true in the auth object.
Response:
{
"old_fingerprint": "sha256:...",
"new_fingerprint": "sha256:...",
"log_entry_id": 3,
"entry_hash": "sha256:..."
}
POST /api/v1/keys/revoke¶
Revoke an active key.
Request body:
{
"payload": {
"fingerprint": "sha256:..."
},
"auth": {
"challenge_id": "...",
"challenge_signature": "..."
}
}
Response:
Signing¶
POST /api/v1/attestations¶
Submit a client-signed attestation. The private key never leaves the client.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
manifest |
object | Yes | Document manifest with content hash |
public_key_pem |
string | Yes | PEM-encoded public key of the signer |
signature |
string | Yes | Base64-encoded signature of the manifest |
attestation_type |
string | No | "authorship", "editorial_review", "peer_review", "publication" (default: "authorship") |
pseudonym |
string | No | Signer pseudonym (used if key not yet registered) |
intent_statement |
string | No | Free-text statement of signing intent |
password |
string | No | Password if registered for this key |
Response:
{
"attestation": {
"id": "a1b2c3...",
"type": "authorship",
"scope": { "content_hash": "sha256:..." },
"signer_key_fingerprint": "sha256:...",
"signature_algorithm": "ed25519",
"signature": "...",
"timestamp": "2026-01-15T10:30:00Z"
},
"fingerprint": "sha256:...",
"pseudonym": "Alice Scholar",
"log_entry_id": 2
}
Error codes: 422 Invalid public key, attestation type, or manifest; signature verification failed. 403 Password required or invalid.
Verification¶
POST /api/v1/verify¶
Verify a document given its manifest and source hash. Source content is never sent to the server.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
manifest |
object | Yes | The document manifest |
source_hash |
string | Yes | SHA-256 hex hash of the source document |
Response:
{
"layer1": { "status": "valid", "details": "..." },
"layer2": { "status": "valid", "details": "..." },
"overall_status": "valid",
"attestation_graph": { "..." }
}
Error codes: 422 Invalid manifest. 503 Transparency log unreachable.
Transparency Log¶
GET /api/v1/log¶
Paginated log entries with optional filters.
Query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
page |
integer | 1 | Page number (1-indexed) |
per_page |
integer | 50 | Entries per page (max 200) |
event_type |
string | -- | Filter by event type |
search |
string | -- | Full-text search across hashes and fingerprints |
Response:
{
"entries": [
{
"id": 1,
"timestamp": "2026-01-15T10:00:00Z",
"event_type": "key_registration",
"payload": { "..." },
"previous_hash": null,
"entry_hash": "sha256:..."
}
],
"page": 1,
"per_page": 50,
"total": 1
}
GET /api/v1/log/head¶
Get the latest log entry and total count.
Response:
{
"head": {
"id": 42,
"entry_hash": "sha256:...",
"event_type": "attestation",
"timestamp": "2026-01-15T10:30:00Z"
},
"entry_count": 42
}
GET /api/v1/log/{entry_id}¶
Get a single log entry by ID.
Response: Same format as entries in GET /api/v1/log.
Error codes: 404 Entry not found.
GET /api/v1/log/by-fingerprint/{fingerprint}¶
Get all log entries referencing a specific fingerprint.
Response:
GET /api/v1/log/tree-head¶
Get a signed Merkle tree head for third-party audit.
Response:
{
"tree_size": 42,
"root_hash": "sha256:...",
"signature": "...",
"timestamp": "2026-01-15T10:30:00Z"
}
GET /api/v1/log/audit-trail¶
Query audit trail with combinable filters.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
fingerprint |
string | Filter by key fingerprint |
document_hash |
string | Filter by document or manifest hash |
start_date |
string | ISO 8601 start date |
end_date |
string | ISO 8601 end date |
At least one parameter is required.
Response: Same format as GET /api/v1/log.
POST /api/v1/log/entries¶
Submit a new event to the transparency log.
Request body:
Response:
{
"id": 43,
"entry_hash": "sha256:...",
"event_type": "key_registration",
"timestamp": "2026-01-15T10:35:00Z"
}
POST /api/v1/log/verify¶
Verify the integrity of the entire hash chain.
Response:
POST /api/v1/log/anchor¶
Anchor the latest log head via OpenTimestamps.
Response:
Endorsements¶
POST /api/v1/endorsements/offer¶
Offer an endorsement to another key holder.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
endorser_fingerprint |
string | Yes | Fingerprint of the endorsing key |
endorsed_fingerprint |
string | Yes | Fingerprint of the key being endorsed |
category |
string | Yes | "x-diogenes:human_attestation" or "x-diogenes:institutional_endorsement" |
valid_until |
string | No | Expiry date (ISO 8601) |
institutional_metadata |
object | No | Metadata for institutional endorsements |
external_identifiers |
array | No | External identity links |
auth |
object | Yes | Auth proof (challenge_id + challenge_signature) |
Response: Log entry for the endorsement offer event.
POST /api/v1/endorsements/accept¶
Accept a pending endorsement offer.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
offer_entry_id |
integer | Yes | Log entry ID of the endorsement offer |
endorsed_fingerprint |
string | Yes | Fingerprint of the endorsed key |
auth |
object | Yes | Auth proof for the endorsed key |
POST /api/v1/endorsements/withdraw¶
Withdraw an endorsement (endorser action).
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
endorser_fingerprint |
string | Yes | Endorser's fingerprint |
endorsed_fingerprint |
string | Yes | Endorsed key's fingerprint |
original_offer_entry_id |
integer | Yes | Original offer log entry ID |
note |
string | Yes | Reason for withdrawal |
auth |
object | Yes | Auth proof for the endorser |
POST /api/v1/endorsements/revoke-acceptance¶
Revoke acceptance of an endorsement (endorsed party action).
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
endorsed_fingerprint |
string | Yes | Endorsed key's fingerprint |
original_offer_entry_id |
integer | Yes | Original offer log entry ID |
note |
string | Yes | Reason for revocation |
auth |
object | Yes | Auth proof for the endorsed key |
GET /api/v1/endorsements/{fingerprint}¶
Get endorsements received by a key.
GET /api/v1/endorsements/{fingerprint}/issued¶
Get endorsements issued by a key.
GET /api/v1/endorsements/{fingerprint}/status¶
Get endorsement status summary for a key.
POST /api/v1/endorsements/revocation-alert¶
Publish an endorser revocation alert.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
endorser_fingerprint |
string | Yes | Alerting endorser's fingerprint |
compromised_fingerprint |
string | Yes | Compromised key's fingerprint |
reason |
string | Yes | Alert reason (max 1000 chars) |
evidence |
string | No | Supporting evidence (max 5000 chars) |
auth |
object | Yes | Auth proof for the endorser |
GET /api/v1/endorsements/revocation-alerts/{fingerprint}¶
Get revocation alerts for a key.
Graph Traversal¶
GET /api/v1/graph/{fingerprint}¶
Depth-limited BFS traversal of the endorsement graph.
Query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
max_depth |
integer | 3 | Maximum traversal depth |
type |
string | -- | Filter by endorsement type |
status |
string | -- | Filter by endorsement status |
institution |
string | -- | Filter by institution |
since |
string | -- | Only endorsements after this date |
until |
string | -- | Only endorsements before this date |
Results are cached (default TTL: 60 seconds) and subject to a configurable timeout (default: 10 seconds).
Trust Configurations¶
POST /api/v1/trust-configs¶
Create a trust configuration for a key.
GET /api/v1/trust-configs¶
List trust configurations.
GET /api/v1/trust-configs/{fingerprint}¶
Get trust configuration for a specific key.
POST /api/v1/trust-configs/revoke¶
Revoke a trust configuration.
Encrypted Claims¶
POST /api/v1/claims¶
Post an encrypted claim to the transparency log.
Response:
GET /api/v1/claims¶
List encrypted claims. Requires authentication.
GET /api/v1/claims/{entry_id}¶
Get a specific encrypted claim. Requires authentication.
POST /api/v1/claims/{entry_id}/reveal¶
Reveal an encrypted claim by providing the plaintext.
Request body:
Response:
Composite Documents¶
POST /api/v1/composite/assemble¶
Assemble a composite document from multiple parts.
POST /api/v1/composite/compile¶
Compile a composite document into a single manifest.
Audit Export¶
GET /api/v1/audit/export¶
Export audit trail in JSON or CSV format with combinable filters.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
format |
string | "json" or "csv" |
scope |
string | Filter scope |
fingerprint |
string | Filter by fingerprint |
document_hash |
string | Filter by document hash |
start_date |
string | ISO 8601 start date |
end_date |
string | ISO 8601 end date |
page |
integer | Page number |
page_size |
integer | Page size (max 1000, total max 10000) |
Webhooks¶
POST /api/v1/webhooks¶
Register a webhook for event notifications.
GET /api/v1/webhooks¶
List registered webhooks.
DELETE /api/v1/webhooks/{webhook_id}¶
Delete a webhook.
Identifier Types¶
GET /api/v1/identifier-types¶
List supported external identifier types.
Rate Limits¶
The API enforces the following rate limits:
| Resource | Default Limit |
|---|---|
| General API queries | 60 requests/minute |
| Key registrations | 10/hour |
| Endorsement offers | 50/day |
| Attestation events | 100/hour |
Rate limit headers are included in all responses.