Building a secure integration
For developers
An integration with CardOffice moves personal information and photographs between systems. Whatever protects that information inside CardOffice stops at your end of the connection, so your integration needs the same care. Work through this list before you go live.
API keys
Section titled “API keys”- One key per system, and per environment. A key for your student system, another for a photo migration, separate keys for test and production. When one has to be revoked, nothing else stops.
- Grant the fewest scopes that work. A system that only reads the roster
needs
card_holders:read, nothing more. See Scopes. - Give every key an expiry, and rotate before it arrives. See Rotating and revoking.
- Keep keys in a secret store, never in source code, configuration files checked into a repository, scripts on shared drives, or anything that runs in a browser or on a phone.
- Treat
photos:attestas privileged. A key with it can put photos onto cards without anyone reviewing them. Use it only for a one-off load from a trusted archive, then revoke it. - Call the API from your servers only. The API is not designed to be called from a browser, and a key in a web page is a published key.
Webhooks
Section titled “Webhooks”- Verify every signature before acting on a delivery, using the raw request body. See Verifying signatures.
- Reject old timestamps, so a captured delivery cannot be replayed later.
- Use a different endpoint, with its own secret, for each environment.
- Treat a delivery as a notification, not as a source of truth. When a decision matters, such as disabling door access, read the current state back from the API first.
Keep what you send to a minimum
Section titled “Keep what you send to a minimum”Send CardOffice only what the card and its processes use. A card does not need
a date of birth, a home address, a national identity number or health
information, so do not put them in customFields or notes. Information that
was never sent cannot leak.
The same applies in the other direction. Store only what your system needs from CardOffice, and do not keep copies of photos longer than you need them.
Photos
Section titled “Photos”- Upload links and download links expire quickly by design. Use them straight away and do not store them.
- Upload photos only for the person they show. A photo becomes the face on an identity credential.
- If your system keeps photos it has downloaded, protect and expire them as you would in CardOffice.
Your integration’s logs are a copy of what passed through it. Do not log API
keys, webhook secrets, Authorization headers, upload or download links, or
photo bytes. Avoid logging full card holder records; an ID and a status is
usually enough to debug.
People who leave
Section titled “People who leave”Decide which system is the source of truth for whether someone is still
active, and send that change to CardOffice promptly, by
SCIM or the API. A person marked
inactive stops passing verification at once. If a door access system also
needs to know, have it act on the
card_holder.status_changed
webhook. Revoking a card they already hold
is a separate step. See Deactivating is not revoking.
Before you go live
Section titled “Before you go live”- Keys are scoped, expiring and stored in a secret store
- Test and production use different keys and webhook endpoints
- Webhook signatures and timestamps are checked
- Nothing the card does not use is sent to CardOffice
- Logs contain no keys, links or photos
- Someone owns rotating the keys and knows how to revoke one in a hurry
© 2026 Secure ID Ltd. All rights reserved.Documentation licence and terms