SX Customers

Customer Webhooks

Register the HTTPS endpoint the platform pushes events to—including the withdrawal and transfer verification codes—then verify it.

The platform pushes events to one HTTPS endpoint per customer. That's also the only place verification codes arrive: when a user starts a withdrawal or a transfer, the code to confirm it goes to your webhook and is never returned by the API. Register the endpoint here, add the auth headers your backend expects, and send a test notification.

Authentication: every endpoint on this page takes your dashboard session token as a Bearer token. The session must own the {customer_id} in the path; any other id answers 404 CUSTOMER_NOT_FOUND.

Authorization: Bearer YOUR_SESSION_TOKEN

One webhook per customer

The webhook endpoint is a singleton at /v1/customers/{customer_id}/webhooks: read it with GET, create or replace it with PUT, change part of it with PATCH, and test it with POST …/verify. Each call returns the endpoint. The URL must be HTTPS on a public host—http, localhost, .local and .internal hosts, private and link-local addresses, and URLs with credentials (user:pass@) are rejected, and redirects aren't followed. Header keys are stored lowercase and header values are never returned: value_masked shows at most a 4-character hint.

Responses use the standard envelope and error format. POST and PATCH accept an optional x-idempotency-key header.

Webhook Fields

FieldTypeDescription
objectstringAlways webhook_endpoint.
customer_idstringOwning customer.
urlstring | nullTarget URL, or null when cleared.
headersarray[{key, value_masked}]. Keys are lowercase.
is_enabledbooleantrue while a URL is set.
last_verificationobject | nullLast test: {is_successful, status_code, message, verified_at}. Reset to null when the URL changes.
created_at / updated_atstringUTC timestamps without milliseconds.
created_by / updated_bystring | nullActor that created or last changed the endpoint.

Create or Replace Webhook

PUThttps://api.sandbox.sovera.io/sovx/v1/customers/:customer_id/webhooks

Set the endpoint. The first call answers 201 Created; later calls replace the URL and the whole header list and answer 200 OK.

POST /v1/customers/{customer_id}/webhooks still works as a deprecated alias of this call.

Request Body

FieldTypeRequiredDescription
urlstringYesHTTPS URL on a public host.
headersarrayNoHeaders sent with every delivery (below).

headers[] object

FieldTypeRequiredDescription
keystringYesHeader name: letters, digits, -, _. Stored lowercase.
valuestringYesHeader value. Write-only.
{
  "url": "https://your-domain.com/webhook/sovera",
  "headers": [
    { "key": "Authorization", "value": "Bearer token123" },
    { "key": "X-API-Key", "value": "secret-key-value" }
  ]
}

Success Response (201 Created, or 200 OK on replace):

{
  "success": true,
  "data": {
    "object": "webhook_endpoint",
    "customer_id": "corp-redundant-firewall",
    "url": "https://your-domain.com/webhook/sovera",
    "headers": [
      { "key": "authorization", "value_masked": "Bear********" },
      { "key": "x-api-key", "value_masked": "secr********" }
    ],
    "is_enabled": true,
    "last_verification": null,
    "created_at": "2026-10-12T14:20:00Z",
    "updated_at": "2026-10-12T14:20:00Z",
    "created_by": "1d8cb40d-8740-5a6b-94c3-7406e08ab4fd",
    "updated_by": "1d8cb40d-8740-5a6b-94c3-7406e08ab4fd"
  },
  "meta": {
    "timestamp": "2026-10-12T14:20:00Z",
    "version": "v1",
    "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736"
  }
}
curl -X PUT "https://api.sandbox.sovera.io/sovx/v1/customers/corp-redundant-firewall/webhooks" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_SESSION_TOKEN" \
  -d '{
    "url": "https://your-domain.com/webhook/sovera",
    "headers": [
      { "key": "Authorization", "value": "Bearer token123" },
      { "key": "X-API-Key", "value": "secret-key-value" }
    ]
  }'

Errors: 401 UNAUTHORIZED missing or invalid session · 404 CUSTOMER_NOT_FOUND not owned by the session, or deleted · 422 VALIDATION_ERROR URL not HTTPS or not a public host (source.pointer: /url), or invalid header key.


Get Webhook

GEThttps://api.sandbox.sovera.io/sovx/v1/customers/:customer_id/webhooks

Return the endpoint with masked header values and the last test result.

GET https://api.sandbox.sovera.io/sovx/v1/customers/corp-redundant-firewall/webhooks

Success Response (200 OK):

{
  "success": true,
  "data": {
    "object": "webhook_endpoint",
    "customer_id": "corp-redundant-firewall",
    "url": "https://your-domain.com/webhook/sovera",
    "headers": [
      { "key": "authorization", "value_masked": "Bear********" },
      { "key": "x-api-key", "value_masked": "secr********" }
    ],
    "is_enabled": true,
    "last_verification": {
      "is_successful": true,
      "status_code": 200,
      "message": "Webhook test successful",
      "verified_at": "2026-10-12T14:25:00Z"
    },
    "created_at": "2026-10-12T14:20:00Z",
    "updated_at": "2026-10-12T14:20:00Z",
    "created_by": "1d8cb40d-8740-5a6b-94c3-7406e08ab4fd",
    "updated_by": "1d8cb40d-8740-5a6b-94c3-7406e08ab4fd"
  },
  "meta": {
    "timestamp": "2026-10-12T14:26:10Z",
    "version": "v1",
    "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736"
  }
}
curl -X GET "https://api.sandbox.sovera.io/sovx/v1/customers/corp-redundant-firewall/webhooks" \
  -H "Authorization: Bearer YOUR_SESSION_TOKEN"

