API reference
Read API for scripts. Host api.meetpraxis.io, every route under /v1. Create a token on the app under API tokens: it starts with prx_, is shown once, and reads your organization only.
curl -H "Authorization: Bearer prx_..." https://api.meetpraxis.io/v1/posture
Responses are JSON with Cache-Control: no-store; times are RFC 3339 UTC. limit defaults to 50 and is clamped to 200; next_cursor is opaque and null on the last page. A token for an organization whose period has ended gets 403 subscription_inactive.
Routes
| Method | Path | Returns | Auth |
|---|---|---|---|
| GET | /v1/posture | organization totals, per account, per framework, each with pass, fail, not_evaluated, not_applicable and last_evaluated_at (FR-018) | token |
| GET | /v1/posture/accounts/{aws_account_id} | counts per control for one account | token, account must belong to org |
| GET | /v1/posture/frameworks/{framework_id} | counts per clause for one framework | token |
| GET | /v1/findings?control=&account=&state=&cursor=&limit= | stored findings, paginated | token |
| GET | /v1/findings/{id} | one finding with every FR-013 field | token, finding must belong to org |
| GET | /v1/controls/{control_id} | published control, FR-013 fields plus mappings with review_state and settings (below) | token |
| GET | /v1/exports | exports of this org, newest first | token |
| POST | /v1/exports | body {"framework": "pci-dss-4-0"}; builds the pack (research R12); 201 with the export row | token, rate-limited 10 per hour per org |
| GET | /v1/exports/{id}/download | 302 to a signed R2 URL valid 10 minutes | token, export must belong to org |
States
state is one of pass, fail, not_evaluated, not_applicable. A control marked not applicable is reported as not_applicable in posture and its findings are not returned by /v1/findings. GET /v1/controls/{control_id} carries settings: the organization-wide state, per-account states and the full change history.
Errors
| Status | Body | When |
|---|---|---|
| 401 | {"error":"unauthorized"} | header missing, malformed, unknown hash, or revoked |
| 403 | {"error":"subscription_inactive"} | token valid, organization not active (FR-005, FR-022) |
| 403 | {"error":"forbidden"} | id is well formed but the object is outside the token's organization (FR-023). RLS means the row was never read; the status only tells the caller the id shape was valid |
| 404 | {"error":"not_found"} | unknown route, id, control, or framework |
| 422 | {"error":"invalid","fields":["state","limit"]} | query or body field fails validation; lists field names |
| 429 | {"error":"rate_limited"} | 600 requests per minute per token, 10 exports per hour per org |