Skip to main content

Documentation Index

Fetch the complete documentation index at: https://waffo.com/docs/llms.txt

Use this file to discover all available pages before exploring further.

Event types

eventTypeDescription
PAYMENT_NOTIFICATIONPayment completed or failed
REFUND_NOTIFICATIONRefund completed or failed
TOKENIZATION_NOTIFICATIONToken generated, token status changed, or card information updated
SUBSCRIPTION_STATUS_NOTIFICATIONSubscription status change (activation, cancellation, etc.; also used for subscription billing events)
SUBSCRIPTION_PERIOD_CHANGED_NOTIFICATIONSubscription period change
SUBSCRIPTION_CHANGE_NOTIFICATIONSubscription change (upgrade/downgrade) completed

Common structure

All Webhooks use the same request structure:
POST {notifyUrl}
Content-Type: application/json
X-SIGNATURE: {Waffo private-key signature}

PAYMENT_NOTIFICATION

Sent after the payment is completed.
{
  "eventType": "PAYMENT_NOTIFICATION",
  "acquiringOrderId": "ACQ123456",
  "merchantOrderId": "ORDER123",
  "paymentRequestId": "REQ123",
  "orderStatus": "PAY_SUCCESS",
  "orderAmount": "100.00",
  "orderCurrency": "USD",
  "finalDealAmount": "100.00"
}

REFUND_NOTIFICATION

Sent after the refund is completed, and delivered to the refundNotifyUrl specified when creating the refund.
{
  "eventType": "REFUND_NOTIFICATION",
  "acquiringRefundOrderId": "REF123456",
  "refundRequestId": "REFUND_REQ123",
  "refundStatus": "ORDER_FULLY_REFUNDED",
  "refundAmount": "100.00"
}

TOKENIZATION_NOTIFICATION

Sent when tokenization is completed, the token status changes, or token card information is updated. Waffo sends this notification to the notifyUrl passed when calling Generate token.
{
  "eventType": "TOKENIZATION_NOTIFICATION",
  "result": {
    "tokenRequestId": "202510111010050001",
    "tokenId": "tok_xxxxxxxxxxxx",
    "tokenType": "CARD",
    "tokenStatus": "UNVERIFIED",
    "tokenData": {
      "maskedCardInfo": "481852******0147",
      "cardHolderName": "Zhang san",
      "cardExpiry": "01/2030",
      "cardBin": "481852",
      "cardScheme": "VISA",
      "cardType": "CREDIT_CARD",
      "cardIssuerName": "INTL HDQTRS-CENTER OWNED",
      "cardIssueCountryCode": "RUS"
    },
    "billingAddress": {
      "countryCode": "USA",
      "region": "CA",
      "city": "Cupertino",
      "postalCode": "95014",
      "address": "One Apple Park Way"
    },
    "merchantUserId": "merchant-user-001",
    "merchantInfo": {
      "merchantId": "your_merchant_id",
      "subMerchantId": ""
    }
  }
}
FieldDescription
tokenRequestIdRequest ID passed by the merchant when starting tokenization. This field may be absent when the status change is triggered by Waffo
tokenIdToken ID. Store it securely and use it for later token payments
tokenTypeToken type. Currently CARD
tokenStatusToken status: UNVERIFIED, VERIFIED, EXPIRED, or SUSPENDED
tokenDataCard summary, including masked card number, expiry, BIN, card scheme, card type, issuer, and issuing country
billingAddressCardholder billing address
merchantUserIdMerchant-side user ID
merchantInfoMerchant information

SUBSCRIPTION_STATUS_NOTIFICATION

Sent when the subscription status changes (including activation, cancellation, billing results, etc.).
{
  "eventType": "SUBSCRIPTION_STATUS_NOTIFICATION",
  "subscriptionId": "SUB123456",
  "subscriptionStatus": "ACTIVE"
}
The SDK provides two handlers:
  • onSubscriptionStatus() — handle this event directly
  • onSubscriptionPayment() — fallback handling when onSubscriptionStatus is not registered

SUBSCRIPTION_PERIOD_CHANGED_NOTIFICATION

Sent when the subscription period reaches a terminal state, used to track renewal results.
{
  "eventType": "SUBSCRIPTION_PERIOD_CHANGED_NOTIFICATION",
  "subscriptionId": "SUB123456",
  "period": "3",
  "orderStatus": "PAY_SUCCESS"
}

SUBSCRIPTION_CHANGE_NOTIFICATION

Sent when a subscription change (upgrade/downgrade) is completed.
{
  "eventType": "SUBSCRIPTION_CHANGE_NOTIFICATION",
  "result": {
    "subscriptionRequest": "new-sub-req-001",
    "originSubscriptionRequest": "orig-sub-req-001",
    "subscriptionId": "waffo-sub-12345",
    "subscriptionChangeStatus": "SUCCESS",
    "subscriptionAction": "UPGRADE",
    "remainingAmount": "50.00",
    "currency": "HKD"
  }
}
subscriptionChangeStatusDescription
SUCCESSChange succeeded
CLOSEDChange failed / closed

Merchant response

All Webhooks must return HTTP 200, and the response body must be {"message":"success"}, and must include the X-SIGNATURE response header (sign the response body using the merchant private key).
Waffo validates both the HTTP status code and the response body. If the response format is incorrect or the signature is missing, Waffo will treat the delivery as failed and retry.
The SDK’s handleWebhook() method automatically performs signature verification, event routing, and response signing:
const result = await waffo.webhook().handleWebhook(body, signature);
res.setHeader('X-SIGNATURE', result.responseSignature);
res.status(200).send(result.responseBody);

Manual response

If you are not using the SDK, the response body must be one of the following:
  • {"message":"success"} — processed successfully
  • {"message":"failed"} — processing failed; Waffo will retry
  • {"message":"unknown"} — status unknown; Waffo will retry
Retry policy: When failed or unknown is returned, Waffo will retry up to 8 times (including the initial attempt), with intervals increasing from 30 seconds to 8 hours. See Retries and failure recovery for details.

Subscription notification selection guide

Subscription scenarios involve three types of notifications. Subscribe to the ones you need:
EventWhen it firesBest for
SUBSCRIPTION_STATUS_NOTIFICATIONSubscription master status changes (activation, cancellation, closure)Managing the subscription lifecycle: granting or revoking user entitlements
SUBSCRIPTION_PERIOD_CHANGED_NOTIFICATIONTerminal state of each renewal period (no notifications during retries — only the final outcome)Tracking the final result of each billing period without caring about intermediate retry attempts
PAYMENT_NOTIFICATIONEvery payment attempt (first period + every retry of subsequent periods)Getting detailed failure reasons, payment timestamps, and other per-attempt details
Recommended combinations:
  • Minimal integration: Subscribe to SUBSCRIPTION_STATUS_NOTIFICATION + SUBSCRIPTION_PERIOD_CHANGED_NOTIFICATION
  • Full integration: Subscribe to all three — use PAYMENT_NOTIFICATION to capture detailed failure reasons for every retry attempt