Errors: 401 UNAUTHORIZED · 404 CUSTOMER_NOT_FOUND · 404 WEBHOOK_NOT_FOUND no webhook configured.


Update Webhook

PATCHhttps://api.sandbox.sovera.io/sovx/v1/customers/:customer_id/webhooks

Change part of the endpoint. headers, when sent, replaces the whole list. "url": null clears the target and stops deliveries (is_enabled: false); to clear it entirely, send {"url": null, "headers": []} (GET then returns it with url: null and is_enabled: false). Changing the URL resets last_verification.

Request Body

FieldTypeRequiredDescription
urlstring | nullNoNew HTTPS URL on a public host, or null to clear.
headersarrayNoNew header list ([{key, value}]).
{
  "url": "https://your-domain.com/webhook/v2/sovera",
  "headers": [{ "key": "X-API-Key", "value": "rotated-secret-key" }]
}

Success Response (200 OK):

{
  "success": true,
  "data": {
    "object": "webhook_endpoint",
    "customer_id": "corp-redundant-firewall",
    "url": "https://your-domain.com/webhook/v2/sovera",
    "headers": [{ "key": "x-api-key", "value_masked": "rota********" }],
    "is_enabled": true,
    "last_verification": null,
    "created_at": "2026-10-12T14:20:00Z",
    "updated_at": "2026-10-12T15:30:00Z",
    "created_by": "1d8cb40d-8740-5a6b-94c3-7406e08ab4fd",
    "updated_by": "1d8cb40d-8740-5a6b-94c3-7406e08ab4fd"
  },
  "meta": {
    "timestamp": "2026-10-12T15:30:00Z",
    "version": "v1",
    "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736"
  }
}
curl -X PATCH "https://api.sandbox.sovera.io/sovx/v1/customers/corp-redundant-firewall/webhooks" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_SESSION_TOKEN" \
  -d '{ "url": "https://your-domain.com/webhook/v2/sovera", "headers": [{ "key": "X-API-Key", "value": "rotated-secret-key" }] }'

Errors: 401 UNAUTHORIZED · 404 CUSTOMER_NOT_FOUND · 404 WEBHOOK_NOT_FOUND · 422 VALIDATION_ERROR invalid URL or header.


Verify Webhook

POSThttps://api.sandbox.sovera.io/sovx/v1/customers/:customer_id/webhooks/verify

Send a test notification with your real header values and record the result in last_verification. The call answers 200 OK whether your endpoint accepts it or not; your endpoint's response body is never echoed. Send no body.

The test notification your endpoint receives looks like this—ignore anything with "test": true:

{
  "test": true,
  "pin": "123456",
  "atx_id": "test-transaction-id",
  "withdrawal_context": {
    "user_id": "test-user",
    "sub_account_id": "corp-redundant-firewall",
    "currency": "BTC",
    "amount": "0.001",
    "status": "pin_sent",
    "pin_sent_at": "2026-10-12T14:25:00.000Z"
  },
  "timestamp": "2026-10-12T14:25:00.000Z"
}
POST https://api.sandbox.sovera.io/sovx/v1/customers/corp-redundant-firewall/webhooks/verify

Success Response (200 OK), endpoint answered 401:

{
  "success": true,
  "data": {
    "object": "webhook_endpoint",
    "customer_id": "corp-redundant-firewall",
    "url": "https://your-domain.com/webhook/sovera",
    "headers": [
      { "key": "authorization", "value_masked": "Bear********" },
      { "key": "x-api-key", "value_masked": "secr********" }
    ],
    "is_enabled": true,
    "last_verification": {
      "is_successful": false,
      "status_code": 401,
      "message": "The endpoint responded with HTTP 401.",
      "verified_at": "2026-10-12T14:25:00Z"
    },
    "created_at": "2026-10-12T14:20:00Z",
    "updated_at": "2026-10-12T14:20:00Z",
    "created_by": "1d8cb40d-8740-5a6b-94c3-7406e08ab4fd",
    "updated_by": "1d8cb40d-8740-5a6b-94c3-7406e08ab4fd"
  },
  "meta": {
    "timestamp": "2026-10-12T14:25:00Z",
    "version": "v1",
    "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736"
  }
}
curl -X POST "https://api.sandbox.sovera.io/sovx/v1/customers/corp-redundant-firewall/webhooks/verify" \
  -H "Authorization: Bearer YOUR_SESSION_TOKEN"

Errors: 401 UNAUTHORIZED · 404 CUSTOMER_NOT_FOUND · 404 WEBHOOK_NOT_FOUND no webhook URL configured · 422 VALIDATION_ERROR the stored URL no longer resolves to a public host.


Event deliveries

Once the endpoint is set, it receives every event as a POST with your configured headers. The Webhooks page describes the envelope, retries, signature, how to process events safely, and the full event catalogue, including the verification code events.


Deprecated routes

These still answer for one release. Move to the routes above.

DeprecatedUse insteadBehavior today
POST /v1/customers/{customer_id}/webhooksPUT …/webhooksSame create-or-replace.
DELETE /v1/customers/{customer_id}/webhooksPATCH …/webhooks with {"url": null, "headers": []}Clears URL and headers and answers 204.

On this page