Audit Logs
The audit log records changes made in your Shorebird organization: who created a release, promoted or rolled back a patch, changed a member’s role, issued a service account key, and so on. Each entry says who acted, with which credential, from where, and on what.
People signing in, personal API keys, and requests that were refused aren’t recorded as events of their own. Each event names the sign-in session or API key behind it instead.
The audit log is available on the Enterprise plan. Owners and Admins of the organization can read it, as can a service account with the Auditor role. Other roles cannot. An enterprise’s Owners and Admins, and an Auditor service account the enterprise owns, read its own log: changes to the enterprise, and membership and access changes in its organizations, without their apps’ contents. See Enterprise Roles and Export your enterprise audit log.
Events are available through the API for at least 90 days.
View the audit log in the console
Section titled “View the audit log in the console”In the Shorebird console, open your organization’s Settings and select the Audit Log tab to see every event in the organization, newest first. Each app also has an Audit Log tab that shows only that app’s events.
Both pages can be filtered by event. Open an entry’s details to see the credential used, the API key or sign-in session, the IP address, the user agent, and any event-specific details such as the patch number.
Export the audit log to a SIEM
Section titled “Export the audit log to a SIEM”To keep the audit log in your own security tooling, poll the audit log API in oldest-first order and forward each new event.
- Create a service account and change its role to Auditor. Auditor can read the audit log and nothing else, so the key your SIEM holds cannot change anything in the organization.
- Create a key for it and
send the key (
sb_api_...) as a bearer token. - Call
GET /api/v1/organizations/{organizationId}/audit-logs?order=asc. The organization ID is the number after/orgs/in the console’s address bar. - Forward the events in
data, then save the response’snext_cursor. - On the next poll, send the saved value as
cursor. Keep the cursor you have when a response has nonext_cursor.
A poll without a cursor starts at the oldest event available. To start later,
add startDate.
Oldest-first reads leave out events from the most recent minute, so an event whose write was still finishing when you polled is never skipped. It appears on a later poll instead.
If your poller stops after forwarding a page but before saving its cursor, the
next poll returns those events again. Deduplicate on each event’s
metadata.uid, which is unique per event.
Each page holds up to 100 events (per_page, default 30). When a page comes
back full, poll again right away. Requests count against the API’s per-caller
rate limit, and a 429 response carries a Retry-After header.
Poll with curl
Section titled “Poll with curl”Save this as a script and run it on a schedule. Each run reads one page, appends
its events to events.jsonl, and saves the cursor for the next run:
Poll with the Shorebird CLI
Section titled “Poll with the Shorebird CLI”shorebird api
(Shorebird CLI 1.6.129 or later) sends the same request, authenticated with the
key in SHOREBIRD_TOKEN. It replaces the query and curl lines in the script
above:
Don’t add --paginate (Shorebird CLI 1.6.130 or later) to an order=asc
request: oldest-first responses keep returning a next_cursor, so once
--paginate reaches the newest event it sees the same cursor twice, exits with
status 1, and prints no events.
Read it with shorebird audit-log
Section titled “Read it with shorebird audit-log”shorebird audit-log (Shorebird 1.6.135 or newer) reads the same events. list
shows one page and prints the command for the next one. export writes every
page to stdout, as one JSON array or, with --format jsonl, one event per line.
Both take the filters the API does, as flags such as
--start, --end, --app-id, and --event. --start and --end also take a
date, which covers the whole day in UTC, or how long ago, such as 7d. Run
shorebird audit-log export --help for the options.
To read your enterprise’s own log instead, as one of its Owners or Admins, run
shorebird enterprise audit-log (Shorebird 1.6.136 or newer). It takes the same
list and export subcommands and filters, without an organization ID.
To poll on a schedule, export oldest first with --order asc and pass the
cursor the previous run printed as --cursor, the way the scripts above save
next_cursor. Without a cursor, each run starts again at the oldest event. With
--json, the cursor is the envelope’s data.next_cursor, next to the events in
data.entries.
It works with a shorebird login session, a key in SHOREBIRD_TOKEN, or GitHub
Actions OIDC, as long as the credential belongs to an Owner, an Admin, or an
Auditor service account. A release and patch only key can’t read the audit log.
Export your enterprise audit log
Section titled “Export your enterprise audit log”Your enterprise’s own log, with changes to the enterprise and membership and access changes across its organizations, is exported the same way from a service account the enterprise owns. Enterprise Owners and Admins can create one:
- In the Shorebird console, open Enterprise in the sidebar, then its Security tab.
- Under Service accounts, click Create service account, name it for where the events will go, and create it. It gets the Auditor role, which reads the enterprise’s audit log and nothing else.
- Create a key for it and send the key as a bearer token.
- Poll
GET /api/v1/enterprises/{enterpriseId}/audit-logs?order=ascthe way the steps in Export the audit log to a SIEM describe, with the same cursor, filters and paging.shorebird enterpriseprints your enterprise’s ID as(id: ...).
The account belongs to the enterprise, not to whoever created it, so the export keeps working when they leave.
Filter the audit log
Section titled “Filter the audit log”These query parameters narrow the results, in either order:
startDateandendDate: ISO 8601 timestamps with a time zone, such as2026-10-01T00:00:00Z. Both ends are inclusive.appId: only events for that app.actorId: only events by that user or service account (itsactor.user.uid). Events by a user or service account that was later deleted no longer have auid, so this filter doesn’t find them. It never matches events by Shorebird staff.operation: only one event, by name, such aspatch.rollback. See Events.order:desc(newest first, the default) orasc.
For example, to list the patch rollbacks in an app, newest first:
Event format
Section titled “Event format”Each event is an
OCSF 1.9.0 API Activity
event (class_uid 6003), so a SIEM that reads OCSF can ingest it without a
custom parser. This is a member rolling back a patch in the console:
The fields most queries use:
api.operation: the event name, from the list below.activity_idsays whether it created (1), read (2), updated (3), or deleted (4) something, or 99 for anything else.time: when the event happened, in milliseconds since the Unix epoch.actor.user: who acted.type_idis 1 for a person and 4 for a service account, whosenameis the account’s name. A service account has no email address, so it has noemail_addr; identify it byuid. A change Shorebird staff made to your organization hastype_id99 andtypeshorebird_staff, with the nameShorebird staff. Which staff member acted isn’t shown, and neither is their credential, session, IP address, or user agent.actor.session: present when the actor was signed in to the console or the CLI.uididentifies the sign-in session,created_timeis when it began, andissueris the identity provider the person signed in with.is_mfais present only when the identity provider reported whether a second factor was used. Google reports it only when the person authenticated with Google during that sign-in, not when Google reused an existing Google session, so a missingis_mfameans unknown, not “no”.api.token: present when the request used an API key.uidis the key’s ID, which is what you revoke, andnameis the key’s name when the event was recorded.src_endpoint.ip: the IP address the request came from. For an action in the console, that’s the person’s own address, not the console’s. When none was recorded,src_endpointis{"name": "unknown"}.http_request.user_agent: the request’sUser-Agent, when it sent one. For an action in the console, that’s the person’s browser.resources: what was acted on.typenames the kind of thinguididentifies, such aspatch,release, oruser.metadata.uid: the event’s unique ID.metadata.tenant_uidis the organization ID, andmetadata.correlation_uid, when present, is theX-Request-IDheader the request sent.unmapped: fields OCSF has no place for.app_idandapp_namename the app,actor_sourcenames the kind of credential (session,api_key,service_account,federatedfor a CI job signed in with OIDC,admin_apifor Shorebird staff, ornone; absent on older events), and the rest are details of the event, such as a patch number or a member’s previous role. Anorg_member.addfor a person who joined the organization automatically when they signed in hassaml_sso,google_workspace, ormicrosoft_entraas itsactor_source, for the identity provider they signed in with. A request from a CI job signed in with a trust rule hasci, with therepository, therun_idof the workflow run, and therule_idof the trust rule.
Events
Section titled “Events”Event names can change. A renamed event appears under its new name, including
past occurrences. An event Shorebird no longer records appears with its stored
resource and action as api.operation, in the form resource_type.action, and
activity_id 99. The operation filter takes event names, not that fallback
form.
Changes to a person’s own account, such as their display name, billing limits, or deleting their account, aren’t part of an organization’s audit log.
Organizations
Section titled “Organizations”organization.create: an organization was created.organization.rename: an organization was renamed.organization.delete: deleting an organization and its apps stopped partway. Once an organization is fully deleted, its audit log can no longer be read.organization.ownership_transfer: ownership was transferred to another member.org_allowed_domain.add: Shorebird staff added an email domain to the domains the organization can invite from.org_allowed_domain.remove: Shorebird staff removed an email domain from those domains.organization.enterprise_default_update: an enterprise admin or Shorebird staff made the organization one of the enterprise’s default organizations, changed the role people join it at, or stopped it being one. Its details are the enterprise ID and the role before and after.
Members and invitations
Section titled “Members and invitations”org_member.add: a user joined the organization.org_member.role_update: a member’s role was changed.org_member.remove: a member was removed.invitation.create: an invitation to the organization or an app was sent.invitation.revoke: a pending invitation was revoked.invitation.accept: an invitation was accepted.invitation.decline: an invitation was declined.
Service accounts
Section titled “Service accounts”service_account.create: a service account was created.service_account.role_update: a service account’s role was changed.service_account.delete: a service account and its API keys were deleted.service_account_key.create: an API key was issued to a service account.service_account_key.revoke: a service account’s API key was revoked.service_account_trust_rule.create: a trust rule was added to a service account.service_account_trust_rule.delete: a trust rule was deleted.service_account.sign_in: a CI job signed in as a service account through a trust rule. Itsunmappeddetails are the job’s claims, such asrepository,workflow_ref,run_id, andref, with the trust rule’srule_id. They aren’t underci.
Apps and collaborators
Section titled “Apps and collaborators”app.create: an app was created.app.update: an app’s settings, such as its display name, were changed.app.transfer: an app was moved to another organization.app.delete: an app was deleted.app_collaborator.add: a user was given a role on an app.app_collaborator.role_update: an app collaborator’s role was changed.app_collaborator.remove: a collaborator was removed from an app.
App Store Connect
Section titled “App Store Connect”app_store_connect_credential.set: the organization gave Shorebird an App Store Connect key, replacing any it had.app_store_connect_credential.delete: the organization removed its App Store Connect key.
Channels
Section titled “Channels”channel.create: a channel was created.channel.delete: a channel was deleted.
Patch signing
Section titled “Patch signing”signing_key.create: Shorebird created the organization’s managed patch-signing key. It does this when a signing key is fetched for one of the organization’s apps and the organization has no current key, as on its first managedshorebird release. The actor is whoever made that request.
Releases
Section titled “Releases”release.create: a release was created.release.update: a release was updated, such as its status or notes.release.delete: a release was deleted.release_artifact.upload: a release artifact was uploaded.release_artifact.replace: a release artifact was replaced by a new upload.release_artifact.delete: a release’s artifacts were deleted.release_artifact.download: a release’s artifacts were listed with their download links.
Patches
Section titled “Patches”patch.create: a patch was created.patch_artifact.upload: a patch artifact was uploaded.patch.promote: a patch was promoted to the stable channel.patch.channel_update: a patch was moved to a channel other than stable.patch.rollback: a patch was rolled back.patch.rollforward: a rolled-back patch was rolled forward.patch.notes_update: a patch’s notes were changed.
Enterprises
Section titled “Enterprises”These appear in an enterprise’s log. Events about an organization’s place in the enterprise, and revoking an organization’s service account key, also appear in that organization’s log.
enterprise.create: the enterprise was created.enterprise.rename: the enterprise was renamed.enterprise.billing_account_update: Shorebird staff gave the enterprise its billing account, so its organizations bill through the company.enterprise_contract.download: an Owner or Billing manager downloaded one of the enterprise’s signed contracts.enterprise.organization_attach: an organization was added to the enterprise.enterprise.organization_detach: an organization was removed from the enterprise, keeping its apps and members.enterprise_domain.add: a domain was added to the enterprise. People who sign in with an account managed by the domain are in the enterprise’s directory from then on.enterprise_domain.remove: a domain was removed from the enterprise.enterprise_domain.sign_in_method_update: the sign-in method a domain’s accounts must use was set or cleared.enterprise_saml_connection.attach: a SAML connection was attached to the enterprise.enterprise_saml_connection.detach: a SAML connection was detached.enterprise.guest_policy_update: the enterprise changed who outside its directory its organizations may invite: anyone, no one, or people at listed domains. Guests already in its organizations stay.enterprise_member.add: an admin, or the enterprise’s identity provider over SCIM, added a person before their first sign-in, with an enterprise role.enterprise_member.role_update: a person’s enterprise role was changed.enterprise_member.update: the enterprise’s identity provider changed a member’s email, display name, or its own ID for them over SCIM.enterprise_member.remove: an admin, or the enterprise’s identity provider over SCIM, deactivated a person: removed them from every one of the enterprise’s organizations and every grant on its apps, and revoked their sessions, API keys, and invitations. Each organization also records anorg_member.remove.enterprise_member.reactivate: a deactivated person was reactivated, so they can sign in again with the enterprise role they held. Their organizations, grants, sessions, and API keys don’t come back.enterprise_guest.remove: an admin removed a guest, someone the enterprise doesn’t manage, from all of its organizations and app grants, and revoked their invitations. The guest’s account is left alone. Each organization also records anorg_member.remove.enterprise_api_key.revoke: an admin revoked an API key from the enterprise’s inventory: a service account’s key or a member’s personal key.