> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Troubleshooting: connectivity SIM events — usage gates, lifecycle stream, and a silent webhook

> Diagnose the seven connectivity_sim.* webhook events — usage_warning vs limit_exceeded quota gates, the ordered → active ⇄ suspended → terminated lifecycle decoder, and the checklist for when the event stream goes quiet.

# Troubleshooting: connectivity SIM events — usage gates, lifecycle stream, and a silent webhook

A connectivity (eSIM / IoT / M2M) SIM reports every state change and every
quota gate as one of seven `connectivity_sim.*` webhook events. This page is
the runbook for that event family: what each event means, why the warning
and the hard cap behave differently, how to decode the lifecycle, and what
to check when the events you subscribed to never arrive.

The model behind the events is on the
[connectivity SIM concept page](/concepts/connectivity-sim-model), and the
full operating walk-through (order → activate → meter → suspend →
terminate) is the [connectivity SIM lifecycle guide](/guides/connectivity-sim-lifecycle). This page is for when the
stream misbehaves. The dashboard surface for everything below is
**Numbers → Connectivity**.

## 1. Event subscription

There are seven `connectivity_sim.*` event types, split into two families:
the **usage gates** (`usage_warning`, `limit_exceeded`) and the **lifecycle
transitions** (`ordered`, `activated`, `suspended`, `resumed`,
`terminated`). Subscribe to the ones you need on the endpoint that receives
`POST /api/v1/webhooks` deliveries — registered under
**Settings → Webhooks** in the dashboard, or through the webhooks API. The
delivery envelope, signature headers, and retry schedule are the same as
for every other event family; see
[Webhooks overview](/webhooks/overview).

The payload differs by family. Usage-gate events carry the quota counters:

```json theme={null}
{
  "type": "connectivity_sim.limit_exceeded",
  "data": {
    "iccid": "8942790014173625180",
    "plan_id": "iot-fleet-pooled",
    "usage_bytes": 5368709120,
    "data_limit_bytes": 5368709120,
    "warning_threshold_bytes": 4294967296,
    "state": "suspended"
  }
}
```

Lifecycle events carry the inventory fields instead:

```json theme={null}
{
  "type": "connectivity_sim.suspended",
  "data": {
    "iccid": "8942790014173625180",
    "plan_id": "iot-fleet-pooled",
    "state": "suspended",
    "fleet_id": "fleet-nordic",
    "cmp_sim_id": "cmp_8f2a1190"
  }
}
```

Full payload shapes for all seven types are in the
[webhook events reference](/reference/webhook-events). Deduplicate on the
envelope event id — `connectivity_sim.*` deliveries are at-least-once, so a
retry or a dead-letter replay can deliver the same lifecycle event twice.

## 2. Usage gates — warning vs hard cap

Two events guard consumption, and they answer different questions:

| Event | Fires when | SIM state afterward | Your move |
| - | - | - | - |
| `connectivity_sim.usage_warning` | Cumulative usage crosses the warning threshold (the percent of the cap you set as `warningThresholdPct`) | Unchanged — the SIM keeps carrying data | Notify, project the burn rate, decide whether to raise the cap before it is hit |
| `connectivity_sim.limit_exceeded` | Cumulative usage reaches or passes the hard cap (`dataLimitBytes`) | **Suspended for quota** — data sessions stop accruing | Raise the cap (`PATCH /numbers/connectivity/sims/:iccid/quota`), then `POST .../resume` to bring the SIM back |

The warning is advisory: it fires once per threshold crossing and changes
nothing on the SIM. The limit event is the gate closing — at the cap the
SIM suspends itself, which is the platform enforcing the budget you set
rather than a fault. That is why every `limit_exceeded` handler should end
in a quota change plus a resume; without both, resuming alone puts the SIM
straight back over the same cap on the next session.

If you receive `limit_exceeded` but never saw a `usage_warning` first,
check the quota configuration: a warning point only exists where
`warningThresholdPct` is set, and a threshold without a cap is rejected at
write time. Clear both fields and the stream goes quiet on the usage
family entirely — lifecycle events still fire.

## 3. Lifecycle decoder

The SIM lifecycle has four states, and every legal move between them emits
exactly one event:

