Skip to content

Merchant Webhooks

Merchant webhooks receive business event notifications sent by FuturePay UCard.

Integration Steps

  1. Sign in to the FuturePay merchant console, enter your Webhook URL in UCard's Tenant Callback Configuration, and enable it. Only one callback URL can be enabled per merchant at a time.
  2. Expose a publicly accessible HTTP endpoint at that URL to receive POST application/json requests from FuturePay.
  3. Verify the platform signature using the request headers and the unmodified raw request body.
  4. Read eventType in the payload and dispatch to the appropriate business handler.
  5. Use eventNo for idempotency and return HTTP 2xx after successful receipt.

All supported UCard events are sent to the same enabled Webhook URL. Do not configure separate URLs for individual events; dispatch by eventType in your receiving service.

Legacy Event Compatibility

New events use schemaVersion: 2, and eventType identifies only the business scenario. To preserve the original request body, signature, and replay idempotency, replays of historical PENDING/DEAD events may still contain status-based eventType values; legacy card withdrawal events may omit eventType. Continue to use eventNo for idempotency and retain parsing support for historical formats.

Callback Request

FuturePay sends requests as follows:

ItemDescription
HTTP methodPOST
Content-Typeapplication/json
Request URLThe enabled Webhook URL in the merchant console
Request timeout10 seconds
Successful responseAny HTTP 2xx

HTTP 3xx, 4xx, and 5xx responses, connection errors, and timeouts are treated as delivery failures. Use HTTPS where possible, and verify the signature and reliably persist the event within 10 seconds. Lengthy business processing can run asynchronously after persistence.

Signature Headers

Each webhook request includes these headers:

HeaderDescription
X-FP-TimestampMillisecond timestamp when FuturePay generated the signature.
X-FP-Api-KeyFuturePay Ed25519 public key in hex.
X-FP-SignatureFuturePay signature in hex.
X-FP-Body-HashSHA-256 hash of the raw request body in hex.

The signing string is:

text
X-FP-Timestamp|RAW_CALLBACK_BODY

Use the raw request body as received for verification. Do not parse and reserialize the JSON first. See Signing and Authentication for the full algorithm and key details.

Common Fields

FieldTypeDescription
schemaVersionintegerPayload schema version. Always 2 for new events.
eventNostringUnique webhook event number and merchant idempotency key. Unchanged by automatic retries or manual replays.
eventTypestringBusiness scenario used to select the appropriate handler; does not encode success or failure.
statusstringBusiness status for the current scenario. Its meaning depends on the event.
failCodestringFailure code; empty when no failure information is available.
failMessagestringFailure reason; empty when no failure information is available.
occurredTimestringEvent time in yyyy-MM-dd HH:mm:ss format.

Events carry their own business fields. Identify the event type before parsing its structure; do not assume all event payloads have the same fields.

Event Types

eventTypeDescription
CARD_OPENINGCard issuance; use status to determine success or failure.
CARD_RECHARGECard recharge; use status to determine success or failure.
CARD_WITHDRAWALCard withdrawal; use status to determine success or failure.
CARD_CONSUMPTIONCard purchase; use status, feeCharged, and failure fields to determine transaction and fee outcomes.
CARD_MONTHLYMonthly card fee; use status to determine whether collection succeeded or failed.

Event Business Fields

In addition to the common fields, events include the following business fields:

eventTypestatus ValuesBusiness Fields
CARD_OPENINGSUCCESS or FAILEDcardOrderNo, requestNo, feeAmount, assetCode, cardId, cardAccountId, last4, expiryMonth, expiryYear
CARD_RECHARGESUCCESS or FAILEDorderNo, requestNo, cardId, amount, currency, feeAmount, feeCurrency
CARD_WITHDRAWALSUCCESS or FAILEDorderNo, requestNo, cardId, amount, feeAmount, platformFeeAmount, tenantFeeAmount, totalAmount, currency
CARD_CONSUMPTIONFinal card transaction status, such as SUCCESS, COMPLETED, SETTLED, FAILED, REJECTED, CANCELLED, or CANCELEDproviderTransactionId, cardId, cardAccountId, amount, assetCode, countryCode, feeCharged, transactionFee, authorizationFee, totalFee
CARD_MONTHLYSUCCESS or FAILEDcardId, billingMonth, amount, assetCode

For CARD_CONSUMPTION, status describes the card transaction. Determine whether fee processing succeeded using feeCharged, totalFee, failCode, and failMessage together.

For CARD_WITHDRAWAL, both amount and totalAmount currently represent the total amount deducted for the withdrawal: principal plus fees.

Card Purchase Notification Example

The card purchase notification uses countryCode for the country or region of the purchase:

json
{
  "schemaVersion": 2,
  "eventNo": "UCCB202608040001",
  "eventType": "CARD_CONSUMPTION",
  "providerTransactionId": "TXN202608040001",
  "cardId": "CARD001",
  "cardAccountId": "ACCOUNT001",
  "amount": "100.00",
  "assetCode": "USD",
  "countryCode": "US",
  "feeCharged": true,
  "transactionFee": "1.00",
  "authorizationFee": "0.00",
  "totalFee": "1.00",
  "status": "SUCCESS",
  "failCode": null,
  "failMessage": null,
  "occurredTime": "2026-08-04 12:00:00"
}

Idempotency

FuturePay uses at-least-once delivery, so the same event may be sent multiple times. Use eventNo as the unique idempotency key. Do not deduplicate solely by eventType, order number, or transaction number.

Recommended processing order:

  1. Verify the platform signature.
  2. Insert eventNo into your database with a unique constraint.
  3. If eventNo already exists, return HTTP 2xx immediately.
  4. Process the event according to eventType.
  5. Commit the local transaction, then return HTTP 2xx.

Returning 2xx before asynchronously persisting the event can lose notifications if the process crashes. If business processing is lengthy, first persist the original event reliably, then consume it asynchronously.

Retry Rules

  • After the first delivery failure, FuturePay continues scanning pending events and retrying delivery.
  • Each event receives at most 3 automatic attempts.
  • A non-2xx response, connection error, or 10-second timeout consumes one attempt.
  • Automatic retries and manual platform replays preserve the original eventNo and request body.
  • After all three automatic attempts fail, automatic delivery stops. Operators may still replay the event manually, so merchants must not disable idempotency protection after any time window.
  • Do not rely on a fixed retry interval or assume events arrive strictly in occurrence order.

Integration Checklist

  • The correct Webhook URL is configured and enabled in the merchant console.
  • The endpoint accepts POST application/json and responds within 10 seconds.
  • X-FP-* signatures are verified against the raw request body.
  • Business handling is dispatched by scenario-based eventType, with support for historical status-based event formats.
  • The database enforces uniqueness for eventNo.
  • Duplicate events return HTTP 2xx without repeating fund movements or order status changes.