API referenceCompliance

Export the tamper-evident hash-chained audit ledger

Returns the caller's audit-log rows in ascending chainSeq order — each row carrying a prevHash and rowHash that link it to the one before — together with an EdDSA-signed manifest committing to the window bounds, rowCount, and head rowHash.

Endpoint
GET https://api.dairo.app/v1/audit-logs/export

Returns the caller's audit-log rows in ascending chainSeq order — each row carrying a prevHash and rowHash that link it to the one before — together with an EdDSA-signed manifest committing to the window bounds, rowCount, and head rowHash. An auditor verifies the manifest against Dairo's published JWKS, then re-derives every rowHash from the rows and confirms the head, detecting any inserted, deleted, or edited row without trusting the response. With neither from nor to set the export defaults to the last 30 days rather than the full history, to avoid accidental over-disclosure; supplying either bound (both are inclusive RFC3339 timestamps on each row's time) requests an explicit, full-history-capable window. A single page holds at most 1000 rows: when more remain, pagination.nextCursor returns this page's head chainSeq — pass it back as ?after=<cursor> to drain the next page, and each page's manifest independently commits to that page's exact window. format is reserved (only JSON is emitted today), and the endpoint is rate-limited to 10 requests per minute per user. The manifest is always signed — if Dairo cannot sign it the call fails with a 500 instead of returning an unsigned export. Requires the account:read scope; a key restricted to specific inboxes is refused with a 403, because the trail spans every inbox.

Scope: account:read. Send the API key as a bearer token; Scopes lists what each one reaches.

Request

cURL
curl "https://api.dairo.app/v1/audit-logs/export" \
  -H "Authorization: Bearer $DAIRO_API_KEY"

Query parameters

NameTypeRequiredDescription
fromstring (date-time)noLower bound (inclusive) RFC3339 timestamp on created_at.
tostring (date-time)noUpper bound (inclusive) RFC3339 timestamp on created_at.
afterinteger (int64)noKeyset cursor: the prior page's pagination.nextCursor (a chainSeq). Returns rows with a strictly greater chainSeq, draining history past the 5000-row page cap.
format"json", "ndjson"noReserved; only the JSON form is emitted in V1 (NDJSON streaming is a fast-follow).

Response

200 Success. Body: application/json, AuditExportResponse.

FieldTypeRequiredDescription
rowsarray of AuditExportRowyes
manifestAuditExportManifestyes
paginationobjectnoKeyset pagination for draining history past the 5000-row page cap.
200
{
  "rows": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "userId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "action": "string",
      "resourceType": null,
      "resourceId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "metadata": {},
      "actor": null,
      "ip": null,
      "agentId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "chainSeq": 0,
      "prevHash": "string",
      "rowHash": "string",
      "createdAt": "2026-10-19T09:30:00Z"
    }
  ],
  "manifest": {
    "alg": null,
    "kid": null,
    "signature": null,
    "type": "dairo.audit.manifest.v1",
    "issuer": "string",
    "userId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "region": "string",
    "fromChainSeq": null,
    "toChainSeq": null,
    "rowCount": 0,
    "headRowHash": "string",
    "headChainSeq": null,
    "exportedAt": "2026-10-19T09:30:00Z"
  },
  "pagination": {
    "nextCursor": null
  }
}

Errors

Every error has the same body, {"error": {"type", "code", "message", "param"}}; branch on code. Errors lists every code.

StatusMeaning
400The request is malformed or a value is invalid (invalid_request, invalid_domain, idempotency_key_mismatch).
401The API key is missing or invalid.
403The key lacks the scope this endpoint needs (scope_missing) or may not do this (not_permitted).
404No such resource in this account (resource_not_found).
422The request is well-formed but a field failed validation (validation_failed).
429Rate limit, plan limit, budget or spend cap reached (rate_limited, plan_limit_reached, budget_exceeded, spend_cap_reached).
500An unexpected error; retry with backoff, then contact support (internal_error).

On this page