```
ordered → activated ⇄ suspended → terminated
```

* `connectivity_sim.ordered` — record created from
  `POST /numbers/connectivity/sims`. The SIM exists but carries no data.
  An eSIM line may wait on a device-side install before activation; a
  physical SIM waits on its activation call.
* `connectivity_sim.activated` — **first** transition into `active` from
  `POST .../activate`. Data sessions start accruing from here.
* `connectivity_sim.suspended` — paused from `POST .../suspend` (manually,
  or by the usage hard cap). No usage accrues while suspended.
* `connectivity_sim.resumed` — return from `suspended` to `active` via
  `POST .../resume`. This is deliberately a different type from
  `activated` so your subscriber can tell a first activation apart from a
  post-suspend restart — bill or alert accordingly.
* `connectivity_sim.terminated` — terminal sink from `POST .../terminate`.
  Nothing can run against the SIM afterward; `active ⇄ suspended` was
  reversible, this is not.

A `409` on activate/suspend/resume/terminate means the SIM is not in the
state the verb expects (most often: already terminated). Read the current
`state` with `GET /numbers/connectivity/sims/:iccid` before issuing the
transition. If your integration only watches `activated` and treats
`resumed` as unknown, it sees suspended SIMs come back as noise — handle
both return-to-active types.

## 4. Events not firing — the silent-stream checklist

`connectivity_sim.*` events are emitted **best-effort** from the per-SIM
endpoints (`POST /numbers/connectivity/sims` and the
`/activate|/suspend|/resume|/terminate|/usage` verbs). A successful state
change returns `2xx` even when the webhook delivery fails, so an empty
stream while the API works means the delivery path broke, not the SIM.
Work through these in order:

1. **Subscription.** Confirm the endpoint under **Settings → Webhooks**
   still lists the `connectivity_sim.*` types. A recreated endpoint does
   not inherit the old one's event filter.
2. **Endpoint health.** A delivery endpoint that answers `401/403/404/410`
   is treated as proven-dead: retries are skipped, the endpoint is
   disabled, and the org admin is notified. Re-enable it after fixing the
   response — see
   [integration receiver disabled](/troubleshooting/integration-webhook-receiver-disabled).
3. **Endpoint cap.** Creating or re-registering endpoints can race the
   per-organization endpoint cap, which silently drops registrations. See
   [webhook endpoint cap and DNS pre-create](/troubleshooting/webhook-endpoint-cap-and-dns-pre-create).
4. **Dead-letter queue.** Deliveries that exhausted retries (about 4.3
   hours of backoff) land in the DLQ and stay replayable for 7 days. List
   them under **Developer → Webhooks → Dead-letter queue** or with
   `GET /api/v1/webhooks/dlq`, and requeue with
   `POST /api/v1/webhooks/dlq/:deliveryId/requeue`. The full recovery flow
   is on the [Webhooks overview](/webhooks/overview#retry-schedule-and-dead-letter-queue).
5. **Silent by configuration.** Usage events only exist while a quota is
   set — if only the usage family is missing while lifecycle events
   arrive, re-read section 2 before suspecting delivery.

If the SIM record itself is stuck — `ordered` forever despite an install
completing, for example — that is a queue or surface problem, not an event
problem; route through
[enqueued empty states](/troubleshooting/enqueued-empty-states).

## 5. Escalation checklist

Open a ticket when sections 1–4 rule out every self-serve cause. Attach
the bundle so support does not have to re-derive your state:

* **ICCID** of the SIM (the identifier in every payload and every per-SIM
  path).
* **Plan id** (`plan_id` from the subscription or the SIM record).
* **Request id** — the `meta.request_id` from the state-change or
  usage-recording POST that should have fired the event.
* The **event type** you expected and the **delivery id** (`evt_...`) from
  the DLQ row or the inspecting-deliveries log, when one exists.
* For quota disputes: the `usage_bytes`, `data_limit_bytes`, and
  `warning_threshold_bytes` from the event payload or from
  `GET /numbers/connectivity/sims/:iccid/usage`.

With those, support can replay the DLQ entry, trace the emitter, and
confirm the state the record settled into without a round trip.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.