Skip to content

Events

Events notify you of state changes in enrollments, certificates, deliveries, and other entities. This page covers event structure, delivery, and what each event means.

Events are emitted through a transactional outbox. An event exists if and only if the state change it describes was committed. There is no path that changes state without emitting, or emits without changing state.

Events are thin. They carry identifiers, the state transition, and correlation data — not personal data, not identity evidence, not document content, not credential material. When you receive an event, you fetch the full details by calling the API under your own authorization.

Delivery is at least once. Consumers must deduplicate by event identifier. An event may be retried and redelivered; the id field is the deduplication key.

Ordering is not guaranteed. Each event carries an aggregate_version (the version of the entity that changed) so you can detect and order events yourself if order matters.

Schemas evolve additively. New fields may appear; existing fields do not change meaning. Tolerate unknown fields and unknown event types.

Every event has this structure:

{
"id": "evt_8Fq2LmVw9dKpRt4X",
"type": "certificate.issued",
"api_version": "1.0.0",
"occurred_at": "2026-09-23T14:30:00Z",
"aggregate": {
"type": "certificate",
"id": "cert_abc123",
"version": 5
},
"environment": "production",
"request_id": "req_8Fq2LmVw9dKpRt4X",
"correlation_id": "your_correlation_value",
"data": {
"subscriber_id": "sub_xyz789",
"certificate_status": "issued_on_hold"
}
}
Field Meaning
id Unique identifier for this event. Use this to deduplicate, including across redeliveries.
type Dotted event type (e.g., certificate.issued). Additive: tolerate unknown types.
api_version Schema version of the event payload. Additive changes do not increment.
occurred_at RFC 3339 UTC timestamp of when the state change committed.
aggregate The entity that changed: type, id, and version. Order by version to handle redelivery.
environment sandbox or production. Never ambiguous.
request_id The API request that caused this event, where one exists.
correlation_id Your supplied correlation ID, where one was sent in the request.
data Identifiers and transition detail. Thin; never personal data or credential material.

A redelivery carries the original id and occurred_at. It is not a new event. If you receive an event and later see the same id again, it is a retry, not a state change.

You register webhook endpoints in the developer console:

  1. Provide an HTTPS URL where the platform will send events
  2. Verify control. The platform sends a GET request with a verification token. Respond with 200 and the token echoed back to prove you control the endpoint.
  3. Review delivery history. Inspect what was sent, what responses you returned, and retry attempts.
  4. Rotate endpoints. Register a new endpoint and retire the old one with a grace period for event redelivery.

Events are signed asymmetrically. The platform signs with a private key and publishes the corresponding verification key. You hold no secret.

Every webhook delivery carries:

Header Meaning
X-Trust-Signature Asymmetric signature over the raw request body
X-Trust-Signed-At RFC 3339 UTC timestamp of when the signature was made
X-Trust-Event-Id The event id for replay protection

Verification steps:

  1. Fetch the platform’s current verification keys from the published location.
  2. Verify the signature over the raw body before parsing JSON.
  3. Check that X-Trust-Signed-At is within the allowed replay window (e.g., last 5 minutes).
  4. Deduplicate by X-Trust-Event-Id, including across redeliveries.
  5. Only then parse and process the JSON.

If verification fails at any step, reject the request.

Two properties follow:

  • A breach of your endpoint cannot forge events. If someone reads your endpoint configuration, they cannot fabricate events. There is no shared secret to steal.
  • Key rotation needs no coordination. The platform publishes a new verification key with an overlap period. You fetch and cache keys; you need not be notified or reconfigured.

The platform retries delivery with bounded exponential backoff with jitter, over a retry window measured in hours. If an endpoint fails permanently, the event is retained for manual redelivery.

A permanently failing endpoint must not silently lose events. They remain retrievable in your console, and you are notified through a separate channel that does not depend on the failing endpoint.

When you receive a webhook:

  1. Verify the signature over the raw body before parsing.
  2. Reject requests outside the replay window.
  3. Deduplicate by event identifier. Process the same event ID only once, even if it is redelivered.
  4. Tolerate unknown fields and unknown event types. Ignore fields and event types you do not recognize.
  5. Order by aggregate version if order matters to you. Do not assume arrival order.
  6. Respond promptly and process asynchronously. A slow consumer is indistinguishable from a failing one. Respond with 200 immediately, then process the event in the background.
  7. Treat the event as a notification, not data. When you receive a certificate.issued event, learn that a certificate was issued. Fetch the certificate details by calling the API under your own authorization.
  8. Never treat absence of an event as evidence. If you never receive a delivery.retired event, reconcile by querying, not by assuming nothing happened.

