Documentation
Audit log
Every administrative change in your INFRO organization, recorded: the event catalog, GET /v1/org/audit filters, 12-month retention, and CSV export.
Every administrative action in your organization — an invite sent, a role changed, a key revoked, a spend limit edited — is recorded as an audit event. The log is append-only: events cannot be edited or deleted through any API or console surface, so it answers "who changed what, and when" with evidence rather than recollection.
The log covers administration, not traffic. It is readable by owners and admins only, retained for 12 months, queryable with GET /v1/org/audit, and exportable to CSV via the exports API.
What gets recorded
Nine event types. Each fires regardless of where the action originated — console, API, or SCIM provisioning — so the log has no blind spots between surfaces.
| Event | What fires it |
|---|---|
member.invited | An invite is sent from the console or via POST /v1/org/invites. The event fires when the invite is sent, not when it is accepted — acceptance sets the member's joined_at field, covered in Members & roles. |
member.removed | A member is removed via DELETE /v1/org/members/{id}, the console, or SCIM deprovisioning. |
member.role_changed | A role changes via PATCH /v1/org/members/{id}, the console, or IdP group mapping through SSO & SCIM. |
key.created | An API key is created in the console — see Authentication. |
key.rotated | A key is rotated in the console: the secret is replaced in one step and the old secret stops working. A manual create-then-revoke rotation fires key.created and key.revoked instead. |
key.revoked | A key is revoked in the console. |
policy.updated | A spend limit, model allowlist, or EU routing-zone pin changes at any scope — org, project, member, or key. |
project.created | A project is created in the console. |
export.created | An export job is started via POST /v1/exports or the console — see Exports. |
API traffic is not audited here — inference requests are recorded per request in the request log and aggregated in analytics. The audit log is only for actions that change your organization.
Event shape
Every event has the same six fields. detail is the only event-specific part.
{
"id": "audit_9f4kq2vx",
"event": "member.role_changed",
"actor": {
"type": "member",
"id": "mem_c81af3",
"email": "dana@acme.dev"
},
"target": {
"type": "member",
"id": "mem_7bq2e9",
"label": "sam@acme.dev"
},
"timestamp": "2026-08-21T14:03:22Z",
"detail": {
"from": "developer",
"to": "admin"
}
}idstring- Unique event id, stable across reads. Deduplicate on it if you poll the log into your own SIEM.
eventstring- One of the nine names in the catalog above. New event types may be added over time — skip unknown names rather than erroring on them.
actorobject- Who performed the action.
typeismember(with the member'sidandemail) orscimfor changes driven by your identity provider, whereemailisnull— see SSO & SCIM. targetobject- What was acted on:
type(member,key,project,org, orexport), itsid, and a human-readablelabel— the member's email, the key's label, the project's name. timestampstring- When the action happened. ISO 8601, always UTC.
detailobject | null- Event-specific fields:
member.invitedcarriesemailandrole;member.role_changedcarriesfromandto;policy.updatedcarries the policy name, scope, and new value.nullwhen there is nothing to add.
Key events reference keys by id and label only — the secret itself never appears in the log, in detail, or in exports.
Querying the log
GET /v1/org/audit returns events newest first, cursor-paginated. All filters combine with AND.
eventstring- Filter to one event name from the catalog, e.g.
key.revoked. Omit for all events. actorstring- A member id (
mem_...) to return only that member's actions, or the literalscimfor provisioning-driven events. fromstring- Inclusive lower bound on
timestamp, ISO 8601 UTC. Defaults to the start of the 12-month retention window. tostring- Exclusive upper bound on
timestamp, ISO 8601 UTC. Defaults to now. cursorstring- The
next_cursorfrom the previous page. Keep the other filters identical between pages. limitinteger- Events per page. Default 25, maximum 100.
curl "https://api.infro.io/v1/org/audit?event=key.revoked&from=2026-08-01T00:00:00Z&limit=50" \
-H "Authorization: Bearer $INFRO_API_KEY"{
"data": [
{
"id": "audit_8xw3n1pd",
"event": "key.revoked",
"actor": { "type": "member", "id": "mem_c81af3", "email": "dana@acme.dev" },
"target": { "type": "key", "id": "key_hj2m8s", "label": "staging-worker" },
"timestamp": "2026-08-21T13:58:47Z",
"detail": null
}
],
"has_more": true,
"next_cursor": "YXVkaXRfOHh3M24xcGQ="
}has_more is false and next_cursor null on the last page. Cursors are opaque — don't parse them, and don't reuse one after changing filters.
Who can read it
Only owners and admins can read the audit log — in the console and via GET /v1/org/audit. A key belonging to a developer or analyst gets 403 with type permission_denied in the standard error envelope. Analysts can see dashboards, usage, and most exports, but not the audit log or audit exports — the log records who holds power in the org, which is itself sensitive. Roles are covered in Members & roles.
Retention and export
Events are retained for 12 months on a rolling basis; older events are permanently deleted. If your compliance program needs a longer horizon, export on a schedule — a quarterly export of the previous quarter is the usual cadence.
curl https://api.infro.io/v1/exports \
-H "Authorization: Bearer $INFRO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"kind": "audit",
"from": "2026-01-01T00:00:00Z",
"to": "2026-07-01T00:00:00Z"
}'This returns an async job in the same envelope as every async job; when it completes, the job yields a signed, expiring CSV URL. Creating a kind: "audit" export requires the owner or admin role, and the export itself fires an export.created event — the log records its own extraction. The full job lifecycle and CSV columns are on the Exports page.
Why it matters for compliance
Access reviews and audits keep asking the same questions: who could create keys, who changed that spend policy, when did the contractor's access end. The audit log answers them from records rather than memory:
- SOC 2 / ISO 27001 evidence. Auditors ask for proof of access provisioning, deprovisioning, and change management.
member.*,key.*, andpolicy.updatedevents, exported to CSV, are that proof — INFRO's own certifications are listed on /security. - Incident response. A leaked key's story is reconstructable:
key.createdshows who minted it and when,key.revokedshows how fast you responded. - EU AI Act and GDPR reviews. Regulators expect you to show governance over the systems that process data — who could change routing zones, retention behavior, and model access.
policy.updatedevents document exactly that, alongside the request-level records described in EU compliance. - SCIM verification. Events with actor
scimlet you confirm the IdP is actually deprovisioning people — every offboarding should have a matchingmember.removed. See SSO & SCIM.
For live monitoring rather than retrospective review — spend spikes, error rates, latency — use alerts and analytics; the audit log is the record of how the organization itself changed.