The dead-letter queue is an operations surface: listing can span tenants, but everything requires the {orgId}:admin:ledger permission — the list only shows tenants you hold admin:ledger for, and reading, reprocessing or discarding a record requires admin:ledger on that record’s tenant. Operations against another tenant’s records answer 403 FORBIDDEN.

List failed events

  GET /ledger/v1/failed-events
  
ParameterNotes
tenantIdFilter by tenant (requires read access to it)
eventTypeFilter by event type
reprocessedtrue/false — filter by reprocessing state

200 response:

  [
  {
    "id": "d1a2…", "eventId": "9c2e…", "tenantId": "org-84120557",
    "eventType": "SalesInvoice",
    "failureReason": "Ontology validation failed: missing required property …",
    "retryCount": 3,
    "failedAt": "2026-07-01T09:20:11.007Z"
  }
]
  

Get one failed event

  GET /ledger/v1/failed-events/{id}
  

200 with the record, or 404:

  { "error": "NOT_FOUND", "message": "Failed event not found: d1a2…", "timestamp": "…" }
  

Reprocess

  POST /ledger/v1/failed-events/{id}/reprocess
  

Queues the event for another processing attempt. Returns 202:

  { "id": "d1a2…", "message": "Event accepted for reprocessing" }
  

Discard

  DELETE /ledger/v1/failed-events/{id}
  

Returns 204 No Content, or 404 if the record does not exist. Like reprocessing, discarding requires write access to the record’s tenant.