Webhooks API
123hub sends outgoing webhooks to merchant callback URLs when payment or payout events occur. Merchants can configure callbacks through onboarding/dashboard flows, Backoffice operations, or per-paymentwebhook_url.
Event Types
Withdrawals use the same
payment.* callbacks as deposits and are identified by data.result.payment.destination: "out". payment.processing is a payment status value, not a currently emitted merchant callback event. Some account tooling may also expose balance.updated, merchant.updated, and webhook.test events outside the payment lifecycle.
Opt-in public support selectors are ticket.created, ticket.updated, ticket.status_changed, ticket.comment.created, ticket.reopened, refund.requested, refund.status_changed, and chargeback.created. They use the same delivery headers/retries but a minimal public-resource payload; see Support webhooks. Existing subscriptions are not expanded automatically.
Delivery Payload
Outgoing payment webhook deliveries use this envelope:_.
Delivery Headers
Use
X-Webhook-Signature-V3 when present. It binds replay metadata and the raw body. Use X-Webhook-Signature-V2 or X-Data-Hash only for backward-compatible verification.
Webhook create/rotation reveals a dedicated webhook-only secret once. Historical
API-compatible rows do not deliver until the webhook secret is explicitly rotated;
API-key rotation is independent. For a callback auto-created by
params.payment.webhook_url, derive the webhook secret as lowercase
HMAC-SHA256(apiSecret, "quadpay:merchant-webhook-signing:v1"), using the exact
test or production API secret that authenticated that payment create. The URL is
bound to that payment and never receives another payment’s events.
Signature Verification
Verify against the exact raw request body bytes. Do not parse and re-serialize JSON before hashing.Node.js
payload.data.result.payment.
Retry Policy
Webhook delivery succeeds on any HTTP 2xx response. Non-2xx responses, timeouts, network errors, oversized payloads, URL validation failures, or an open circuit breaker are treated as failures. Default webhook retry settings:
The retry delay uses exponential backoff with jitter:
Idempotency
Useid plus data.result.payment.status.status as a practical deduplication key. data.request_id is unique per generated callback body and should not be used as the business idempotency key.
Webhook Management
Legacy callback configuration routes under/api/v1/webhooks are no longer part of the public API. Configure merchant callback URLs through onboarding or Backoffice operations. Payment-level re-delivery remains available through the signed endpoint below.
Merchant Payment Webhook Resend
For payment-level re-delivery, merchants can also use the signed API endpoint:X-Data-Application-Id, X-Data-Hash and the
webhooks.update scope. X-Data-Timestamp plus X-Data-Nonce are an
optional pair; a partial pair is rejected. It is throttled to 10 requests per
minute. The JSON body is:
payment_id must equal the path parameter. Reuse operation_id only for an
exact retry of the same resend intent.
Without replay headers, X-Data-Hash remains
SHA512(raw JSON body + API secret). With both optional replay headers, the
signature payload is the exact UTF-8 concatenation below, followed by the raw
JSON body; X-Data-Hash is SHA512(payload + API secret):
Per-Payment Webhook URL
payment.in and payment.out accept params.payment.webhook_url. In production, use an absolute public HTTPS URL including the protocol. The system validates it at request time and again before delivery to reduce SSRF risk.
The first use of a new URL creates a webhook-only derived secret. Compute the
same lowercase hex value with
HMAC-SHA256(exactAuthenticatedApiSecret, "quadpay:merchant-webhook-signing:v1")
and use that derived value for callback verification.