> ## 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.

# Integration acceptance criteria

> Acceptance criteria for merchants after completing Waffo integration, covering functional tests, exception handling, parameter requirements, and data integrity.

After completing integration, you must pass the following acceptance criteria in the sandbox environment before going live.

## Acceptance materials

After API integration, download and complete the matching acceptance template:

* <a href="/files/developer-docs/acceptance/one-time-payment-acceptance-cases.json" data-waffo-download-file="one-time-payment-acceptance-cases.xlsx">One-time payment acceptance template</a>
* <a href="/files/developer-docs/acceptance/subscription-acceptance-cases.json" data-waffo-download-file="subscription-acceptance-cases.xlsx">Subscription acceptance template</a>

Submit the completed acceptance result to the Waffo technical support group. Waffo will review the executed cases, merchant transaction IDs, Webhook handling results, and exception-handling logic.

> **Additional note**: Some exception cases in the acceptance templates are reproduced with sandbox special amounts. If you pass these amounts in the sandbox environment, the API intentionally returns the matching error. See [Sandbox simulator](/en/developer-docs/tools-and-references/developer-tools/sandbox-simulator) for the full list.

## Functional tests

### Payments (required)

* Payment success: create an order → complete payment → order status updated → business logic executes correctly
* Payment failure: use a failure test card → order status updated → business logic **not executed**
* Webhook receipt: success and failure notifications are handled correctly
* Webhook idempotency: when the same notification is received more than once, business logic executes only once

### Refund (if integrated)

* Refund success: initiate a refund on a paid order → status updated correctly
* Refund notification: Webhook arrives and status is updated correctly

### Subscription (if integrated)

* First period payment success → subscription activated
* Renewal simulation: trigger next period billing via the sandbox management page → business logic handled correctly
* Cancel subscription → status updated correctly

***

## One-time payment acceptance cases

Complete these cases according to your actual integration scope, and record the result and merchant transaction ID in the template.

### Required cases

* Create an order and simulate payment success; verify `notifyUrl` receives the terminal success notification and that `paymentRequestId`, `orderCurrency`, and `orderAmount` match the merchant order.
* Create an order and simulate payment failure; verify `notifyUrl` receives the terminal failure notification and that order information matches.
* Query a successful payment and confirm `orderStatus = PAY_SUCCESS`.
* Query a failed payment and confirm `orderStatus = ORDER_CLOSE`.
* Process payment success notifications only after signature verification passes.
* Do not fulfill goods or grant entitlements on payment failure.
* If notification signature verification fails, do not process the notification; query the order status instead.

### Exception cases

* Channel rejection: simulate `C0005 Payment Channel Rejection`.
* Idempotency conflict: reuse the same `paymentRequestId` with a different amount or currency and verify `A0011`.
* System unavailable: simulate `C0001 System Error`.
* Unknown Status: simulate `E0001 Unknown Status`; do not close the order yourself, and wait for inquiry results or Webhook notification.

### Conditional cases

* If cancel is integrated, cancel before payment and verify `ORDER_CLOSE`.
* If cancel is integrated, cancel after successful payment and verify `A0013`.
* If refund is integrated, verify `refundRequestId`, `refundAmount`, and refund status after a successful refund.
* If refund inquiry or refund notification is integrated, verify in-progress, full refund, partial refund, and refund failure states.

## Subscription acceptance cases

Complete these cases according to your actual integration scope, and record the result, merchant transaction ID, and merchant transaction time in the template.

### Required cases

* Create a subscription and simulate first payment success; verify subscription status notification and subscription payment notification are both received.
* Create a subscription and simulate first payment failure; verify the failure notification and failed redirect.
* Query an unpaid subscription and guide the user through `subscriptionAction` or `orderAction`.
* Query a successful subscription and confirm the status is `ACTIVE`.
* Query a failed subscription and confirm it is in a closed terminal state.
* After verifying the subscription status notification signature, match `subscriptionRequest`, amount, currency, period, and trial-period fields to merchant records.
* After verifying the subscription payment notification signature, match the payment order to the correct `subscriptionRequest` and `period`.
* If notification signature verification fails, do not update local state; query the real status instead.

### Renewal and cancellation

* Simulate next-period payment success from the subscription management page and verify the renewal payment notification.
* Simulate next-period payment failure from the subscription management page and verify the failed renewal notification.
* If merchant-side cancellation is integrated, cancel and verify `MERCHANT_CANCELLED`.
* If channel-side cancellation is supported, handle `CHANNEL_CANCELLED`.

### Exception cases

* Subscription channel rejection: simulate `C0005 Payment Channel Rejection`.
* Idempotency conflict: reuse the same request ID with different amount or currency and verify `A0011`.
* System unavailable: simulate `C0001 System Error`.
* Unknown Status: simulate `E0001 Unknown Status`; do not close the subscription yourself, and wait for inquiry results or Webhook notification.
* If refund is reused for subscriptions, validate refund, refund inquiry, and refund notification using the one-time payment refund rules.

***

## Payment method coverage

You do not need to test every contracted payment method individually. Select representatives by type:

| Rule                                           | Example                                         |
| ---------------------------------------------- | ----------------------------------------------- |
| At least 1 card                                | CC\_VISA                                        |
| At least 1 per country per type                | DANA or ShopeePay for Indonesia e-wallets       |
| Methods with special parameters must be tested | OVO (requires phone number), PIX (requires CPF) |
| At least 1 VA                                  | BCA\_VA                                         |
| Apple Pay / Google Pay                         | Must be tested manually on a real device        |

***

## Exception handling requirements

Waffo will check your handling logic for these exception scenarios during acceptance:

| Scenario                               | What you need to do                                                                                                             |
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| Unknown Status (E0001)                 | **Do not close the order**. Retry with the same parameters; if still failing, wait for the query result or Webhook notification |
| Channel rejection / system unavailable | Show a user-friendly message and guide the user to retry or switch payment methods                                              |
| Webhook signature verification failure | Do not process the notification; get the correct status via the query API                                                       |
| Idempotency conflict (A0011)           | Ensure each request uses an independently generated ID (paymentRequestId / refundRequestId / subscriptionRequest)               |

***

## Parameter requirements

| Field                   | Requirement                                                                                      |
| ----------------------- | ------------------------------------------------------------------------------------------------ |
| Amount                  | String type (e.g., `"100.00"`), not floating-point                                               |
| `orderDescription`      | Provide an accurate description; do not use "test" placeholders                                  |
| `goodsName`             | Required                                                                                         |
| `goodsUrl` or `appName` | Provide at least one (compliance and risk control requirement)                                   |
| `userEmail`             | Real email or `userId@examples.com` format (avoid "test" characters, avoid sharing across users) |
| Time fields             | UTC+0, ending with `Z`, milliseconds no more than 3 digits                                       |

***

## Data integrity

* `paymentRequestId` is persisted **before** the API call (for recovery via query in case of network timeout)
* `acquiringOrderID` is stored after payment success
* Redirect URLs (successRedirectUrl / failedRedirectUrl) are set
