Skip to main content

Compliance Reports API

One API produces a formatted, regulator-appropriate artifact from the governance data AxonFlow already holds. You choose a regulator, a framework and a reporting period; AxonFlow renders a real PDF, CSV, XLSX or JSON file, stores it, and hands you a time-limited download link.

Before this API, every "export" on the platform was raw JSON. This one produces the document you attach to a submission.

:::tip Looking for the Customer Portal walkthrough? This page is the API reference. If you want to select a jurisdiction, read your live posture, and generate a report from the Customer Portal UI, see Compliance Reports (Customer Portal). :::

:::info Enterprise feature Report generation requires an Evaluation or Enterprise licence. On the Community edition the routes are not registered. See Community vs Enterprise. :::

Quickstart

Three calls: create, poll, download.

# 1. Create. Returns 202 immediately with a job id.
curl -sS -X POST "$AXONFLOW_URL/api/v1/compliance/reports" \
-H "Content-Type: application/json" \
-d '{
"regulator": "euaiact",
"framework": "EU_AI_ACT",
"format": "pdf",
"period_start": "2026-04-01T00:00:00Z",
"period_end": "2026-06-30T23:59:59Z"
}'
# {"id":"creport-9f3c...","status":"pending","report_state":"","progress":0, ...}

# 2. Poll until status is `completed` or `failed`.
curl -sS "$AXONFLOW_URL/api/v1/compliance/reports/creport-9f3c..."
# {"id":"creport-9f3c...","status":"completed","report_state":"populated",
# "progress":100,"record_count":184,"checksum":"3b1f...","size_bytes":58213, ...}

# 3. Download. Responds 307 to a presigned URL valid for one hour.
curl -sSL -o eu-ai-act-q2.pdf \
"$AXONFLOW_URL/api/v1/compliance/reports/creport-9f3c.../download"

Requests are scoped by the X-Org-ID and X-Tenant-ID headers, which the AxonFlow Agent gateway and the customer portal proxy set from your validated credential. You never send them by hand from an application.

The three endpoints

MethodPathSuccessPurpose
POST/api/v1/compliance/reports202 AcceptedCreate a report job
GET/api/v1/compliance/reports/{id}200 OKPoll job status
GET/api/v1/compliance/reports/{id}/download307 Temporary RedirectPresigned artifact URL (1 hour)

Generation is asynchronous because a multi-year OJK report over a busy tenant is not a request-timeout-sized amount of work. The create call returns as soon as the job is durably recorded.

Statuses

statusMeaning
pendingRecorded, not started
processingCollecting data and rendering
completedArtifact stored and checksummed - downloadable
failedTerminal failure; error names the cause

A job reaches completed only when a checksummed artifact is durably stored. If no artifact storage backend is configured, the job fails with an error naming the missing configuration rather than reporting success you cannot download.

report_state: the three-state answer

Every create and poll response carries an explicit report_state. It exists because an empty report is ambiguous, and the two readings need different responses from you:

report_stateMeaningWhat to do
not_availableThe regulator's module is not enabled in this deploymentEnable the module, or pick a different regulator
enabled_emptyThe module is enabled and the period genuinely contains no governed activityNothing - this is a valid "no activity in range" attestation
populatedThe module is enabled and returned dataNothing
(empty string)Not determined yetThe job is still pending or processing. Poll again.

The field is always present on every create and poll response, including while it is the empty string. You never have to tell "absent" from "null" to work out what happened.

not_available is also returned synchronously: creating a report for a regulator whose module is not enabled is refused with 409 Conflict and {"error_code":"REGULATOR_NOT_AVAILABLE","report_state":"not_available"} rather than producing a job that can never succeed.

Regulators, frameworks and formats

RegulatorregulatorframeworkFormatsRetention shown on the artifact
EU AI ActeuaiactEU_AI_ACTpdf, csv, jsonLogs at least 6 months (Art. 12/19); technical documentation 10 years (Art. 18)
SEBI (India)sebiSEBI_AI_MLpdf, csv, xlsx, json5 years
RBI FREE-AI (India)rbiRBI_FREE_AIpdf, csv, xlsx, jsonPer the FREE-AI framework and the board-approved policy
MAS FEAT (Singapore)masfeatMAS_FEATpdf, csv, json7 years
OJK / BI / UU PDP (Indonesia)ojkOJK_AI_GOVERNANCE, UU_PDP, BI_PJP, OJK_BI_COMBINEDpdf, csv, json5 years

framework may be omitted for the four regulators that define exactly one. It is required for ojk, which reports against three different Indonesian instruments - selecting one for you would file the report under the wrong law.

