Event catalog
Every async state change in Helium MVNE emits a webhook event. This catalog enumerates the event types you can subscribe to; payload shapes are documented in the API reference under the Events tag.
Shape
Every event carries:
{
"id": "evt_...",
"type": "sim.activated",
"created_at": "2026-04-24T15:00:00Z",
"livemode": false,
"data": { "object": { ... } },
"idempotency_key": "..."
}
Subscription events
| Type | Fires when |
|---|---|
subscription.created | A subscription is created (reserved, not emitted in v0) |
subscription.updated | A status or pending-plan-change reconciliation with no dedicated event below, such as a scheduled downgrade being set or cleared |
subscription.plan_switched | A plan change applies (an upgrade immediately, a scheduled downgrade at renewal) |
subscription.paused | Moves to paused |
subscription.resumed | Moves from paused back to active |
subscription.cancelled | Moves to cancelled |
subscription.terminated | Moves to terminated (reserved, no trigger in v0) |
subscription.past_due | Payment is overdue and the subscription moves to past_due |
subscription.unpaid | Payment retries are exhausted and collection has stopped |
subscription.recovered | A past_due subscription recovers to active after a successful payment |
SIM events
| Type | Fires when |
|---|---|
sim.ordered | SIM record created |
sim.activated | Carrier confirms activation |
sim.activation_failed | Carrier rejects activation |
sim.suspended | Moves to suspended |
sim.reinstated | Moves back to active |
sim.swap_completed | New SIM takes over the MSISDN |
sim.deactivated | Terminal deactivation |
Port events
| Type | Fires when |
|---|---|
port.submitted | Port-in request accepted by Helium MVNE |
port.validation_success | Losing carrier validated |
port.validation_failed | Losing carrier rejected |
port.scheduled | Carrier scheduled the cut-over |
port.completed | Number transfer complete |
port_out.requested | Gaining carrier requested port-out |
port_out.completed | Port-out finalized |
CPNI step-up events
When a support agent needs to view a subscriber's PII or change their account, Helium MVNE issues a one-time verification code and asks you to deliver it to the subscriber over your own channel (SMS, app push, email). The subscriber reads it back to the agent, who enters it to unlock access for a window.
| Type | Fires when |
|---|---|
cpni.verification.requested | An agent started a step-up challenge — carries the one-time code |
cpni.verification.succeeded | The agent entered the correct code |
cpni.verification.failed | The challenge locked out after too many attempts |
cpni.verification.requested is the only event whose payload
contains a secret: data.object.code. Deliver it to the subscriber and
treat it like a password — don't log it, and don't store it. The code is
short-lived (operator-configured, default 10 minutes) and is never
returned by the GET /events API; it rides the signed webhook only.
{
"type": "cpni.verification.requested",
"data": {
"object": {
"object": "cpni_verification",
"id": "cpniv_01HGZX...",
"subscriber_id": "sbr_01HGZX...",
"agent": { "user_id": "...", "email": "agent@operator.example" },
"code": "482913",
"expires_at": "2026-06-08T17:10:00Z",
"grant_duration_seconds": 1800
}
}
}
Carrier + operational events
| Type | Fires when |
|---|---|
carrier_connection.verify_failed | A scheduled verify call failed |
usage.threshold_crossed | Configured data/voice/SMS threshold hit |
event.delivery_failed | A webhook endpoint landed in dead-letter |
Event types are additive — new types may appear without a major
version bump. Handlers should ignore unknown type values.