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

# Frequently asked questions (FAQ)

> Common questions and answers about Waffo integration, payments, and security.

## Integration

<AccordionGroup>
  <Accordion title="Which integration method is recommended?">
    If you want to go live quickly, use **Checkout integration**. You don't need to handle sensitive card data and the integration effort is minimal.
  </Accordion>

  <Accordion title="What is the difference between ONE_TIME_PAYMENT and DIRECT_PAYMENT?">
    `DIRECT_PAYMENT` is an early product that is largely unused today. New merchants should integrate `ONE_TIME_PAYMENT` directly.

    At the system level, the two are identical. The difference is in the business relationship:

    * **ONE\_TIME\_PAYMENT**: Waffo acts as PSP, providing full acquiring services (information flow + fund settlement)
    * **DIRECT\_PAYMENT**: Waffo acts as ISV/PG, providing only system connectivity (no fund handling)
  </Accordion>

  <Accordion title="Why does the amount need to be a String type?">
    To avoid floating-point precision issues. For example, `0.1 + 0.2 = 0.30000000000000004`, which is unacceptable in financial scenarios.
  </Accordion>

  <Accordion title="What are the currency precision requirements?">
    * **Same-currency orders**: Most currencies require 2 decimal places per ISO 4217, but `IDR`, `COP`, `KES`, and `TWD` **must not have decimals**
    * **Cross-currency orders**: All currency amounts must conform to ISO 4217 precision, with no exceptions
  </Accordion>

  <Accordion title="How do I test Webhooks locally?">
    Use a tunneling tool such as cloudflared or ngrok to expose your local port as a public URL.
  </Accordion>
</AccordionGroup>

## Parameters

<AccordionGroup>
  <Accordion title="How should I pass payMethodType and payMethodName?">
    * **Omit both**: The user selects a payment method on the Waffo checkout page
    * **Card payments**: Pass `payMethodType="CREDITCARD,DEBITCARD"` and omit `payMethodName`. Waffo automatically determines the card network from the card BIN the user enters, supporting Visa/Mastercard and credit/debit cards in a single order
    * **VA (virtual account)**: Pass `payMethodType="VA"` and omit `payMethodName`; the user selects a bank on the checkout page
    * **Specify a particular method**: Pass both `payMethodType` and `payMethodName`. You can look up the exact values on the Payin page in the Portal

    For detailed parameter rules, see [Cashier integration - Customization options](/en/developer-docs/integration/checkout/customization).
  </Accordion>

  <Accordion title="Can I omit userEmail?">
    Yes. If you have not collected the user's email, you have two options:

    1. Send a fixed-format value such as `userId@examples.com` (replace with the actual userId)
    2. Contact Waffo to have Waffo overwrite it to `userId@examples.com` format on your behalf (requires merchant authorization)

    > After going live, passing the user's real email is recommended. Avoid using strings like `test` or reusing the same email across multiple users, as this may trigger risk controls.
  </Accordion>

  <Accordion title="Should I pass orderExpiredAt?">
    It is optional. The field controls the time window within which the user can submit an order on the checkout page (must be UTC+0). Once the order is submitted to the payment channel, the expiry is controlled by the payment method itself. A small number of payment methods support passing a channel-side expiry time; check the Payin page in the Portal for details.
  </Accordion>

  <Accordion title="What is the difference between same-currency and cross-currency orders?">
    * **Same-currency**: The merchant's pricing currency matches the user's local currency (e.g., IDR pricing → Indonesian user pays in IDR)
    * **Cross-currency**: The merchant's pricing currency differs from the user's payment currency (e.g., USD pricing → Indonesian user pays in IDR via DANA)

    Cross-currency orders require passing `payMethodCountry` when either `payMethodType` or `payMethodName` is not specified. `userCurrency` is optional.
  </Accordion>

  <Accordion title="When should I pass payMethodCountry?">
    Pass it when you want the checkout to display only the payment methods of a **specific country**. If omitted, all available payment methods across all countries in the merchant's contract are shown.

    * **Global cards** (CREDITCARD/DEBITCARD): **Do not pass** this field—global cards do not belong to any specific country.

    For detailed parameter rules, see [Cashier integration - Customization options](/en/developer-docs/integration/checkout/customization).
  </Accordion>
</AccordionGroup>

## Payments

