Event reference
The authoritative list is served by the API. Read it rather than hardcoding:
const groups = await client.developer.listEventTypes();
The portal's event picker renders from this same endpoint, so the two can never drift apart.
Events
| Event | Fires when |
|---|---|
safety.incident.reported | A safety incident is submitted |
safety.incident.status_changed | An incident moves through its workflow |
safety.inspection.completed | An inspection is completed |
operations.production_log.created | A production log is recorded |
operations.shift_log.submitted | A shift log is submitted |
operations.lot.created | A mineral lot is created |
operations.custody.transferred | Custody of a lot changes hands |
compliance.permit.expiring | A permit approaches expiry |
compliance.submission.status_changed | A regulatory submission changes status |
workforce.worker.registered | A worker is registered |
workforce.payroll.batch.completed | A payroll batch finishes processing |
inventory.stock.threshold_breached | Stock crosses a configured threshold |
environment.threshold.breached | An environmental reading breaches a limit |
webhook.test | You press Send test ping |
Envelope
Every event has the same outer shape; only data varies:
{
"id": "evt_…",
"type": "safety.incident.reported",
"createdAt": "2026-03-14T09:21:04.512Z",
"environment": "live",
"data": { }
}
Forward compatibility
New event types are added over time, and an unrecognised type must not break your
receiver. The SDK's typed union stays deliberately open-ended so a default branch
compiles and keeps working:
switch (event.type) {
case 'safety.incident.reported':
return handleIncident(event.data);
default:
log.info(`Unhandled event ${event.type}`);
}
Similarly, treat data as append-only: new fields may be added within a major
version. Read the fields you need and ignore the rest.