Merchant payment callbacks (outbound)
When a webhook exists for the payment's wallet and network, Apex POSTs JSON from the payment service to your configured URLs. This is separate from the inbound webhook REST API on Apex (list, create, update, delete).
URLs
host+success_path— resolved to an absolute URL (same rules as a browser:hostis the origin,success_pathis appended or resolved relative to it).host+error_path— same resolution for error callbacks.
Which path is used depends on the callback type (see table below): success-style events use success_path; failure-style events use error_path.
Authentication
If auth_type is basic, Apex sends Authorization: Basic … when username/password are set. If token, Apex sends Authorization: Bearer <auth_token> (or the client library equivalent). Unauthenticated POSTs are used when credentials are not configured.
Request body (contract)
All outbound payment webhooks use the same envelope:
{
"type": "payment_deposited",
"payment": {
"id": "…",
"external_id": "…",
"node_id": "…",
"wallet_id": "…",
"network_id": "…",
"member_id": "…",
"currency_id": "…",
"deal_id": 0,
"price": 0,
"paid_price": 0,
"payment_method": "web3",
"payment_group": "product",
"payment_address": "…",
"status": "blockchain_deposited",
"transaction_hash": "…",
"metadata": "…",
"completed_at": "2026-01-01T00:00:00Z",
"diamond_address": "…",
"created_at": "2026-01-01T00:00:00Z"
}
}
type(string): identifies the event (see table). The same value is used internally for delivery logging / retries per stream.payment: snapshot of the payment at send time (optional fields may be omitted when empty).
Content-Type is application/json.
Callback type and URL
type | HTTP target | When |
|---|---|---|
payment_deposited | success | On-chain deposit detected for the deal; payment reaches deposited state (cron-driven). |
payment_create_failed | error | Custody / chain create payment failed after submission (create_payment wallet tx error). |
payment_cancelled | success | Custody cancel payment completed on chain. |
payment_cancel_failed | error | Custody cancel payment failed. |
payment_refunded | success | Custody refund payment completed on chain. |
payment_refund_failed | error | Custody refund payment failed. |
payment_refund_init_failed | error | Refund flow failed before custody (e.g. validation / setup in the refund consumer). |
There is no merchant webhook when create payment succeeds on chain (blockchain_created only). The “money received” callback is payment_deposited after the deposit is observed, to avoid duplicate success notifications.
Retries
Failed deliveries (non-2xx or transport error) are retried automatically up to 5 attempts per (webhook_id, payment_id, type). A successful payment_deposited does not block a later payment_cancelled or payment_refunded for the same payment.
Idempotency
Your endpoint should treat callbacks as at-least-once: the same type may be retried until a 2xx response is returned. Use payment.id plus type (and optionally payment.status / transaction_hash) to deduplicate side effects.