Audit log
For developers
Every change to an organisation’s data is an audit entry. Entries are numbered within the organisation’s chain and each carries the hash of the entry before it and a hash of its own content, so a gap or an altered entry is detectable. This page covers the shapes a developer meets: the streamed entry, the export file, and the public key.
The entry
Section titled “The entry”Streams and exports carry the same JSON shape.
{ "seq": 4821, "id": "2f3c9a44-3b1e-4a4f-9e52-7f1d6f1a2c0b", "at": "2026-11-03T02:14:09.311Z", "organisationId": "7e0d9c3a-2d8b-4e57-8f43-5c3a1b2d9e10", "actor": { "userId": "c2b1…", "label": "Mere Ngata" }, "entityType": "card_holder", "entityId": "9d5e…", "action": "update", "changes": { "department": { "from": "Nursing", "to": "Midwifery" } }, "ipAddress": "203.0.113.9", "userAgent": "Mozilla/5.0 …", "redactedAt": null, "prevHash": "a1f0…", "hash": "7c2e…"}seq is the entry’s place in the organisation’s chain, starting at 1 with
no gaps. prevHash is the hash of entry seq - 1. redactedAt is set
when the personal fields inside changes were blanked under a privacy
request or the retention policy; the entry’s place and hash are kept, and
the redaction is itself an entry.
Streams
Section titled “Streams”Under Settings, Audit log, Streams an organisation sends entries to its own collector as they are written. A cursor per stream means a collector that was down receives everything it missed, in order, once.
Webhook. A POST to your HTTPS URL with up to 200 entries per request:
{ "type": "audit.entries", "organisationId": "7e0d…", "entries": [ … ] }The request carries X-IDPortal-Event: audit.entries and an
X-IDPortal-Signature header computed with the stream’s secret exactly as
for every other webhook. Answer with any 2xx status.
Syslog. RFC 5424 over TLS with octet counting (RFC 6587), one message
per entry: facility 13 (log audit), severity 6, app name idportal, the
action as the message id, structured data
[cardoffice@58001 seq="4821" hash="7c2e…" org="7e0d…"], and the entry’s
JSON as the message. Your collector must present a certificate that a
public resolver trusts.
Exports
Section titled “Exports”Settings, Audit log, Export downloads a date range. The NDJSON form is one entry per line in chain order and a trailer line:
{ "trailer": "cardoffice-audit-export", "version": 1, "organisationId": "7e0d…", "from": "2026-10-01T00:00:00.000Z", "to": "2026-11-01T00:00:00.000Z", "entries": 3120, "sha256": "…", "signature": "…", "keyId": "3f9a1c2b4d5e6f70" }sha256 is over every byte above the trailer. signature is Ed25519 over
the string cardoffice-audit-export|v1|<sha256>, base64, or null when
CardOffice has no signing key configured. Verify with
ops/verify-audit-export.mjs from the CardOffice repository, which checks
the hash, the signature against the public key, and the chain links and
numbering inside the file:
curl -s https://app.cardoffice.nz/api/audit/public-key | jq -r .data.publicKeyPem > cardoffice-audit.pemnode ops/verify-audit-export.mjs audit-2026-10-01_2026-10-31.ndjson cardoffice-audit.pemThe CSV form carries the same columns for a spreadsheet and is not signed.
Daily digests
Section titled “Daily digests”Just after midnight UTC, CardOffice writes a digest per organisation for
the previous day: the first and last seq, the count, and the chain’s head
hash after the last entry, signed with the same key. Digests are listed on
the settings page and are what lets a chain still verify after entries older
than the organisation’s audit retention have been removed.
Public key
Section titled “Public key”{ "data": { "algorithm": "Ed25519", "keyId": "3f9a1c2b4d5e6f70", "publicKeyPem": "-----BEGIN PUBLIC KEY-----\n…" } }keyId is the first 16 hex characters of the SHA-256 of the PEM with its
whitespace removed; digests and export trailers name the key they were
signed with so a rotated key can still be matched.
Verifying inside CardOffice
Section titled “Verifying inside CardOffice”Settings, Audit log, Verify the whole chain now recomputes every entry’s hash in the database and checks every link and number. Faults are reported by position, and the verification is itself logged.
© 2026 Secure ID Ltd. All rights reserved.Documentation licence and terms