Skip to content

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:

{
  "status": "ok",
  "version": "0.1.0"
}

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:

{
  "fingerprint": "sha256:...",
  "status": "active",
  "expires_at": null
}

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:

{
  "fingerprint": "sha256:...",
  "status": "revoked",
  "log_entry_id": 4,
  "entry_hash": "sha256:..."
}

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:

{
  "entries": [ "..." ]
}

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:

{
  "event_type": "key_registration",
  "payload": { "..." }
}

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:

{
  "valid": true,
  "entry_count": 42,
  "errors": []
}

POST /api/v1/log/anchor

Anchor the latest log head via OpenTimestamps.

Response:

{
  "anchored_entry_id": 42,
  "entry_hash": "sha256:...",
  "ots_proof": "base64-encoded-proof..."
}

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:

{
  "entry_id": 1,
  "commitment": "sha256:..."
}

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:

{
  "plaintext": { "key": "value" }
}

Response:

{
  "valid": true
}

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.