Events are organized by entity type. All are first-slice unless marked [2] for second slice (signing).

Event Emitted when Key fields
organization.submitted Verification evidence supplied organization_id
organization.verified Legal entity confirmed organization_id
organization.rejected Verification refused organization_id, reason
organization.suspended Authority withheld organization_id, reason
organization.terminated Terminal state reached organization_id, reason
organization.verification_expiring Verification approaching lapse organization_id, expires_at
capability.granted Authority granted organization_id, capability
capability.revoked Authority withdrawn organization_id, capability
application.registered Workload registered application_id, organization_id
application.disabled Workload disabled application_id, organization_id
application.reinstated Disabled application restored application_id, organization_id
client_certificate.issued Workload identity issued application_id, certificate_id
client_certificate.expiring Approaching expiry — the most valuable operational event application_id, certificate_id, expires_at
client_certificate.rotated Replacement active application_id, old_certificate_id, new_certificate_id
client_certificate.revoked Withdrawn application_id, certificate_id
Event Emitted when Key fields
subscriber.created New subscriber record subscriber_id
enrollment.created Enrollment opened enrollment_id, subscriber_id
enrollment.submitted Submitted for verification enrollment_id, subscriber_id
enrollment.information_requested Further detail demanded enrollment_id, subscriber_id, requested_information
enrollment.verified Identity evidence accepted enrollment_id, subscriber_id
enrollment.recommended Recommended by the requesting organization enrollment_id, subscriber_id
enrollment.approved Approved enrollment_id, subscriber_id
enrollment.rejected Refused, with reasons enrollment_id, subscriber_id, rejection_reasons
enrollment.confirmation_required Subject details ready for subscriber confirmation before issuance enrollment_id, subscriber_id, proposed_certificate_digest
enrollment.confirmed Subscriber confirmed the details enrollment_id, subscriber_id
enrollment.decision_overdue The statutory decision window elapsed without a decision. Enrollment remains open. enrollment_id, subscriber_id, due_at
enrollment.cancelled Withdrawn enrollment_id, subscriber_id, reason

About enrollment.decision_overdue: This event tells you a decision is late, not that the enrollment terminated. The decision remains owed, is recorded as late, and carries no reasons (a timer did not make the decision; a human must).

