Skip to main content
VelaFi sends event notifications to your registered URL as HTTP POST requests with JSON payloads. To protect your endpoint from spoofed requests, VelaFi signs every webhook payload using RSA-SHA256 and includes the hex-encoded signature in the signature request header. Your server must verify this signature before processing the event.

How Signature Verification Works

1

Extract the signature header

Read the signature header from the incoming HTTP request. The value is the RSA-SHA256 signature of the raw request body, encoded as a hexadecimal string.
2

Load your public key

Retrieve the publicKey that was returned when you created the webhook endpoint. It is also included for each webhook in the List Webhooks response. This is a Base64-encoded RSA public key in X.509 format.
3

Compute and verify the signature

Use RSA-SHA256 to verify the signature against the raw request body bytes and the public key. Decode the hex signature to bytes before verifying.
4

Respond to VelaFi

Return {"callbackStatus": "SUCCESS"} if verification passes, or {"callbackStatus": "FAIL"} if it does not. VelaFi uses this response to determine whether to retry delivery.
Always verify the signature before acting on a webhook payload. Processing unverified events can expose your system to replay attacks and fraudulent state changes.

Signature Verification Code

Webhook Event Types

VelaFi supports the following event types. Each requires a separate webhook endpoint registration. Creating a webhook is rejected while an active webhook already exists for that event type. Webhooks belong to your VelaFi account, so one webhook receives its event for every merchant under the account:

ORDER_WEBHOOK

Fired when a fiat-to-crypto or crypto-to-fiat order created through the API changes status.

GLOBAL_PAYMENT_WEBHOOK

Fired when a fiat-to-fiat global payment order created through the API changes status.

FUNDING_WEBHOOK

Fired when a funding record (a deposit, withdrawal, crypto purchase, or internal transfer) is completed, canceled, or refunded.

ON_RAMP_WITHDRAW_WEBHOOK

Fired when the crypto withdrawal for a completed API on-ramp order to the order’s destination wallet address succeeds.

STABLE_COIN_PAYMENT_WEBHOOK

Fired when a stablecoin payment order is confirmed.

CRYPTO_WITHDRAW_WEBHOOK

Fired when a crypto withdrawal from a merchant wallet succeeds, fails, or is cancelled.
Store the publicKey returned on webhook creation securely. You need it for every verification call. If you lose it, call List Webhooks, which returns the publicKey for each webhook.

Delivery and Retries

Each delivery is an HTTP POST with a JSON body and a signature header. Every payload contains these fields in addition to the event-specific fields: Payload values are sent as JSON strings, including IDs, amounts, and timestamps.
  • Acknowledgement. A delivery counts as successful only when your endpoint returns a 2xx HTTP status and a JSON object body whose callbackStatus is SUCCESS. Any other status or body counts as a failed attempt. VelaFi uses 6-second connect, write, and read timeouts, and a timeout also counts as a failed attempt.
  • Retries. A failed delivery is normally retried automatically, for three attempts in total. The second attempt is made about 5–10 minutes after the first failure, and the third about 60–65 minutes after the second failure. After the third failed attempt, the event is not retried. The Open API has no endpoint for requesting redelivery.
  • Duplicates. The same event can be delivered more than once. For example, if your endpoint processes a delivery but its response is not received in time, the event is retried. Make your handler idempotent by keying on the event type, the record ID (orderId, txId, or withdrawId), and the status.
  • Ordering and skipped statuses. VelaFi does not guarantee that deliveries arrive in the order the statuses occurred. For ORDER_WEBHOOK, GLOBAL_PAYMENT_WEBHOOK, FUNDING_WEBHOOK, and ON_RAMP_WITHDRAW_WEBHOOK, VelaFi checks the record’s current status before each attempt. If the status has changed since the event was queued, that event is discarded and not delivered, so you may not receive every intermediate status. Query the order or funding record to read its latest state. CRYPTO_WITHDRAW_WEBHOOK is sent only for a withdrawal’s final status.
  • Active webhooks only. Events are queued only while an active webhook (status 10) exists for the event type. Events that occur while no webhook is active are not queued and are not delivered later. Events that were already queued are not cancelled when a webhook is disabled or deleted: they are held, and if an active webhook for the same event type exists again within about 15 days, they are delivered to that webhook’s URL with their original webhookId. CRYPTO_WITHDRAW_WEBHOOK events are the exception: they are delivered only to the webhook they were queued for, so they are not delivered to a new webhook you create after deleting or disabling the old one.