# Webhooks

We recommend webhooks over polling. When something happens to one of your eSIMs, we send a
`POST` to the URL you configured for that event.

## Set up

1. Sign in to [console.gmjroaming.com](https://console.gmjroaming.com) with your reseller account.
2. Go to **Dashboard → Developer**.
3. Enter a URL for each event you want. Leave an event empty to skip it.

## Events

| Event (`notifyType`) | When | Console field |
| --- | --- | --- |
| `ORDER_STATUS` | An order's eSIMs are ready | Order Status |
| `ESIM_STATUS` | The eSIM's status changes (installed, in use, suspended, expired, ...) | eSIM Status |
| `DATA_USAGE` | Data usage was updated | Data Usage |
| `VALIDITY_USAGE` | Validity changed | Validity Usage |
| `SMDP_EVENT` | Profile events from the eSIM server (download, install, delete) | SMDP Event |

## Payload

Every webhook has the same wrapper:

```json
{
  "status": "success",
  "notifyType": "DATA_USAGE",
  "content": {
    "transactionId": "order-20261111-0001",
    "orderNo": "B26111100001",
    "iccid": "8985200012345678901",
    "totalVolume": 3221225472,
    "orderUsage": 1073741824,
    "remain": 2147483648
  }
}
```

`content.transactionId` is the purchase `transaction_id` you sent to `/checkout`. Use it, or
`iccid`, to find the eSIM on your side.

| `notifyType` | Fields you can rely on in `content` |
| --- | --- |
| `ORDER_STATUS` | A **list** of the order's eSIMs, in the same provider format as `/myesim` source data (`iccid`, `esimTranNo`, `orderNo`, `transactionId`, `ac`, ...) |
| `ESIM_STATUS` | `transactionId`, `orderNo`, `iccid` |
| `DATA_USAGE` | `transactionId`, `iccid`, `totalVolume`, `orderUsage`, `remain` (bytes) |
| `VALIDITY_USAGE` | `transactionId`, `iccid`, `durationUnit`, `totalDuration`, `expiredTime` |
| `SMDP_EVENT` | `transactionId` plus the provider's event details |

Apart from `ORDER_STATUS`, `content` is passed through from the network provider as is, so it
usually has more fields than listed. Ignore fields you don't know. After an `ESIM_STATUS`
event, read the new status with `POST /myesim`.

## Responding

Reply `200` with this body as fast as you can:

```json
{ "success": true }
```

Do slow work (database writes, emails) after you reply. We wait up to 30 seconds.

:::warning{title="Delivery is best-effort"}
- Failed deliveries are **not retried**. If you need certainty, confirm with `POST /myesim` or
  `POST /check-status-payment`.
- Webhooks aren't signed. Use a hard-to-guess URL (for example with a random token in the
  path), accept HTTPS only, and treat the payload as a hint: re-read the eSIM from the API
  before acting on it.
:::