Event Emitted when Key fields
certificate.issued Issued certificate_id, subscriber_id, status
certificate.published Published to the repository certificate_id
certificate.submitted_to_regulator Submitted to the regulator’s record certificate_id
certificate.submission_overdue Issued but not submitted past the defined threshold certificate_id, due_at
certificate.held Placed on hold pending the signed application certificate_id, expires_at
certificate.hold_released Hold lifted; certificate is now usable certificate_id
certificate.hold_expiring Approaching the hold limit without the signed form certificate_id, expires_at
certificate.withdrawn Hold limit reached; revoked as unsatisfied requirement certificate_id, reason
certificate.compromise_reported A compromise report received certificate_id, subscriber_id
certificate.explanation_requested Statutory explanation window opened certificate_id, due_at
certificate.suspended Suspended, with ground certificate_id, subscriber_id, reason, suspended_at, release_by, revoke_by
certificate.suspension_released Released certificate_id, subscriber_id
certificate.suspension_expiring Approaching the statutory maximum certificate_id, expires_at
certificate.show_cause_issued Ground for suspension established; subscriber has three days to show cause. Certificate stays suspended. certificate_id, show_cause_until
certificate.suspension_maximum_breached Rule 33(4) maximum reached on a controller-directed suspension the platform cannot release. Recorded as a defined state for an open policy contradiction. certificate_id, due_at
certificate.revoked Revoked, with reason and effective time certificate_id, subscriber_id, reason, effective_at
certificate.expired Validity period ended certificate_id, expired_at
certificate.expiring Approaching expiry certificate_id, expires_at
Event Emitted when Key fields
delivery.created Delivery authorized delivery_id, certificate_id, subscriber_id, application_id
delivery.available Package retrievable delivery_id, certificate_id
delivery.retrieved Package collected delivery_id, certificate_id, attempt
delivery.import_confirmed Import confirmed with digest and thumbprint delivery_id, certificate_id, digest_confirmed
delivery.retired Material retired, destruction evidence recorded delivery_id, certificate_id
delivery.expired Window elapsed unused delivery_id, certificate_id
delivery.cancelled Withdrawn delivery_id, certificate_id, reason
delivery.attempt_limit_reached Attempts exhausted delivery_id, certificate_id
transfer.requested Transfer request opened transfer_id, certificate_id, target_application_id
transfer.refused Relay refused (revoked certificate or unauthorized target) transfer_id, certificate_id, reason
transfer.completed Reported complete by receiving application transfer_id, certificate_id, target_application_id
reissuance.requested Reissuance sought reissuance_id, certificate_id, subscriber_id, reason
reissuance.completed Successor issued, predecessor revoked reissuance_id, old_certificate_id, new_certificate_id
Event Emitted when Key fields
signature_request.created [2] Request registered signature_request_id, subscriber_id, organization_id
signature_request.presented [2] Document presented, digest recorded signature_request_id, subscriber_id, document_digest
signature_request.authorized [2] Authorization evidence obtained signature_request_id, subscriber_id
signature_request.authorization_failed [2] Challenge unanswered, incorrect, or sent to unregistered channel signature_request_id, subscriber_id, reason
contact_channel.changed Registered authorization channel was changed subscriber_id, channel_type
signature_request.signed [2] Signature produced signature_request_id, subscriber_id, certificate_id
signature_request.completed [2] Validation material attached signature_request_id, subscriber_id
signature_request.declined [2] Subscriber refused — evidence, not absence signature_request_id, subscriber_id
signature_request.expired [2] Window elapsed signature_request_id, subscriber_id
signature_request.failed [2] Technical failure, retryable signature_request_id, subscriber_id, reason
envelope.participant_completed [2] One participant of a multi-party envelope signed envelope_id, subscriber_id
envelope.completed [2] All participants signed envelope_id
envelope.invalidated [2] Document revised; prior signatures void envelope_id
Event Emitted when Key fields
delegation_certificate.issued [2] Licence certificate issued delegation_certificate_id, organization_id
delegation_certificate.expiring [2] Approaching expiry delegation_certificate_id, expires_at
delegation_certificate.rotated [2] Replacement active delegation_certificate_id, old_id, new_id
delegation_certificate.suspended [2] Licence suspended delegation_certificate_id
delegation_certificate.revoked [2] Licence revoked delegation_certificate_id
Event Emitted when Key fields
usage.recorded A billable operation occurred organization_id, operation, period

Usage events never gate trust operations. They record what happened; they do not authorize it. An outage in usage recording must not block issuance, status publication, or signing.

These are not emitted as events:

What Why
Private keys, packages, or passwords Credential material never leaves its delivery path
Identity evidence Evidence is referenced by ID, never distributed
One-time codes Codes are never logged or transmitted outside their delivery channel
Document content or presentation images The platform never holds documents
Event for every revocation status check Audit records these; emitting them would swamp consumers

1. Idempotent processing. Since events may be redelivered, handle them idempotently. Store the event id and check it before processing to avoid duplicate work.

2. Fast webhook responses. Respond with 200 immediately, then process the event asynchronously. A slow consumer looks like a broken one.

3. Fetch details on demand. Events carry identifiers; fetch full details by calling the API under your own authorization. This keeps authorization at the interface.

4. Order by aggregate version. If order matters, use the aggregate.version field to detect out-of-order delivery and reorder if needed.

5. Monitor event lag. Track when events are emitted versus when you process them. Event lag indicates a problem with your endpoint or processing.

6. Preserve key events. Events like client_certificate.expiring are operationally critical. Log them and alert on them.

7. Do not rely on event presence. Use events to trigger actions, but reconcile by querying when events matter. An integrator that waits for a delivery.retired event instead of checking the delivery status will miss events and get stuck.


See Concepts for entity definitions, Errors for error handling, and the API Reference for the complete webhook and event operations.