> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.simjuno.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.simjuno.com/_mcp/server.

# Webhooks

> Receive signed eSIM lifecycle and usage events from SimJuno.

SimJuno sends signed HTTPS webhooks when an eSIM's provisioning, status, usage, or validity changes.

## Set up your endpoint

Create a public HTTPS endpoint, then open **Settings → Webhook** in the [SimJuno Dashboard](https://simjuno.com/dashboard/settings) and save its URL. The URL must not contain credentials or resolve to a private network address.

```text
https://example.com/webhook/simjuno
```

![Setting up a webhook and copying its signing secret](https://fdr-prod-docs-files-public.s3.us-east-1.amazonaws.com/simjuno.docs.buildwithfern.com/0d519a1e470d2e1de59732c99fc0ca0f317063016cc931b11292e894d468a9dd/docs/assets/setup-webhook.gif?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIA6KXJSKKNFOCF7G4B%2F20260909%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260909T205805Z&X-Amz-Expires=604800&X-Amz-Signature=7a781585c91a8924f2ea0943c4d4ae7553a42571c4206cded2f0a9ce2a29213a&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject)

Copy the generated signing secret and store it in a secret manager:

```bash
SIMJUNO_WEBHOOK_SECRET=whsec_...
```

Saving an endpoint for the first time, or changing its URL, queues a `CHECK_HEALTH` event.

## Event structure

Every event has five top-level fields:

```json
{
  "id": "evt_example",
  "type": "ESIM_STATUS",
  "version": "1",
  "created_at": "2026-08-19T12:00:00.000Z",
  "data": {...}
}
```

| Field        | Type     | Description                                                             |
| ------------ | -------- | ----------------------------------------------------------------------- |
| `id`         | `string` | Unique event identifier. It remains unchanged when an event is retried. |
| `type`       | `string` | Event type that determines how to interpret `data`.                     |
| `version`    | `string` | Event payload schema version.                                           |
| `created_at` | `string` | ISO 8601 timestamp for when SimJuno created the event.                  |
| `data`       | `object` | Event-specific fields.                                                  |

## Verify signatures

SimJuno includes these headers:

| Header               | Value                                 |
| -------------------- | ------------------------------------- |
| `content-type`       | `application/json`                    |
| `simjuno-event-id`   | Event ID from the request body        |
| `simjuno-event-type` | Event type from the request body      |
| `simjuno-signature`  | `t=<unix_timestamp>,v1=<hmac_sha256>` |
| `user-agent`         | `SimJuno-Webhooks/1`                  |

The signature is the hexadecimal HMAC-SHA256 of `<timestamp>.<raw_request_body>`, where `timestamp` is in Unix seconds. Verify the unmodified request bytes before parsing JSON, compare signatures in constant time, and reject stale timestamps to limit replay attacks.

## Delivery behavior

Return any `2xx` response within 10 seconds to mark a delivery successful. SimJuno does not automatically retry a recorded failed delivery. You can retry failures from **Dashboard → Webhooks → Event delivery**; a retry keeps the event ID and body but uses a new signature timestamp.

Delivery order is not guaranteed. Network interruptions, provider notifications, and manual retries can produce repeated deliveries, so process every event idempotently.

Changing the endpoint URL keeps the current signing secret and queues a new `CHECK_HEALTH` event. Regenerating the secret invalidates the old secret immediately. Removing the endpoint clears its secret and fails pending deliveries.

## Event reference

Events associated with reseller API orders include your `transaction_id` as `transactionId`. Events for an individual eSIM also include its SimJuno `esimId`. Optional provider fields are omitted when unavailable.

### Status values

SimJuno relays these eSIMAccess status values unchanged.

#### `esimStatus`

| Value            | Meaning                                      |
| ---------------- | -------------------------------------------- |
| `GOT_RESOURCE`   | Profile allocated and ready for provisioning |
| `IN_USE`         | Profile is active and being used             |
| `USED_UP`        | All data has been consumed                   |
| `USED_EXPIRED`   | Data used and validity period has expired    |
| `UNUSED_EXPIRED` | Validity expired with no data usage          |
| `CANCEL`         | Order was cancelled                          |
| `REVOKED`        | Profile was administratively revoked         |
| `SUSPENDED`      | Profile temporarily suspended                |

#### `smdpStatus`

| Value          | Meaning                                |
| -------------- | -------------------------------------- |
| `RELEASED`     | Profile created but not yet downloaded |
| `DOWNLOAD`     | Profile download in progress           |
| `INSTALLATION` | Profile being installed on device      |
| `ENABLED`      | Profile active and enabled on device   |
| `DISABLED`     | Profile present but disabled on device |
| `DELETED`      | Profile removed from device            |

### Check health

Event type: `CHECK_HEALTH`

Sent after an endpoint URL is first saved or changed. The `data` object is empty.

```json
{
  "id": "evt_health_example",
  "type": "CHECK_HEALTH",
  "version": "1",
  "created_at": "2026-08-19T12:00:00.000Z",
  "data": {}
}
```

Use this event only to verify setup. A manual retry can deliver the same event ID again.

### Order status

Event type: `ORDER_STATUS`

Sent when every eSIM profile in an order has been allocated and is ready for retrieval.

| Field           | Description                            |
| --------------- | -------------------------------------- |
| `transactionId` | Your `transaction_id`                  |
| `orderStatus`   | Order status, currently `GOT_RESOURCE` |

```json
{
  "id": "evt_order_status_example",
  "type": "ORDER_STATUS",
  "version": "1",
  "created_at": "2026-08-19T12:00:00.000Z",
  "data": {
    "transactionId": "your-order-123",
    "orderStatus": "GOT_RESOURCE"
  }
}
```

Use this event to retrieve the allocated eSIMs for the matching `transactionId`.

### SM-DP+ event

Event type: `SMDP_EVENT`

Sent for profile installation and SM-DP+ lifecycle transitions.

| Field           | Description                        |
| --------------- | ---------------------------------- |
| `transactionId` | Your `transaction_id`              |
| `esimId`        | SimJuno eSIM identifier            |
| `esimStatus`    | Current eSIM lifecycle status      |
| `smdpStatus`    | Current profile installation state |

```json
{
  "id": "evt_smdp_example",
  "type": "SMDP_EVENT",
  "version": "1",
  "created_at": "2026-08-19T12:00:00.000Z",
  "data": {
    "transactionId": "your-order-123",
    "esimId": "esim_example",
    "esimStatus": "GOT_RESOURCE",
    "smdpStatus": "DOWNLOAD"
  }
}
```

Use `smdpStatus` to track the SM-DP+ operation and `esimStatus` to track the eSIM lifecycle.

### eSIM status

Event type: `ESIM_STATUS`

Sent when an individual eSIM's lifecycle status changes after allocation.

| Field           | Description                             |
| --------------- | --------------------------------------- |
| `transactionId` | Your `transaction_id`                   |
| `esimId`        | SimJuno eSIM identifier                 |
| `esimStatus`    | Current [eSIM status](#status-values)   |
| `smdpStatus`    | Current [SM-DP+ status](#status-values) |

```json
{
  "id": "evt_esim_status_example",
  "type": "ESIM_STATUS",
  "version": "1",
  "created_at": "2026-08-19T12:00:00.000Z",
  "data": {
    "transactionId": "your-order-123",
    "esimId": "esim_example",
    "esimStatus": "IN_USE",
    "smdpStatus": "ENABLED"
  }
}
```

Use this event for customer-facing activation, exhaustion, expiration, cancellation, revocation, and suspension states.

### Data usage

Event type: `DATA_USAGE`

Sent when the eSIM crosses a provider usage threshold.

| Field             | Description                                 |
| ----------------- | ------------------------------------------- |
| `transactionId`   | Your `transaction_id`                       |
| `esimId`          | SimJuno eSIM identifier                     |
| `totalVolume`     | Total data allowance in bytes               |
| `orderUsage`      | Data consumed in bytes                      |
| `remain`          | Remaining data in bytes                     |
| `remainThreshold` | Provider threshold value, relayed unchanged |
| `lastUpdateTime`  | Time the provider last calculated usage     |

```json
{
  "id": "evt_data_usage_example",
  "type": "DATA_USAGE",
  "version": "1",
  "created_at": "2026-08-19T12:00:00.000Z",
  "data": {
    "transactionId": "your-order-123",
    "esimId": "esim_example",
    "totalVolume": 21474836480,
    "orderUsage": 10741066164,
    "remain": 10733770316,
    "remainThreshold": 0.5,
    "lastUpdateTime": "2026-08-19T12:00:00Z"
  }
}
```

`totalVolume`, `orderUsage`, and `remain` are measured in bytes:

```text
KB = bytes / 1024
MB = bytes / 1048576
GB = bytes / 1073741824
```

For the sample above, the total is 20 GB and approximately 10 GB remains. eSIMAccess documents usage events at 50%, 80%, and 90% consumed, with `remainThreshold` values of `0.5`, `0.8`, and `0.9`. Its checked-in 90% example instead uses `0.1`, so SimJuno relays the value unchanged. Calculate the actual percentage from `orderUsage / totalVolume` rather than interpreting `remainThreshold` yourself.

Use these events for low-data notifications, usage dashboards, and top-up prompts. After a top-up, `totalVolume` can increase while `esimId` remains unchanged.

### Validity usage

Event type: `VALIDITY_USAGE`

Sent when an active eSIM is approaching expiration.

| Field           | Description                                   |
| --------------- | --------------------------------------------- |
| `transactionId` | Your `transaction_id`                         |
| `esimId`        | SimJuno eSIM identifier                       |
| `remain`        | Remaining validity measured in `durationUnit` |
| `durationUnit`  | Unit for validity values, usually `DAY`       |
| `totalDuration` | Original validity duration                    |
| `expiredTime`   | Provider-reported expiration timestamp        |

```json
{
  "id": "evt_validity_example",
  "type": "VALIDITY_USAGE",
  "version": "1",
  "created_at": "2026-08-19T12:00:00.000Z",
  "data": {
    "transactionId": "your-order-123",
    "esimId": "esim_example",
    "remain": 1,
    "durationUnit": "DAY",
    "totalDuration": 30,
    "expiredTime": "2026-08-20T12:00:00Z"
  }
}
```

This event normally fires when one day remains. Use `expiredTime` for the cutoff and `durationUnit` to interpret `remain`; an expired eSIM cannot be topped up.