Skip to main content

Payment lifecycle and webhooks

Hubpay tracks three related resources:

  • A payment request tracks whether the requested balance is unpaid, partly paid or fully paid.
  • Each payment tracks one card payment, bank transfer or crypto deposit through receipt and wallet credit.
  • An optional payout tracks a separate outbound transfer after a payment completes.
Crypto confirmation signal

For crypto integrations, use v1.collection.payment_request.payment.completed, then fetch the payment request and confirm that the matching payment has status COMPLETE.

v1.collection.payment_request.payment.received only confirms that the crypto deposit was confirmed on-chain. Sender verification, KYT, remitter screening, conversion, reconciliation and Hubpay wallet credit may still be outstanding.

States at a glance

ResourceAPI stateMeaning
Payment requestUNPAIDNo confirmed amount has been applied to the request
Payment requestPART_PAIDSome confirmed value has been applied, but a balance remains
Payment requestPAIDThe full requested value has been received or confirmed; individual payments may still be processing
Payment requestCANCELLEDThe request was cancelled by the user or after a payment was rejected
PaymentPENDINGPayment initiated, authorised, reported as sent or awaiting confirmation
PaymentRECEIVEDFunds were captured or confirmed by the payment rail; for crypto, compliance checks, conversion, reconciliation and wallet credit may still be in progress
PaymentCOMPLETEThe payment completed, all applicable crypto compliance gates cleared and your Hubpay wallet was credited
PaymentFAILEDThe payment failed or was rejected

A payment request can be PAID while an individual payment is still RECEIVED. This means the request balance is covered, while later processing such as conversion, reconciliation or wallet credit may still be in progress.

Webhook sequence by payment method

StepCardBank transferCryptoWebhook
Payment in progressCard authorisedCustomer reports transfer sentQueued immediately before payment.received when a confirmed deposit is processedv1.collection.payment_request.payment.pending
Funds observedCard capturedFunds received by HubpayDeposit confirmed on-chainv1.collection.payment_request.payment.received
Request balance updatedRequest becomes PAID or PART_PAIDRequest becomes PAID or PART_PAIDRequest becomes PAID or PART_PAIDv1.collection.payment_request.paid or .part_paid
Compliance and internal processingSender verification, KYT, remitter screening, conversion and settlement reconciliationNo additional public payment event; payment remains RECEIVED
Wallet creditFunds credited to Hubpay walletFunds credited to Hubpay walletProvider settlement reconciled and funds credited to Hubpay walletv1.collection.payment_request.payment.completed

These are lifecycle transitions, not a delivery-order guarantee. Webhook retries can arrive more than once or out of order. Verify the signature, deduplicate the event, and fetch current API state before changing your own records.

Crypto lifecycle

For crypto, the current backend queues payment.pending immediately before payment.received when it processes a provider-confirmed deposit. Do not use the crypto pending event as evidence that confirmation is still outstanding.

After on-chain confirmation, Hubpay verifies the sender, starts KYT where enabled and checks remitter screening. An internal compliance hold is exposed through the payment API as RECEIVED and does not produce a separate hold webhook. If a check rejects the crypto payment, the payment request can be cancelled and the payment is exposed as FAILED when queried.

The provider's conversion-executed and fiat-settlement callbacks are also internal processing stages. They do not emit a public payment webhook or change the public payment status. For crypto, use payment.completed plus status COMPLETE; this confirms the applicable compliance gates and settlement checks passed and the Hubpay wallet was credited.

For a full crypto payment, payment.received and payment_request.paid can arrive before payment.completed. For an underpayment, the request becomes PART_PAID; settlement can wait for the remaining amount or occur when the quote window expires. See simulating payments for the partial-payment rules.

  1. Receive the webhook and verify its HMAC signature against the raw request body.
  2. Deduplicate using the webhook event identifier.
  3. Read data.paymentRequestId and data.paymentId from the event.
  4. Fetch GET /v1/collections/payment-requests/{id}.
  5. Find the matching payment and check the state required by your workflow.
  6. Apply the business action once, then return 2xx promptly.

For a crypto success workflow, require all three checks:

  • The event is v1.collection.payment_request.payment.completed.
  • The event signature is valid.
  • The matching payment returned by the API has status COMPLETE.

Do not use the browser redirect, checkout success screen, payment_request.paid, payment.received or payment status RECEIVED as final crypto confirmation.

Choose the right signal

Business actionRecommended signal
Show crypto processing progresspayment.pending or payment.received; do not treat either as final confirmation
Show the requested balance is coveredpayment_request.paid plus current API state; individual payments may still be processing
Confirm a crypto paymentpayment.completed plus payment status COMPLETE
Confirm funds are available in the Hubpay walletpayment.completed plus payment status COMPLETE
Track an automatic payout to a beneficiarypayment.payout.* events; see Payouts

Detailed references