<AccordionGroup>
  <Accordion title="Which should I use, webUrl or deeplinkUrl from orderAction?">
    Determine based on `orderAction.actionType`:

    * `actionType = "WEB"` → use `webUrl`
    * `actionType = "DEEPLINK"` → use `deeplinkUrl`

    In most cases only `webUrl` is present. If you pass `userTerminal=APP`, some wallet payment methods that require external authorization return a deeplink.

    > In the sandbox, deeplinks cannot launch real wallet apps because a simulator is used. Verify this behavior in production.
  </Accordion>

  <Accordion title="What should I do if the order creation returns orderStatus = AUTHORIZATION_REQUIRED?">
    Redirect the user to the external authorization page. The URL comes from `orderAction`; use `webUrl` or `deeplinkUrl` based on `actionType`.
  </Accordion>

  <Accordion title="What should I do if I receive an UnknownStatus exception?">
    This exception occurs because of a network timeout when calling the payment channel—it is unclear whether the order was created successfully.

    * **When creating an order**: If you can confirm the user cannot complete payment under the error condition (e.g., payment methods that require returning a checkout URL), you may abandon the order.
    * **When refunding**: You **must** retry with the same `refundRequestId`. Do not abandon the request.

    See [Error handling](/en/developer-docs/core-concepts/error-handling).
  </Accordion>

  <Accordion title="Why do some sandbox amounts immediately return C0005, C0001, or E0001?">
    This is expected behavior for sandbox acceptance and exception testing. The current acceptance templates use a set of special amounts to intentionally trigger channel rejection, system unavailable, and Unknown Status responses.

    * If you only want to test the normal success/failure flow, avoid these amounts
    * If you want to reproduce a specific exception, use the matching amount from [Sandbox simulator](/en/developer-docs/tools-and-references/developer-tools/sandbox-simulator)
    * `A0011` and refund `A0003` are not triggered by special amounts. They are triggered by request parameter combinations
  </Accordion>

  <Accordion title="The user paid successfully but I didn't receive a Webhook—what should I do?">
    1. Verify that `notifyUrl` is HTTPS and publicly reachable
    2. Verify that the callback port is 80 or 443 (Waffo production only accepts standard ports)
    3. Verify that the response body is `{"message": "success"}` and Content-Type is `application/json`
    4. Verify that the response includes the `X-SIGNATURE` header
    5. Proactively call the inquiry API to get the latest status
    6. If you still don't receive it, contact Waffo technical support
  </Accordion>

  <Accordion title="Is the inquiry API required?">
    Strongly recommended. Use cases:

    * Query proactively when the user lands on a success/failure page to give the smoothest experience
    * Retrieve the result for historical orders
    * Fall back to the inquiry API when Webhook signature verification fails
  </Accordion>

  <Accordion title="Can I use multiple payment methods at the same time?">
    If you do not specify `payMethodType` / `payMethodName`, the checkout displays all available payment methods for the user to choose from.
  </Accordion>
</AccordionGroup>

## Signature & security

<AccordionGroup>
  <Accordion title="What are the common reasons for signature verification failures?">
    1. **Incorrect private key format**: The key must be in PKCS#8 format
    2. **Incorrect signing content**: The entire HTTP body must be signed; you cannot sign only selected fields
  </Accordion>

  <Accordion title="What are the minimum requirements for RSA keys?">
    A 2048-bit RSA key pair using the SHA256WithRSA (RSASSA-PKCS1-v1\_5 + SHA-256) signature algorithm.
  </Accordion>

  <Accordion title="Can the sandbox and production environments use the same set of keys?">
    Not recommended. Sandbox and production should use different API keys and RSA key pairs.
  </Accordion>
</AccordionGroup>

## App integration

<AccordionGroup>
  <Accordion title="What should I pay attention to when integrating the checkout in a merchant App?">
    * Confirm that the App and WebView allow opening external Apps or external browser pages
    * Confirm that the App and WebView support download, copy, and long-press save behavior. QR, OTC, and bank-transfer style payment methods may depend on these capabilities
    * Confirm that query parameters are preserved when URLs are passed between the native App and WebView
    * When loading via WebView, set `userTerminal` to `APP`
    * For detailed limitations, see [Payment method integration notes](/en/developer-docs/tools-and-references/references/payment-method-integration-notes)
  </Accordion>

  <Accordion title="Can merchants integrate Google Pay / Apple Pay on their own?">
    Not recommended. Use the GP/AP capabilities built into the Waffo checkout directly.

    | Comparison                              | Using Waffo checkout | Self-integration    |
    | --------------------------------------- | -------------------- | ------------------- |
    | GP/AP developer account                 | Not required         | Required            |
    | Domain registration and verification    | Required             | Required            |
    | Managing encryption certificates/keys   | Handled by Waffo     | Managed by merchant |
    | Server-side token processing/decryption | Handled by Waffo     | Managed by merchant |
    | PCI DSS compliance                      | Not required         | May be required     |
    | Checkout UI                             | Provided by Waffo    | Built by merchant   |
    | **Integration complexity**              | **Low**              | **High**            |

    If you have a specific requirement to self-integrate, contact Waffo technical support for a detailed integration guide.
  </Accordion>

  <Accordion title="Does PayMe payment launch the App?">
    Yes, it launches the PayMe App. If the user does not have it installed, they will be prompted to download it.
  </Accordion>
</AccordionGroup>