XLSX is offered only where the regulator's own submission practice is spreadsheet-shaped. Requesting a format a regulator does not offer is a 400 with UNSUPPORTED_FORMAT and the supported list in the message.

What each report contains

RegulatorSections
EU AI ActConformity assessments (Art. 43), Article 43 summary, risk management (Arts. 9-17), accuracy and bias monitoring (Art. 15), human oversight (Art. 14), audit trail (Art. 12)
SEBIReadiness checks, policy violations, LLM activity, decision-chain lineage, human oversight, PII redactions, retention posture
RBI FREE-AIBoard reports, AI incidents, kill switches, kill-switch activation history, model validations, AI system registry
MAS FEATFEAT assessments, four-pillar summary, AI system registry, kill-switch history
OJK / BI / UU PDPAI governance summary, policy violations, LLM and decision activity, human oversight, PII redactions, cross-border transfers (UU PDP Pasal 56), 72-hour breach log (Art. 46), BI PJP, retention posture

Sections are always emitted, even when empty, carrying a sentence saying so. A dropped section would make "we recorded no HITL oversight" indistinguishable from "this report does not cover HITL oversight", which on a regulatory artifact is a different claim.

Access control

Two different authorities, deliberately:

ActionRequired
Poll report statusaudit:read - any caller who may read the audit trail
Create a reportAdministrator (owner, admin or policy admin)
Download an artifactAdministrator

Generating and downloading produce a whole-tenant compliance artifact, so they sit in the same authority class as evidence export. Polling returns job metadata only - id, status, progress, report_state, checksum - and no audit content, so a compliance viewer can watch a report they requested reach completion.

Every by-id path is scoped to the caller's own organization and tenant. A report id belonging to another tenancy returns 404, byte-identical to an unknown id, so the endpoint cannot be used to discover which report ids exist.

Errors

HTTPerror_codeCause
400UNKNOWN_REGULATORregulator is not one of the five
400UNKNOWN_FRAMEWORKFramework missing for ojk, or not defined for the regulator
400UNSUPPORTED_FORMATFormat unknown, or not offered for that regulator
400INVALID_PERIODMissing, inverted, zero-length, or longer than 1096 days
400INVALID_BODYMalformed JSON, or an unrecognised field
401SCOPE_REQUIREDNo X-Org-ID / X-Tenant-ID - the request did not traverse an authenticating hop
403COMPLIANCE_REPORT_REQUIRES_EVALUATION_LICENSECommunity tier
404REPORT_NOT_FOUNDNo such report in your tenancy
409REGULATOR_NOT_AVAILABLEThat regulator's module is not enabled here
409REPORT_NOT_COMPLETEDDownload requested before the job finished; the message carries the failure cause when it failed
409REPORT_ARTIFACT_UNAVAILABLEThe job completed but its stored artifact is no longer retrievable
429COMPLIANCE_REPORT_LIMIT_EXCEEDEDDaily report budget for your tier
503INTERNAL_ERRORThe service has no database connection

Reports share the daily budget of the evidence-export tier: 3 per day on Evaluation, unlimited on Enterprise. A refused request - a malformed body, a tier refusal, an unavailable regulator - does not consume a slot.

Artifacts

Artifacts are stored in the object-storage backend the orchestrator is configured with (AUDIT_EXPORT_STORAGE_TYPE and its bucket/credential variables) under compliance-reports/{org}/{regulator}/{report-id}.{ext}. The download endpoint mints a presigned URL valid for one hour; the orchestrator never streams the bytes itself.

Each job records the SHA-256 of the artifact. Rendering is deterministic: the same job rendered twice produces byte-identical output, including the PDF's creation date, which is taken from the job record rather than the render clock. That is what makes the stored checksum a durable integrity claim rather than a one-time snapshot.

Known limitations

  • PDF glyph coverage. PDFs use the standard 14 core fonts so nothing is embedded and an air-gapped build produces the same bytes as any other. Those fonts are cp1252-encoded, so a character outside that set - Devanagari, Han, an emoji - renders as ?. Request json or csv when the data contains them; both carry full Unicode.
  • Row cap. Any single section is capped at 5,000 rows. When a section is truncated it says so, with the number of rows not shown. Narrow the reporting period for the full set.
  • BI PJP. Selecting BI_PJP or OJK_BI_COMBINED scopes the export, but the Bank Indonesia framework contributes no payment-service-specific data class of its own yet. The report says so in that section rather than showing it empty.
  • Legacy per-module exports. The older per-regulator export endpoints remain available and unchanged, with two corrections: SEBI's CSV export now returns real CSV, and its XML format returns 501 Not Implemented instead of JSON under an XML content type. RBI's PDF and XLSX exports are now real PDF and real XLSX. New integrations should use this API.