# Citrus Mobile Reseller API

_Version 2.0_

Build your own eSIM platform with pay-as-you-go connectivity in 200+ countries.

The Citrus Mobile Reseller API lets you provision, manage, and bill for eSIMs
programmatically. Build a travel eSIM storefront, IoT connectivity platform,
corporate travel solution, or any product that needs cellular data in 200+
countries.

## Quick Start

1. Create a developer account at [citrusmobile.com/developer](https://citrusmobile.com/developer).
2. Top up your reseller balance via the developer dashboard. Minimum **$10**.
3. Check available rates with `GET /rates`.
4. Provision your first eSIM with `POST /esim/provision`.
5. Fund the eSIM with `POST /esim/{iccid}/fund` — the SIM starts with a $0 wallet.

## Pricing

- **No monthly fee** — API access is free for all registered developers
- **$1.75 per eSIM** provisioning fee
- Data rates are **10% below** the retail rates shown on citrusmobile.com
- Volume-commitment discounts start at $1,000/month — contact sales

## Authentication

All requests require an API key in the `Authorization` header. API keys use
the prefix `rsk_` and are 68 characters long.

```
Authorization: Bearer rsk_a1b2c3d4e5f6...
```

### Access levels

| Operation | API Key | Balance |
|-----------|---------|---------|
| Read endpoints (list, status, rates, balance) | Required | — |
| Provision eSIM | Required | ≥ $1.75 |
| Enable data | Required | > $0 |
| Throttle speed | Required | — |
| Fund eSIM | Required | ≥ funded amount |
| Defund eSIM (return unused balance) | Required | — |
| Disable / Terminate | Required | — |
| Webhook management | Required | — |
| Create / update group | Required | — |
| Fund group | Required | ≥ funded amount |
| Defund group | Required | — |
| Add / remove group eSIM | Required | — |

## Rate Limits

API requests are limited to **100 requests per minute** per API key.
Exceeding this returns `429 Too Many Requests` with a `Retry-After` header.
Need higher limits? Email [support@citrusmobile.com](mailto:support@citrusmobile.com).

## Display Precision

`wallet_balance_usd` is always rounded **down** to the nearest cent and may
be up to ~5¢ below the exact remaining credit — never above it. Funding
`$20` will show `$19.99` right after funding; funding `$9`, `$18`, or `$27`
round-trips exactly. Your customer is never shortchanged — the SIM always
has at least the displayed amount of credit.

## Propagation Delay

Our upstream network takes about 10 minutes to reflect credit and usage
changes. `POST /fund` returns immediately and your customer can start using
data right away, but the reporting pipeline (`total_data_charged_usd`
updates, `esim.balance_low` / `esim.balance_depleted` webhooks) pauses for
about 15 minutes after every fund so upstream propagation can settle. Usage
during that window is still counted and appears on the next sync cycle.

## Shared Balance Groups

A group is a shared wallet. Every eSIM you put in it draws from one balance
instead of being funded one by one. A partner running 20 eSIMs for a single
customer funds one group, not 20 wallets.

### One-time setup, per group

1. `POST /groups` to create it. Set `low_balance_threshold_usd` and
   `refill_amount_usd` here, or accept the defaults of $10 and $25.
2. `POST /groups/{id}/fund` to move money from your account into the group.

### Per eSIM

3. `POST /esim/provision` with `group_id`. The eSIM is born into the group.
   It has no wallet of its own, so `POST /esim/{iccid}/fund` on it returns
   `ESIM_IN_GROUP`. Fund the group instead.

### The loop, from then on

4. The group balance drops below `low_balance_threshold_usd`.
5. If your account balance cannot cover `refill_amount_usd` and you have
   auto-refill configured, we charge your saved card first and wait for the
   credit to land. This is why the notification in step 6 can arrive a few
   minutes after the balance actually dipped: we would rather you receive it
   with funds already in place than send you a transfer that fails.
6. We send the `group.balance_low` webhook.
7. Your system calls `POST /groups/{id}/fund` for `suggested_amount_usd`.

### Drive the loop from `group.balance_low`, not from a top-up event

Step 7 must be triggered by `group.balance_low`, which fires once per
crossing and only when the group actually needs money.

Triggering the same transfer on `balance.topped_up` or
`balance.auto_refill_succeeded` looks equivalent and is not. Those fire
whenever your account is credited, including by your own auto-refill, so the
transfer runs against money that has just arrived and empties the account
again, which asks for another refill.

Two guards make this bounded rather than unbounded, and neither is
permission to build it that way:

- Moving money into a group or a SIM wallet is a transfer, not spend, and
  never triggers an auto-refill charge. Only real spend does: provisioning
  an eSIM, or a group that is low while your account cannot cover it.
- Auto-refill stops after 10 charges in 24 hours, switches itself off, and
  emails you.

If you do fund on a top-up event, read the group's current `balance_usd`
first and transfer only the shortfall against its threshold.

### Subscribe your webhook to the group events first

**If you registered your webhook before shared balance groups existed, you
are not subscribed to the group events and step 6 will never reach you.**
Webhook subscriptions are an explicit list of event names, so the four
`group.*` events and the two `esim.group_*` events are not added to existing
endpoints automatically.

Check what you are subscribed to with `GET /webhooks`, then update the
endpoint with `PUT /webhooks/{id}`:

```
PUT /webhooks/{id}
{ "events": ["*"] }
```

Using `["*"]` subscribes to every current and future event. If you prefer an
explicit list, add at least `group.balance_low`, since the whole top-up loop
depends on it, plus `group.funded`, `group.balance_depleted`,
`group.defunded`, `esim.group_assigned`, and `esim.group_removed`.
`GET /webhooks` returns the full set in `available_events`.

`group.balance_low` fires **once per crossing**, not once per sync cycle. A
group sitting below its threshold will not re-notify until the balance
recovers above the threshold and dips again. Funding the group also resets
it, so a partial top-up that leaves the group still low will re-notify on
the next dip.

If we could not top up your account within about 30 minutes, the webhook is
sent anyway with `account_underfunded: true`. That flag means your saved
card needs attention: check `GET /account` for `auto_refill_last_error`.

### Moving eSIMs between modes

eSIMs move freely. `POST /groups/{id}/esims` adds one, and
`DELETE /groups/{id}/esims/{iccid}` returns it to standalone mode at a $0
balance.

Most moves complete immediately and return `200`. The one exception is
moving a standalone eSIM that still holds its own balance. We cannot simply
flip it, or that money would be stranded, so we pause its data, return the
balance to your account, and complete the move once our upstream reporting
settles. That returns `202` with `status: "move_pending"` and
`settles_in_minutes`. A `202` is not a failure. Watch for the
`esim.group_assigned` webhook, or poll `GET /esim/{iccid}` until `group_id`
is set.

### Getting money back out

`POST /groups/{id}/defund` returns a group's remaining balance to your
account. It pauses data on every member eSIM first, then settles after about
15 minutes. Members stay in the group at a $0 balance and resume as soon as
you fund the group again.

### Limits

You can have up to **10 groups**, each holding up to **500 eSIMs**. These
limits exist only to deter spam and abuse. If your business needs more,
email [support@citrusmobile.com](mailto:support@citrusmobile.com) and we
will raise them.

Groups cannot be deleted. To reuse one, move its eSIMs out, defund it, and
rename it with `PATCH /groups/{id}`.

## Servers

- `https://citrusmobile.com/api/v2/reseller` — Production

## Authentication

**ApiKeyAuth** (http / bearer)

API key passed as a bearer token. Keys use the `rsk_` prefix and are 68 characters long. Manage keys at [citrusmobile.com/developer](https://citrusmobile.com/developer).

## Endpoints

- `POST /esim/provision` — Provision a new eSIM
- `GET /esim/list` — List your eSIMs
- `GET /esim/{iccid}` — Get eSIM details
- `POST /esim/{iccid}/enable` — Enable data on an eSIM
- `POST /esim/{iccid}/disable` — Disable data on an eSIM
- `POST /esim/{iccid}/terminate` — Terminate an eSIM
- `POST /esim/{iccid}/throttle` — Throttle SIM speed
- `POST /esim/{iccid}/defund` — Return an eSIM's unused balance
- `POST /esim/{iccid}/fund` — Fund an eSIM wallet
- `GET /groups` — List groups (New)
- `POST /groups` — Create a group (New)
- `GET /groups/{id}` — Get a group (New)
- `PATCH /groups/{id}` — Update a group (New)
- `POST /groups/{id}/fund` — Move funds into a group (New)
- `POST /groups/{id}/defund` — Return a group balance to your account (New)
- `GET /groups/{id}/esims` — List eSIMs in a group (New)
- `POST /groups/{id}/esims` — Add an eSIM to a group (New)
- `DELETE /groups/{id}/esims/{iccid}` — Remove an eSIM from a group (New)
- `GET /wallet/balance` — Get reseller account balance
- `GET /rates` — Get per-country data rates
- `GET /account` — Get account details
- `GET /webhooks` — List webhook endpoints
- `POST /webhooks` — Register a new webhook endpoint
- `GET /webhooks/{id}` — Get webhook detail
- `PUT /webhooks/{id}` — Update a webhook
- `DELETE /webhooks/{id}` — Delete a webhook
- `POST /webhooks/{id}/test` — Send a test event

## Endpoint Reference


### `POST /esim/provision`

**Provision a new eSIM**

Tags: eSIMs

Reserves an eSIM from inventory, assigns it to your billing group, and returns installation details including a QR code (base64 PNG data URL) and an iOS direct install URL. The SIM is created with a **$0 wallet** — call `POST /esim/{iccid}/fund` before your customer can use data. Delivery of the QR code or install URL is your responsibility (e.g. via email). Pass `group_id` to issue the eSIM into a shared-balance group instead. It then draws from the group balance and is not funded individually.

**Request body** `application/json`

- `end_user_reference` `string` — Your own customer/order ID for tracking. Surfaced in webhook payloads. (e.g. `order_789`)
- `label` `string` — Human-friendly label shown in dashboards and webhook payloads. (e.g. `Jane Smith - Tokyo`)
- `group_id` `string <uuid>` — Issue this eSIM into a shared-balance group. It will draw from the group balance and cannot be funded individually. Omit for a standalone eSIM funded with `POST /esim/{iccid}/fund`.

**Responses**

- `201` — eSIM created and reserved.
- `401` — API key is missing, invalid, or revoked.
- `402` — Reseller balance is insufficient for the requested operation.
- `503` — eSIM inventory depleted. Try again later or contact support.

### `GET /esim/list`

**List your eSIMs**

Tags: eSIMs

List all eSIMs provisioned by your account with pagination and optional status filtering. The returned items include the per-SIM `wallet_balance_usd` so you can drive a dashboard without a follow-up lookup.

**Parameters**

- `status` (query) `enum(pending | active | suspended | terminated)` — Filter by status
- `limit` (query) `integer` — Max results per page (up to 100).
- `offset` (query) `integer` — Pagination offset.

**Responses**

- `200` — eSIM list.
- `401` — API key is missing, invalid, or revoked.

### `GET /esim/{iccid}`

**Get eSIM details**

Tags: eSIMs

Get full detail for one eSIM, including a live activation state read from the network (with graceful fallback to the cached state). **`wallet_balance_usd`** is the remaining balance on this SIM's wallet in the same units you funded it with. When it hits 0, data stops. See the display-precision note in the intro. **`total_data_charged_usd`** is the lifetime data usage charged for this SIM at the rates returned by `/rates`. Use it as a running meter for per-customer throttle or quota logic.

**Parameters**

- `iccid` (path) `string` _(required)_ — The ICCID of the eSIM.

**Responses**

- `200` — eSIM detail.
- `401` — API key is missing, invalid, or revoked.
- `404` — ICCID not found or doesn't belong to your account.

### `POST /esim/{iccid}/enable`

**Enable data on an eSIM**

Tags: eSIMs

Enable cellular data. Use this to resume connectivity after a disable or suspension.

**Parameters**

- `iccid` (path) `string` _(required)_ — The ICCID of the eSIM.

**Responses**

- `200` — Data enabled.
- `401` — API key is missing, invalid, or revoked.
- `402` — Reseller balance is insufficient for the requested operation.
- `404` — ICCID not found or doesn't belong to your account.

### `POST /esim/{iccid}/disable`

**Disable data on an eSIM**

Tags: eSIMs

Disable cellular data. The eSIM remains provisioned but cannot pass data until re-enabled.

**Parameters**

- `iccid` (path) `string` _(required)_ — The ICCID of the eSIM.

**Responses**

- `200` — Data disabled.
- `401` — API key is missing, invalid, or revoked.
- `404` — ICCID not found or doesn't belong to your account.

### `POST /esim/{iccid}/terminate`

**Terminate an eSIM**

Tags: eSIMs

Permanently terminate an eSIM. Disables data and marks the profile as terminated. **This action cannot be undone.** Any remaining wallet balance is forfeited.

**Parameters**

- `iccid` (path) `string` _(required)_ — The ICCID of the eSIM.

**Responses**

- `200` — eSIM terminated.
- `400` — eSIM is already terminated. Cannot un-terminate; provision a new one.
- `401` — API key is missing, invalid, or revoked.
- `404` — ICCID not found or doesn't belong to your account.

### `POST /esim/{iccid}/throttle`

**Throttle SIM speed**

Tags: eSIMs

Set the data speed on an eSIM. Use this to implement fair-use policies (e.g., full speed for the first 2 GB/day, then throttle to 512 Kbps). Set to `NO_LIMIT` to restore full speed. Valid speeds: `NO_LIMIT`, `SPEED_100_KBPS` through `SPEED_3000_KBPS` in 100 Kbps increments, plus `SPEED_3500_KBPS`, `SPEED_4000_KBPS`, `SPEED_4500_KBPS`, and `SPEED_5000_KBPS`. Common choices: - `SPEED_500_KBPS` — basic browsing and messaging - `SPEED_1000_KBPS` — standard definition video - `SPEED_2000_KBPS` — light HD streaming

**Parameters**

- `iccid` (path) `string` _(required)_ — The ICCID of the eSIM.

**Request body** `application/json` (required)

- `speed` `enum(NO_LIMIT | SPEED_100_KBPS | SPEED_500_KBPS | SPEED_1000_KBPS | SPEED_2000_KBPS | SPEED_5000_KBPS)` _(required)_ — Throttle speed. See the full list in the description.

**Responses**

- `200` — Throttle applied.
- `400` — Invalid request body or parameters.
- `401` — API key is missing, invalid, or revoked.
- `404` — ICCID not found or doesn't belong to your account.

### `POST /esim/{iccid}/defund`

**Return an eSIM's unused balance**

Tags: eSIMs

Returns the unused balance on an eSIM to your account balance. This is asynchronous. The call immediately pauses data on the SIM and returns `202` with an estimate. The credit lands after a short settlement period (about 15 minutes), once upstream usage has fully reported. The final amount credited may be lower than `estimated_return_usd` if your customer used data between your request and settlement. The returned amount equals the SIM's displayed balance. The SIM is not terminated: its profile stays installed and you can fund it again later. A SIM with a return in progress cannot be funded or re-enabled until it completes.

**Parameters**

- `iccid` (path) `string` _(required)_

**Responses**

- `202` — Balance return accepted and data paused.
- `400` — No returnable balance (`NO_BALANCE_TO_RETURN`), the SIM is terminated (`ESIM_ALREADY_TERMINATED`), or it has no wallet yet (`WALLET_NOT_READY`).
- `401` — API key is missing, invalid, or revoked.
- `404` — ICCID not found or doesn't belong to your account.
- `409` — A balance return is already in progress (`DEFUND_ALREADY_PENDING`).
- `502` — Could not pause data upstream; nothing was moved (`UPSTREAM_ERROR`).

### `POST /esim/{iccid}/fund`

**Fund an eSIM wallet**

Tags: eSIMs

Fund an eSIM's data wallet. Deducts from your reseller account balance and credits the SIM's individual wallet. The eSIM can use data until this funded amount is consumed at the rates shown in `/rates`. Your reseller account is **not** debited again during usage — the fund call is the only charge. To top a customer up mid-trip, just call this endpoint again with the additional amount. See the **Display Precision** and **Propagation Delay** notes in the intro for details on how the balance number you get back relates to the amount you funded.

**Parameters**

- `iccid` (path) `string` _(required)_ — The ICCID of the eSIM.

**Request body** `application/json` (required)

- `amount` `number` _(required)_ — Amount in USD to fund this eSIM (deducted from your reseller account balance).

**Responses**

- `200` — eSIM funded.
- `400` — Invalid request body or parameters.
- `401` — API key is missing, invalid, or revoked.
- `402` — Reseller balance is insufficient for the requested operation.
- `404` — ICCID not found or doesn't belong to your account.

### `GET /groups`

**List groups (New)**

Tags: Groups

Every shared-balance group on your account, newest first. Remove the "New" badge from this operation once the feature is no longer newly launched.

**Responses**

- `200` — Groups
- `401` — API key is missing, invalid, or revoked.

### `POST /groups`

**Create a group (New)**

Tags: Groups

Creates a shared-balance group with a $0 balance. Fund it with `POST /groups/{id}/fund` before issuing eSIMs into it. Groups cannot be deleted, and you can have at most 10. This limit exists only to deter spam and abuse; email support@citrusmobile.com if you need more.

**Request body** `application/json` (required)

- `name` `string` _(required)_ — Your label for the group. Must be unique on your account. (e.g. `Acme Corp Fleet`)
- `low_balance_threshold_usd` `number` — Send `group.balance_low` when the group balance drops below this. (e.g. `25`)
- `refill_amount_usd` `number` — How much you intend to transfer in when notified. Sent as `suggested_amount_usd`. (e.g. `100`)

**Responses**

- `201` — Created
- `400` — Invalid request body or parameters.
- `401` — API key is missing, invalid, or revoked.
- `409` — A group with that name already exists (`GROUP_NAME_TAKEN`)
- `429` — Group limit reached (`GROUP_LIMIT_REACHED`)

### `GET /groups/{id}`

**Get a group (New)**

Tags: Groups

**Responses**

- `200` — Group
- `401` — API key is missing, invalid, or revoked.
- `404` — Not found (`GROUP_NOT_FOUND`)

### `PATCH /groups/{id}`

**Update a group (New)**

Tags: Groups

Change the name or the top-up policy. Provide at least one field. Renaming is how you reuse a group you are done with, since groups cannot be deleted.

**Request body** `application/json` (required)

- `name` `string`
- `low_balance_threshold_usd` `number`
- `refill_amount_usd` `number`

**Responses**

- `200` — Updated
- `400` — Invalid request body or parameters.
- `401` — API key is missing, invalid, or revoked.
- `404` — Not found (`GROUP_NOT_FOUND`)
- `409` — Name already taken (`GROUP_NAME_TAKEN`)

### `POST /groups/{id}/fund`

**Move funds into a group (New)**

Tags: Groups

Debits your account balance and credits the group. Every member eSIM draws from this balance. Funding also resets the low-balance notification state, so the group will notify again on its next dip below the threshold.

**Request body** `application/json` (required)

- `amount` `number` _(required)_ (e.g. `100`)

**Responses**

- `200` — Funded
- `400` — Invalid request body or parameters.
- `401` — API key is missing, invalid, or revoked.
- `402` — Account balance too low (`INSUFFICIENT_BALANCE`)
- `404` — Not found (`GROUP_NOT_FOUND`)
- `409` — A balance return is in progress (`GROUP_DEFUND_PENDING`)

### `POST /groups/{id}/defund`

**Return a group balance to your account (New)**

Tags: Groups

Pauses data on every member eSIM, then returns the group's remaining balance to your account. Settlement takes about 15 minutes because our upstream network needs that long to report final usage. Members stay in the group at a $0 balance and resume as soon as you fund it again. Watch for the `group.defunded` webhook.

**Responses**

- `200` — Return requested
- `400` — Nothing to return (`NO_BALANCE_TO_RETURN`)
- `401` — API key is missing, invalid, or revoked.
- `404` — Not found (`GROUP_NOT_FOUND`)
- `409` — Already in progress (`GROUP_DEFUND_PENDING`)

### `GET /groups/{id}/esims`

**List eSIMs in a group (New)**

Tags: Groups

**Parameters**

- `limit` (query) `integer`
- `offset` (query) `integer`

**Responses**

- `200` — Members
- `401` — API key is missing, invalid, or revoked.
- `404` — Not found (`GROUP_NOT_FOUND`)

### `POST /groups/{id}/esims`

**Add an eSIM to a group (New)**

Tags: Groups

Moves an existing eSIM into this group. Returns `200` immediately in most cases. If the eSIM is standalone and still holds its own balance, we cannot flip it without stranding that money, so we pause its data, return the balance to your account, and finish the move once our upstream reporting settles. That case returns `202` with `status: "move_pending"`. Watch for `esim.group_assigned`. A group holds at most 500 eSIMs. This limit exists only to deter spam and abuse; email support@citrusmobile.com if you need more.

**Request body** `application/json` (required)

- `iccid` `string` _(required)_ (e.g. `8944478000000123456`)

**Responses**

- `200` — Moved
- `202` — Move accepted, settling
- `400` — Invalid request body or parameters.
- `401` — API key is missing, invalid, or revoked.
- `404` — Group or eSIM not found (`GROUP_NOT_FOUND`, `ESIM_NOT_FOUND`)
- `409` — Already a member, or a move is already in progress (`ESIM_ALREADY_IN_GROUP`, `MOVE_PENDING`)
- `429` — Group is full (`GROUP_FULL`)

### `DELETE /groups/{id}/esims/{iccid}`

**Remove an eSIM from a group (New)**

Tags: Groups

Returns the eSIM to standalone mode with a $0 balance. Fund it with `POST /esim/{iccid}/fund`. No money moves, because a pooled eSIM holds none of its own.

**Responses**

- `200` — Removed
- `401` — API key is missing, invalid, or revoked.
- `404` — Not a member of that group (`ESIM_NOT_FOUND`)

### `GET /wallet/balance`

**Get reseller account balance**

Tags: Wallet

Check your current reseller account balance and lifetime spending statistics. `data_suspended` is `true` **only** if Citrus support has manually frozen your account. A zero main-account balance does **not** disable existing eSIMs — they keep running as long as their per-SIM wallets have credit. Use the per-SIM `esim.balance_depleted` webhook to detect individual SIM cutoffs. `lifetime_usage_usd` is the total you've spent out of your reseller account (provisioning fees + every `/fund` call). It doesn't include pending top-ups.

**Responses**

- `200` — Wallet balance.
- `401` — API key is missing, invalid, or revoked.

### `GET /rates`

**Get per-country data rates**

Tags: Rates

Get per-country data rates — 10% below the retail rates on citrusmobile.com. These are the rates charged to your account as your customers consume data. Filter by country or continent.

**Parameters**

- `country` (query) `string` — Filter by ISO2 code, slug, or name (e.g. `US`, `japan`).
- `continent` (query) `string` — Filter by continent (e.g. `Europe`, `Asia`).

**Responses**

- `200` — Rate card.
- `401` — API key is missing, invalid, or revoked.

### `GET /account`

**Get account details**

Tags: Account

Returns your account details and eSIM counts.

**Responses**

- `200` — Account detail.
- `401` — API key is missing, invalid, or revoked.

### `GET /webhooks`

**List webhook endpoints**

Tags: Webhooks

List all registered webhook endpoints for your account. Also returns the full set of subscribable event names.

**Responses**

- `200` — Webhook list.
- `401` — API key is missing, invalid, or revoked.

### `POST /webhooks`

**Register a new webhook endpoint**

Tags: Webhooks

Register a new webhook endpoint. You'll receive a `signing_secret` in the response — **save it immediately as it won't be shown again**. Maximum 5 webhooks per account. Subscribe to specific events or pass `["*"]` to receive all events.

**Request body** `application/json` (required)

- `url` `string <uri>` _(required)_ — HTTPS URL that receives webhook POSTs.
- `events` `string[]` _(required)_ — Events to subscribe to, or `["*"]` for all.

**Responses**

- `201` — Webhook registered.
- `400` — Invalid request body or parameters.
- `401` — API key is missing, invalid, or revoked.

### `GET /webhooks/{id}`

**Get webhook detail**

Tags: Webhooks

**Parameters**

- `id` (path) `string` _(required)_

**Responses**

- `200` — Webhook detail.
- `401` — API key is missing, invalid, or revoked.
- `404` — Resource not found.

### `PUT /webhooks/{id}`

**Update a webhook**

Tags: Webhooks

Update URL, events, or active state. Setting `active` to `true` resets `failure_count` to 0.

**Parameters**

- `id` (path) `string` _(required)_

**Request body** `application/json` (required)

- `url` `string <uri>`
- `events` `string[]`
- `active` `boolean`

**Responses**

- `200` — Webhook updated.
- `400` — Invalid request body or parameters.
- `401` — API key is missing, invalid, or revoked.
- `404` — Resource not found.

### `DELETE /webhooks/{id}`

**Delete a webhook**

Tags: Webhooks

**Parameters**

- `id` (path) `string` _(required)_

**Responses**

- `200` — Deleted.
- `401` — API key is missing, invalid, or revoked.
- `404` — Resource not found.

### `POST /webhooks/{id}/test`

**Send a test event**

Tags: Webhooks

Send a test event to a webhook endpoint to verify it's receiving and processing correctly. The test event uses the special event type `"test"` and does not require a subscription to any specific event.

**Parameters**

- `id` (path) `string` _(required)_

**Responses**

- `200` — Test delivery result.
- `401` — API key is missing, invalid, or revoked.
- `404` — Resource not found.

## Contact

- Email: support@citrusmobile.com
- https://citrusmobile.com/developer

---

This Markdown is a server-rendered mirror of the interactive API reference at https://citrusmobile.com/developer/docs, generated from the OpenAPI spec at https://citrusmobile.com/openapi-reseller.yaml.
