API reference
Webhooks
Endpoints we POST signed events to, their delivery history and resends.
10 operationsBase URL https://packetexchange.io/api/v1Postman collection
BrowseWebhooks
List your webhook endpoints
GET/
- Access
- API key. Scoped keys need
account:read. - Rate limit
- 100 requests per second (the default)
Secrets are redacted to their last 4 characters.
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object[] | - |
idrequireddata[].id | string (uuid) | - |
urlrequireddata[].url | string (uri) | - |
secretLast4requireddata[].secretLast4 | string | Last 4 characters of the signing secret, to tell secrets apart |
eventsrequireddata[].events | string[] | -One of call.completed, call.ringing, call.answered, call.gathered, sms.sent, sms.dlr, sms.delivered, sms.failed, campaign.started, campaign.completed, topup.confirmed, balance.low and 24 more |
isActiverequireddata[].isActive | boolean | False when you disabled it, or after sustained delivery failures |
failureCountrequireddata[].failureCount | integer | Consecutive failed deliveries; resets on success |
lastDeliveryAtrequireddata[].lastDeliveryAt | string (date-time) | null | ISO-8601 timestamp (UTC) |
createdAtrequireddata[].createdAt | string (date-time) | ISO-8601 timestamp (UTC) |
updatedAtrequireddata[].updatedAt | string (date-time) | ISO-8601 timestamp (UTC) |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Create a webhook endpoint
POST/
- Access
- API key. Scoped keys need
webhooks:write. - Rate limit
- 100 requests per second (the default)
The signing secret is returned ONCE in secret. URLs must be https and resolve to a public address. Works from a dashboard session, or with an API key that was created with the webhooks:write permission. A full-access key does not include webhooks:write: it has to be chosen explicitly, so keys issued before this permission existed cannot manage endpoints.
Each delivery is a POST of { event, data, timestamp } with headers X-Webhook-Event, X-Webhook-Id (the delivery id), X-PX-Timestamp (Unix seconds at send time) and two signatures: X-PX-Signature: v1=<hex HMAC-SHA256 of "<timestamp>.<raw body>"> (verify this one, and reject timestamps more than 5 minutes old to stop replays) and the legacy X-Webhook-Signature: sha256=<hex HMAC-SHA256 of the raw body>, kept during the transition.
Request body (application/json)
| Field | Type | Description |
|---|---|---|
urlrequired | string (uri) | - |
eventsrequired | string[] | -One of call.completed, call.ringing, call.answered, call.gathered, sms.sent, sms.dlr, sms.delivered, sms.failed, campaign.started, campaign.completed, topup.confirmed, balance.low and 24 more |
Response 201
| Field | Type | Description |
|---|---|---|
datarequired | object | - |
idrequireddata.id | string (uuid) | - |
urlrequireddata.url | string (uri) | - |
secretLast4requireddata.secretLast4 | string | Last 4 characters of the signing secret, to tell secrets apart |
eventsrequireddata.events | string[] | -One of call.completed, call.ringing, call.answered, call.gathered, sms.sent, sms.dlr, sms.delivered, sms.failed, campaign.started, campaign.completed, topup.confirmed, balance.low and 24 more |
isActiverequireddata.isActive | boolean | False when you disabled it, or after sustained delivery failures |
failureCountrequireddata.failureCount | integer | Consecutive failed deliveries; resets on success |
lastDeliveryAtrequireddata.lastDeliveryAt | string (date-time) | null | ISO-8601 timestamp (UTC) |
createdAtrequireddata.createdAt | string (date-time) | ISO-8601 timestamp (UTC) |
updatedAtrequireddata.updatedAt | string (date-time) | ISO-8601 timestamp (UTC) |
secretrequireddata.secret | string | The signing secret. Returned ONCE; store it now. |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 409
CONFLICT(or a code-specific 409): the change clashes with existing state. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Update a webhook endpoint
PATCH/
- Access
- API key. Scoped keys need
webhooks:write. - Rate limit
- 100 requests per second (the default)
Change the URL, the subscribed events or isActive. The signing secret and delivery history are kept. Works from a dashboard session, or with an API key that was created with the webhooks:write permission. A full-access key does not include webhooks:write: it has to be chosen explicitly, so keys issued before this permission existed cannot manage endpoints.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string | - |
Request body (application/json)
| Field | Type | Description |
|---|---|---|
url | string (uri) | - |
events | string[] | -One of call.completed, call.ringing, call.answered, call.gathered, sms.sent, sms.dlr, sms.delivered, sms.failed, campaign.started, campaign.completed, topup.confirmed, balance.low and 24 more |
isActive | boolean | - |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | Same fields as Webhook, shown earlier on this page. |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 404
NOT_FOUND: no such resource on your account. - 409
CONFLICT(or a code-specific 409): the change clashes with existing state. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Delete a webhook endpoint
DELETE/
- Access
- API key. Scoped keys need
webhooks:write. - Rate limit
- 100 requests per second (the default)
Removes the endpoint, its secret and its delivery history. Events stop immediately. Works from a dashboard session, or with an API key that was created with the webhooks:write permission. A full-access key does not include webhooks:write: it has to be chosen explicitly, so keys issued before this permission existed cannot manage endpoints.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string | - |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | - |
idrequireddata.id | string (uuid) | - |
deletedrequireddata.deleted | boolean | -One of true |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 404
NOT_FOUND: no such resource on your account. - 409
CONFLICT(or a code-specific 409): the change clashes with existing state. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Rotate a webhook signing secret
POST/
- Access
- API key. Scoped keys need
webhooks:write. - Rate limit
- 100 requests per second (the default)
Issues a new secret, returned once. Deliveries are signed with it from this moment (including pending retries); there is no overlap window, so update your receiver at the same time. Works from a dashboard session, or with an API key that was created with the webhooks:write permission. A full-access key does not include webhooks:write: it has to be chosen explicitly, so keys issued before this permission existed cannot manage endpoints.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string | - |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | - |
idrequireddata.id | string (uuid) | - |
urlrequireddata.url | string (uri) | - |
secretLast4requireddata.secretLast4 | string | Last 4 characters of the signing secret, to tell secrets apart |
eventsrequireddata.events | string[] | -One of call.completed, call.ringing, call.answered, call.gathered, sms.sent, sms.dlr, sms.delivered, sms.failed, campaign.started, campaign.completed, topup.confirmed, balance.low and 24 more |
isActiverequireddata.isActive | boolean | False when you disabled it, or after sustained delivery failures |
failureCountrequireddata.failureCount | integer | Consecutive failed deliveries; resets on success |
lastDeliveryAtrequireddata.lastDeliveryAt | string (date-time) | null | ISO-8601 timestamp (UTC) |
createdAtrequireddata.createdAt | string (date-time) | ISO-8601 timestamp (UTC) |
updatedAtrequireddata.updatedAt | string (date-time) | ISO-8601 timestamp (UTC) |
secretrequireddata.secret | string | The signing secret. Returned ONCE; store it now. |
messagerequireddata.message | string | - |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 404
NOT_FOUND: no such resource on your account. - 409
CONFLICT(or a code-specific 409): the change clashes with existing state. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Send a test ping to a webhook endpoint
POST/
- Access
- API key. Scoped keys need
account:write. - Rate limit
- 100 requests per second (the default)
Queues a ping delivery, signed like any other, usually delivered within 15 seconds.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string | - |
Response 202
| Field | Type | Description |
|---|---|---|
datarequired | object | - |
idrequireddata.id | string (uuid) | - |
statusrequireddata.status | string | -One of pending, sending, delivered, failed |
eventrequireddata.event | string | -One of ping |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 404
NOT_FOUND: no such resource on your account. - 409
CONFLICT(or a code-specific 409): the change clashes with existing state. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
List deliveries for one webhook endpoint
GET/
- Access
- API key. Scoped keys need
account:read. - Rate limit
- 100 requests per second (the default)
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string | - |
cursor | query | string (uuid) | The nextCursor from the previous page |
limit | query | integer | -Default 20 |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object[] | - |
idrequireddata[].id | string (uuid) | Also sent as the X-Webhook-Id header. Automatic retries reuse it (de-duplicate on it); a manual resend is a new delivery with a new id. |
webhookIddata[].webhookId | string (uuid) | Present on the account-wide list |
urldata[].url | string | The endpoint URL, on the account-wide list |
eventrequireddata[].event | string | - |
statusrequireddata[].status | string | -One of pending, sending, delivered, failed |
httpStatusrequireddata[].httpStatus | integer | null | Response code your server returned on the last attempt |
attemptsrequireddata[].attempts | integer | Attempts so far (max 5, with attempts^2-minute backoff) |
lastErrorrequireddata[].lastError | string | null | - |
nextRetryAtrequireddata[].nextRetryAt | string (date-time) | null | ISO-8601 timestamp (UTC) |
createdAtrequireddata[].createdAt | string (date-time) | ISO-8601 timestamp (UTC) |
deliveredAtrequireddata[].deliveredAt | string (date-time) | null | ISO-8601 timestamp (UTC) |
nextCursorrequired | string | null | Pass as cursor to fetch the next page; null on the last page. |
hasMorerequired | boolean | True when another page exists. |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 404
NOT_FOUND: no such resource on your account. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
List webhook deliveries across all your endpoints
GET/
- Access
- API key. Scoped keys need
account:read. - Rate limit
- 100 requests per second (the default)
Newest first. Filter by endpoint, status or event. Includes the endpoint URL on each row.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
cursor | query | string (uuid) | The nextCursor from the previous page |
limit | query | integer | -Default 20 |
webhookId | query | string (uuid) | Only deliveries to this endpoint |
status | query | string | -One of pending, sending, delivered, failed |
event | query | string | Only this event name, e.g. call.completed |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object[] | Same fields as WebhookDelivery, shown earlier on this page. |
nextCursorrequired | string | null | Pass as cursor to fetch the next page; null on the last page. |
hasMorerequired | boolean | True when another page exists. |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Get one webhook delivery, with its payload
GET/
- Access
- API key. Scoped keys need
account:read. - Rate limit
- 100 requests per second (the default)
Parameters
| Name | In | Type | Description |
|---|---|---|---|
deliveryIdrequired | path | string | - |
Response 200
| Field | Type | Description |
|---|---|---|
datarequired | object | - |
idrequireddata.id | string (uuid) | Also sent as the X-Webhook-Id header. Automatic retries reuse it (de-duplicate on it); a manual resend is a new delivery with a new id. |
webhookIddata.webhookId | string (uuid) | Present on the account-wide list |
urldata.url | string | The endpoint URL, on the account-wide list |
eventrequireddata.event | string | - |
statusrequireddata.status | string | -One of pending, sending, delivered, failed |
httpStatusrequireddata.httpStatus | integer | null | Response code your server returned on the last attempt |
attemptsrequireddata.attempts | integer | Attempts so far (max 5, with attempts^2-minute backoff) |
lastErrorrequireddata.lastError | string | null | - |
nextRetryAtrequireddata.nextRetryAt | string (date-time) | null | ISO-8601 timestamp (UTC) |
createdAtrequireddata.createdAt | string (date-time) | ISO-8601 timestamp (UTC) |
deliveredAtrequireddata.deliveredAt | string (date-time) | null | ISO-8601 timestamp (UTC) |
payloadrequireddata.payload | object | The exact JSON body that was (or will be) POSTed |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 404
NOT_FOUND: no such resource on your account. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.
Resend a webhook delivery
POST/
- Access
- API key. Scoped keys need
account:write. - Rate limit
- 30 requests per minute
Queues a NEW delivery with the same event and payload to the same endpoint, signed with a fresh timestamp. The original delivery is left as it was, so the history shows both. The new delivery has its own id (X-Webhook-Id); the payload is byte-identical, so de-duplicate on your own event data if you need exactly-once processing. The endpoint must be active.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
deliveryIdrequired | path | string | - |
Response 202
| Field | Type | Description |
|---|---|---|
datarequired | object | Same fields as WebhookDelivery, shown earlier on this page. |
Errors
- 400
VALIDATION_ERROR,INVALID_INPUTorBAD_REQUEST. ForVALIDATION_ERROR,error.detailsis an array of{ path, message }. - 401
UNAUTHORIZED: missing, invalid, expired or revoked credential. - 403
FORBIDDEN: not allowed - a scoped key lacks the scope, or the endpoint is session-only. - 404
NOT_FOUND: no such resource on your account. - 409
CONFLICT(or a code-specific 409): the change clashes with existing state. - 429
RATE_LIMITED: slow down and retry after theRetry-Afterseconds. - 500
INTERNAL_ERROR: unexpected failure. QuoteX-Request-Idto support.