API reference

Two customer-facing endpoints (OTLP ingest + receipt creation), one public auditor-facing endpoint (verify URL), plus the dashboard's REST surface for building integrations against your own data.

Authentication

Customer-facing endpoints use the X-Marturia-Key header. Mint a key in the dashboard's Keys page. Only the SHA-256 hash is stored; you'll see the plaintext exactly once at creation time.

Dashboard endpoints (under /api/marturia/projects/...) use JWT bearer tokens issued by the login flow.

Customer endpoints

POST /api/marturia/v1/traces

OTLP/HTTP trace ingest. Standard OTel protocol.

HeaderValue
X-Marturia-Keyrequired
Content-Typeapplication/x-protobuf or application/json

Returns 200 OK with empty body on success. 413 if body > 5 MB. 429 if monthly quota exceeded.

POST /api/marturia/v1/receipts

Create a signed cryptographic receipt.

Body

{
  "agent_name": "string, 1-80 chars, required",
  "payload":    "any JSON object, max 64KB canonical, required",
  "agent_run_id": "optional string, your stable run identifier"
}

Response 200

{
  "id": 98,
  "tenant_id": 2,
  "project_id": 70,
  "receipt_seq": 54,
  "signing_kid": "t2-v1",
  "receipt_hash": "803e993d40fa...",
  "agent_name": "purchase_approver",
  "agent_run_id": "run_demo_001",
  "verify_url": "https://marturia.dev/v1/verify/2/98"
}

Errors

StatusCause
400Missing or invalid agent_name / payload; payload > 64 KB.
401Missing or invalid X-Marturia-Key.
429Rate limit (60/min/project) exceeded.

Public verifier

GET /v1/verify/{tenant_id}/{receipt_id}

No auth. Returns the full receipt JSON for offline verification. Use this URL when sharing receipts with auditors or customers.

Response 200

{
  "tenant_id": 2,
  "receipt_seq": 54,
  "agent_name": "purchase_approver",
  "agent_run_id": "run_demo_001",
  "created_at": "2026-05-09T18:42:11.337Z",
  "signing_kid": "t2-v1",
  "receipt_hash": "803e993d40fa...",
  "prev_hash": "a609ed8ce163...",
  "signature": "5fd2e0a14a6d...",
  "public_key": "9fc982fe3474...",
  "payload_canonical_bytes": "<base64>"
}

Dashboard endpoints

JWT auth. The dashboard SPA uses these; you can hit them too if you're building integrations off your own data.

GET /api/marturia/projects

List your tenant's projects.

GET /api/marturia/projects/{id}/spans

List spans for a project. Query params:

ParamDefaultNotes
hours24Lookback window. Max 720 (30d).
status(any)OK, ERROR, or UNSET.
service(any)Filter to one service.name.
qFree-text match against name/attributes.
trace_idPin to a single trace.
beforeCursor for pagination — pass the previous page's last start_time.
limit200Max 1000.

GET /api/marturia/projects/{id}/traces/{trace_id}

All spans for a single trace, ordered by start time, with parent linkage.

GET /api/marturia/projects/{id}/aggregations

Dashboard tile data — totals, percentiles, timeline, services, models, slowest spans. Same hours param as /spans.

GET /api/marturia/projects/{id}/receipts

List receipts for the tenant (the chain is tenant-scoped, surfaced on every project for convenience). Query: limit (default 100, max 1000).

GET /api/marturia/projects/{id}/receipts/{receipt_id}

Full receipt detail in the same shape as the public verifier.

GET /api/marturia/projects/{id}/receipts/{receipt_id}/export

Download the receipt as a JSON bundle (Content-Disposition: attachment).

Rate limits + quotas

EndpointLimit
POST /tracesProject span quota (Free 100K/mo, Pro 1M, Team 10M, Audit 100M)
POST /receipts60 requests / minute / project
GET /v1/verify120 requests / minute / IP
Dashboard endpoints600 requests / minute / user

Errors

All endpoints return JSON errors in the form:

{ "detail": "human-readable message" }

Status codes follow REST conventions. 500 is reserved for server bugs and triggers an internal alert; if you see one, please tell us.