Anatomy of a governance event
Every connector maps its own vocabulary into one shared event shape. That is what lets a single filter span Slack, GitHub, Okta, Google Workspace and AWS.
The shape of an event#
{
"id": "8f14e45f-ea2b-4c2f-9f1e-1d6a3b0c7e21",
"entity_seq": 42,
"source_tool": "okta",
"event_type": "access.admin_role_granted",
"actor": { "email": "[email protected]", "external_id": "00u1a2b3c4" },
"subject": { "email": "[email protected]", "external_id": "00u9z8y7x6" },
"payload": { "role": "SUPER_ADMIN" },
"occurred_at": "2026-08-03T09:14:22.000Z",
"ingested_at": "2026-08-03T09:14:23.481Z",
"source_event_id": "b1946ac9-2c1f-4a45-9d3f-88a2c6a7e0d1",
"prev_hash": "4b227777d4dd1fc61c6f884f48641d02b4d121d3fd328cb08b5531fcacdabf8a",
"row_hash": "ef2d127de37b942baad06145e54b0c619a1f22327b2ebbcfbec78f5564afe39d"
}Field by field#
Hashes are lowercase hex with no 0x prefix. The organisation and entity identifiers are stored on the row but not returned, because the URL you used to fetch the event already establishes both.
Actor and subject#
Both are either an object with email and external_id, or null. They are null when the source tool gave neither, which happens for events that are not attributable to a person, such as a workspace-level setting change reported without an author.
How completely these are filled depends on the tool. Okta and Google Workspace supply email addresses. Slack supplies opaque user ids, which Governax resolves to email at the moment of writing, because an append-only record cannot be enriched afterwards. GitHub webhooks carry account logins and never email addresses, so GitHub events always have empty emails and can only be matched on login.
The two timestamps#
Event types#
Event types follow domain.action. Six domains are in use:
Types are reused across tools where the meaning genuinely matches, so access.group_member_added means the same thing from Okta, Google Workspace and AWS, and one filter covers all three.
Two types carry provenance markers worth knowing. access.baseline_observed is written by every connector at connect time with baseline: true in its payload, meaning "this access already existed when we started watching". And access.role_changed carries reconciled: true when it was inferred by comparing a reconnect snapshot against history, rather than observed live. The per-connector type lists are on each connector's own page.
What is deliberately not captured#
Governax records governance-relevant change, not activity. The ledger stays useful precisely because it is not a firehose.
- Slack: messages, file shares and reactions.
- GitHub: ordinary pushes, pull request opens, syncs and comments.
- Okta: routine authentication and session events.
- Google Workspace: settings toggles and usage events.
- AWS: read-only API calls, and routine IAM console activity by an MFA-authenticated user. Failed calls are dropped unless they are a sign-in failure, an attempt to tamper with a security control, or an authorisation denial against a sensitive service.
Unrecognised events are skipped silently, so a connector receiving something it has no mapping for writes nothing rather than storing a half-understood row. How that pipeline works is in How events reach the ledger.