A verifiable, immutable record of who did what in your account, and from where.
Audit logs give your team a tamper-proof record of the sensitive actions taken in your account — keys created and revoked, domains and inboxes added or deleted, webhooks changed. Each event captures what happened, who did it, and where it came from, so you can answer a compliance or incident question after the fact with a real answer.
Read the trail
Fetch events from GET /v1/audit-logs, newest first. The call needs the
account:read scope. The trail spans every inbox of the
organization, so a key restricted to specific inboxes
gets a 403. Events come back in the standard list envelope under data,
paginated with a cursor.
A page is the standard list envelope — data holds the events and pagination
carries the cursor for the next page:
Event fields
| Field | Meaning |
|---|---|
action | The audited action, e.g. api_key.created, domain.deleted, webhook.created. |
resourceType | The kind of resource the action targeted, e.g. api_key, domain, inbox, webhook. May be null. |
resourceId | Identifier of the affected resource, when one applies. |
metadata | Action-specific context recorded with the event. May be null. |
actor | Who performed the action — an API key (by id), dashboard for console actions, or a system actor. May be null. |
ip | Source IP the request came from, when captured. |
createdAt | When the event was recorded, in UTC. |
metadata holds action-specific context — some actions record a field or two and
others record none. An inbox.created event records the new inbox's address,
for example, while an api_key.created event records an empty object. Treat it as
free-form context, not a fixed schema.
Actions you'll see
The trail records security-relevant actions. The most common, grouped by what they target:
resourceType | Actions |
|---|---|
api_key | api_key.created, api_key.revoked |
domain | domain.created, domain.deleted |
inbox | inbox.created, inbox.deleted |
webhook | webhook.created, webhook.deleted |
audience | audience.created, audience.deleted, audience.sent |
The set of audited actions grows over time. Don't hard-code an exhaustive list:
match on the prefix (api_key., domain.) or read resourceType, and tolerate
actions you don't recognize yet.
Page through history
Pass limit (1–100, default 25) and follow pagination.nextCursor the usual way —
see pagination. The trail is account-wide and newest-first.
Add action to return only one exact action, such as ?action=api_key.created
(dotted lowercase, up to 64 characters; anything else is a 400); filter by
resourceType on each page in your own code.
Audit events are append-only — there's no endpoint to edit or delete them, and that immutability is the point. For long-term retention under your own control, schedule a signed export to your own archive.
API-key IP allowlisting
For high-trust automation, you can lock an API key to a set of trusted IP addresses, so a leaked secret is useless from anywhere else. It's a governance control that sits on top of scopes: scopes limit what a key can do; the allowlist limits where it can do it from.
Set an allowlist
Send allowedIps when you create a key. Each entry is an IPv4 or IPv6 address, or
a CIDR range — up to 50 of them.
The created key — and the key returned by the list endpoint — echoes its
allowedIps. A key with no allowlist returns an empty allowedIps array ([])
and authenticates from any IP, which is the default.
See where a key is locked to
The allowlist shows up wherever a key's details appear, so you can audit it
without re-creating the key. List your keys to see every key's allowedIps and
confirm each one is pinned to the IPs you expect.
How enforcement works
On every authenticated request, Dairo resolves the caller's source IP and checks it against the key's allowlist before the request does any work:
Resolve the source IP
The trusted client IP is the real connecting address, never a header the caller supplies — so it can't be spoofed.
Match against the allowlist
The IP must fall inside at least one configured address or CIDR range.
Allow or deny (deny-by-default)
A match proceeds. Anything else — an IP that can't be matched, or can't be
resolved at all — is rejected with 403, even when the bearer secret and scopes
are otherwise valid. A correct secret from an untrusted network gets you nothing.
Operating notes
Omitting allowedIps keeps the default: the key authenticates from any IP.
Allowlisting is strictly opt-in.
Allowlist the stable egress IPs of your servers, CI, or NAT gateway — not laptops on dynamic residential or café networks, which will lock themselves out when the IP rotates.
Creating or revoking an allowlisted key is recorded in the audit trail, so the control itself leaves a record.
If your egress IP changes and a key can no longer reach the API, create a replacement key (with the new range) from a trusted network and revoke the old one. Dairo never weakens the check to recover access.