Vortex webhooks let your application receive real-time notifications when ramp lifecycle events occur, instead of continuously polling GET /v1/ramp/{id}.Transaction creation — a new ramp is registered.
Status changes — a ramp's status moves between PENDING, COMPLETE, and FAILED.
Security Model#
Every webhook request includes:X-Vortex-Signature — RSA-PSS signature of the raw request body, base64-encoded.
X-Vortex-Timestamp — Unix timestamp (seconds) of the request.
All webhook URLs must use HTTPS. Signatures are verified against the RSA-PSS 2048-bit public key returned by GET /v1/public-key.Registering A Webhook#
{
"url": "https://partner.example.com/vortex/webhook",
"quoteId": "quote_...",
"events": ["TRANSACTION_CREATED", "STATUS_CHANGE"]
}
The body must include exactly one of quoteId or sessionId. Use sessionId to subscribe to events from a Widget-hosted ramp instead of a partner-created quote.Store the returned webhook ID so you can delete it later.Webhook endpoints require a partner secret key. They do not accept Supabase Bearer tokens.Event Types#
TRANSACTION_CREATED#
Fired immediately after the ramp state is created (POST /v1/ramp/register).{
"eventType": "TRANSACTION_CREATED",
"timestamp": "2025-01-15T10:30:00.000Z",
"payload": {
"quoteId": "quote_...",
"transactionId": "tx_...",
"sessionId": "session_...",
"transactionStatus": "PENDING",
"transactionType": "BUY"
}
}
| Field | Description |
|---|
quoteId | Unique identifier for the quote. |
transactionId | Unique identifier for the ramp (rampId). |
sessionId | Widget session identifier if registered against a session. |
transactionStatus | Always "PENDING" for new transactions. |
transactionType | "BUY" (onramp) or "SELL" (offramp). |
STATUS_CHANGE#
Fired whenever the ramp's status changes during processing.{
"eventType": "STATUS_CHANGE",
"timestamp": "2025-01-15T10:35:00.000Z",
"payload": {
"quoteId": "quote_...",
"transactionId": "tx_...",
"sessionId": "session_...",
"transactionStatus": "COMPLETE",
"transactionType": "BUY"
}
}
PENDING — ramp is in progress.
COMPLETE — ramp completed successfully.
FAILED — ramp failed or timed out.
Retry Mechanism#
Vortex automatically retries failed webhook deliveries:Backoff: exponential (1s, 2s, 4s, 8s, 16s)
Timeout: 30 seconds per request
Auto-deactivation: after 5 consecutive failures, the webhook is disabled and must be re-registered.
Return 2xx quickly. Do heavy work asynchronously after acknowledging the request.Verification#
Fetch the current public key:Verify signatures using RSA-PSS with SHA-256. Reject requests that fail signature verification, are outside an acceptable timestamp window, contain malformed payloads, or do not match the expected event structure.Example: Bun + TypeScript Listener#
When To Still Poll#
Webhooks are preferable for reconciliation, back-office automation, and support workflows. Polling GET /v1/ramp/{id} is still useful for live user-facing status screens where you want sub-second updates without waiting for the next webhook delivery. GET /v1/ramp/{id}/errors returns the structured error log and is useful for support tooling.
Modified at 2026-05-19 08:03:57