# Alternative payment methods (APM)

Alternative payment methods (APMs) are the local, non-card ways buyers pay in their own
market — Bancontact in Belgium, Multibanco and MB WAY in Portugal, Wero in Belgium, Germany,
and France, and Swish in Sweden. Fynex offers them through a single payment provider that
fronts all of these schemes, on a dedicated payment rail (`apm`) that is distinct from the
`card` rail that carries card, Apple Pay, and Google Pay.

APMs are a sibling to Apple Pay and Google Pay in that they are wallet-like, buyer-initiated
methods you surface at checkout — but they are **architecturally different**. There is no
card token to decrypt and no card payload to forward. Most methods send the buyer to the
scheme (a bank-selection page, an app handoff, or a QR code) to authorize. Multibanco can
instead return an Entity and Reference that your own checkout renders for the buyer.

Fynex accepts APMs two ways:

- **Server-to-server API** — call `POST /payments-api/v1/initialize-payment` with
  `paymentType: "apm"` and the APM instrument from your own backend. Follow the redirect
  action Fynex returns, or render the structured payment instructions returned for
  Multibanco. Bearer-authenticated, the same endpoint used for card / Apple Pay / Google Pay.
  See [Server-to-server API](#server-to-server-api) below.
- **Fynex-hosted checkout** — create a checkout session as you would for a card checkout, and
  the Fynex-hosted page renders whichever APM tiles are available; the redirect handshake
  happens inside that page. See [Hosted checkout](#hosted-checkout) below.

Both paths use the same asynchronous-settlement behavior. Redirect flows also converge on
the same Fynex-hosted return step.

## Instruments and availability

Five instruments are supported. Each is only offered for the currency (and, where the scheme
is country-bound, country) combinations the provider actually supports it on:

| Instrument | Wire value | Currency | Country | Notes |
|------------|-----------|----------|---------|-------|
| Bancontact | `bancontact` | `EUR` | `BE` | Belgium's domestic card/bank scheme. |
| Multibanco | `multibanco` | `EUR` | `PT` | Portuguese reference-number / voucher payment. |
| MB WAY | `mbway` | `EUR` | `PT` | Portuguese mobile-app payment. Offered alongside Multibanco for `EUR`/`PT` — the two cannot be told apart by currency/country, so the buyer picks between them at checkout. |
| Wero | `wero` | `EUR` | `BE`, `DE`, `FR` | European account-to-account wallet. Requests outside these three countries are rejected before routing. |
| Swish | `swish` | `SEK` | `SE` | Swedish mobile payment. |

A `EUR`/`BE` checkout therefore offers Bancontact **and** Wero; `EUR`/`DE` and `EUR`/`FR`
offer Wero; `EUR`/`PT` offers Multibanco and MB WAY; a `SEK`/`SE` checkout offers Swish.
Wero is not offered for other EUR countries, including Italy.

> [!NOTE]
> This currency/country matrix is the *ceiling* of what a checkout can show. The actual set a
> given buyer sees is narrower — it is also gated on your account being routable for that
> method. See [How hosted-checkout availability is decided](#how-hosted-checkout-availability-is-decided).

### How the buyer completes each method

The buyer action differs by method and integration style. It matters especially when you test:

- **Bancontact** completes on the redirect page itself — the buyer authorizes there and comes
  straight back.
- **MB WAY** completes on the redirect page by default. Server-to-server, you can instead keep
  the buyer on your own checkout: send `apmData.phone` and the authorization is pushed to that
  number's MB WAY app, so there is nothing to redirect to. See
  [Keeping the buyer on your checkout with MB WAY](#keeping-the-buyer-on-your-checkout-with-mb-way).
- **Multibanco** server-to-server initiation can return `paymentInstructions` containing an
  Entity and Reference. Render both with the response's top-level amount and currency; the
  buyer completes the payment through Portuguese online banking or an ATM. Fynex-hosted
  checkout continues to handle the provider redirect flow for you.
- **Wero hands off to a Wero code / QR flow.** In live, the buyer approves in their Wero
  app. In sandbox, you can complete the flow with the Wero UAT test site — see
  [Testing APMs in sandbox](#testing-apms-in-sandbox).
- **Swish hands off to the buyer's Swish app and BankID.** There is no card-number-entry
  fallback. Sandbox completion needs Swish test credentials provisioned by Fynex / the
  provider; otherwise the payment can remain `provider_pending` even though your redirect
  integration is working.

> [!IMPORTANT]
> **Returned to your site is not the same as paid.** APMs are asynchronous. The buyer can land
> back on your `returnUrl` while the scheme is still processing, or while an app-based method
> is still waiting for approval. Treat the return as a UX step only; confirm the final outcome
> with webhooks or `GET /payments-api/v1/payments/{payment_id}`.

## Testing APMs in sandbox

Use a **Demo** account and its token. Whether APM sandboxes are reached is decided by the account's operational mode, not the host — Demo accounts exist on both `https://staging-api.fynex.ai` and `https://api.fynex.ai`. Call the base URL your token was issued for: the two environments keep separate credential stores, so a token only authenticates against its own host.
Do not send these test values to production. Your seller account still needs APMs enabled and
routable: `GET /payments-api/v1/payment-methods` should include `apm` in
`allowedPaymentRails` and the specific instrument in `allowedPaymentMethods`.

You can test with either integration style:

1. **Server-to-server:** call `POST /payments-api/v1/initialize-payment` with
   `paymentType: "apm"`, a unique `externalOrderRef`, a unique `Idempotency-Key`, and the
   method/currency/country from the table below. The response should be `202 Accepted` with
   `requiresAction: true`. Redirect methods include `redirectFullPage: true` and an
   `actionUrl`; Multibanco includes `paymentInstructions` and can also include the redirect.
2. **Hosted checkout:** create a checkout session in staging, open the hosted checkout URL,
   and choose the APM tile. The tile only appears if the checkout's currency/country and your
   seller routing both support the method.
3. **Complete the buyer action:** for redirect methods, open `actionUrl` in a top-level browser
   window (not an iframe). For Multibanco, render the returned Entity and Reference. Then wait
   for the webhook or poll `GET /payments-api/v1/payments/{payment_id}` until terminal.

| Method | Request values | How to complete a sandbox payment | Failure-path test |
|--------|----------------|-----------------------------------|-------------------|
| Bancontact | `paymentMethod: "bancontact"`, `currencyCode: "EUR"`, `countryCode: "BE"` | On the provider-hosted Bancontact page, choose the card/PAN entry flow and use PAN `60600599999899023` with expiry `01/2035` and any CVV. | Use PAN `60600599999899080` with expiry `01/2035` to deny authentication. |
| Multibanco | `paymentMethod: "multibanco"`, `currencyCode: "EUR"`, `countryCode: "PT"` | For server-to-server integration, verify that `paymentInstructions.entity` and `.reference` render on your checkout with the top-level amount/currency. The provider sandbox can also return a mock redirect; approve there if you exercise that fallback. Then wait for webhook/polling because the method is asynchronous. | Abandon the instructions/redirect and keep polling to verify your pending-state handling, or choose the deny/fail option on the mock page when offered. |
| MB WAY | `paymentMethod: "mbway"`, `currencyCode: "EUR"`, `countryCode: "PT"` | MB WAY has no scheme sandbox — the provider simulates it. **Redirect flow:** approve on the provider's mock-authorization page; if it asks for a phone number use `+11111111112`, and for a verification code use `777123`. **Inline flow:** send `apmData.phone: "+11111111112"` and verify your page renders the waiting state from `paymentInstructions`, then that the payment reaches a terminal status without any redirect being followed. | Choose the deny/fail option on the mock page when offered, or abandon the flow and keep polling to verify your pending-state handling. For the inline flow, send a well-formed number that is not enrolled and confirm your page handles the payment expiring. |
| Wero | `paymentMethod: "wero"`, `currencyCode: "EUR"`, `countryCode: "BE"`, `"DE"`, or `"FR"` | On the provider page, select **Pay with Wero code**, copy the displayed code, open `https://example-consumer-psps.werouat.eu`, choose **Give consent**, paste the code, and choose **Approve**. | Repeat the same Wero UAT flow and choose **Deny**. |
| Swish | `paymentMethod: "swish"`, `currencyCode: "SEK"`, `countryCode: "SE"` | Swish sandbox completion requires provider-issued Swish test credentials / app access. If your sandbox account has them, complete the Swish app / BankID flow after redirect. | Use the provider-issued Swish failure path, or abandon the flow and verify that your integration handles `provider_pending` correctly. |

> [!NOTE]
> Bancontact is the only APM with static public card-like test PANs. Multibanco and MB WAY
> run on the provider's mock authorizer (approve/deny buttons, plus the `777123` /
> `+11111111112` test values above where prompted), Wero uses the Wero UAT consent site, and
> Swish test credentials are provisioned separately — the scheme publishes none for sandbox.
> If you need Swish credentials, contact Fynex support before scheduling your sandbox test.
> The underlying scheme and provider sandboxes are hosted outside Fynex and can be
> intermittently flaky. If the API times out or returns `502` before you receive a definitive
> payment result, retry the unchanged request with the same `externalOrderRef` and
> `Idempotency-Key`; Fynex reconciles the same provider attempt and re-surfaces the current
> buyer action (a redirect and/or Multibanco payment instructions). While that reconciliation
> is still active, the unchanged retry can return `503`
> with `provider create is pending reconciliation`; continue retrying the same request rather
> than minting a new key. A `409` with `provider create requires manual reconciliation` means
> automated recovery has stopped and Fynex support must resolve the provider charge. After a
> definitive terminal `failed` result, start a new payment attempt with a fresh pair.

### Suggested sandbox amounts

Use small, realistic amounts such as `10.00` in the method's currency. Avoid huge values in
sandbox unless Fynex support has asked you to test a specific limit or edge case. For each
scenario, use a fresh `externalOrderRef` and `Idempotency-Key`; reusing an idempotency key is
only for retrying the exact same payment attempt.

### What a successful test proves

A complete APM sandbox test proves that:

- your seller token is valid in staging;
- your seller account is configured for the `apm` rail and the chosen instrument;
- your `returnUrl` host is allow-listed when you send one;
- your frontend follows `actionUrl` as a full-page redirect, or renders complete Multibanco
  Entity/Reference instructions when returned; and
- your system waits for a terminal status via webhook or polling instead of treating the
  browser return as final payment success.

If a method does not appear on hosted checkout or `initialize-payment` rejects it, first
check the method/currency/country combination and `GET /payments-api/v1/payment-methods`.
An unsupported combination is rejected with `400` before Fynex creates or routes a payment;
for example, Wero with `countryCode: "IT"` is invalid. If
the buyer returns to your site with `status=pending`, keep polling or wait for your webhook.
That is normal for asynchronous APMs.

## Server-to-server API

Submit the payment directly from your backend to
`POST /payments-api/v1/initialize-payment`, authenticated with your seller
`Authorization: Bearer` token. Set `paymentType` to `apm` and `paymentMethod` to one of the
five APM instruments. No card, wallet, or billing data is required — the buyer authenticates
at the scheme, not on your form.

```bash
curl -sS -X POST "$FYNEX_API/payments-api/v1/initialize-payment" \
  -H "Authorization: Bearer $FYNEX_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "externalOrderRef": "ORDER-1042",
    "amount": 49.99,
    "paymentType": "apm",
    "paymentMethod": "bancontact",
    "currencyCode": "EUR",
    "countryCode": "BE",
    "returnUrl": "https://merchant.example/checkout/return"
  }'
```

`paymentMethod` must be one of `bancontact`, `multibanco`, `mbway`, `wero`, or `swish`, and it
must be compatible with the currency/country you send — Fynex routes on the currency/country
matrix (see [Instruments and availability](#instruments-and-availability)) and on your
`apm`-rail terminals. An instrument that isn't compatible with `paymentType: "apm"` returns
`400`. An otherwise valid APM whose currency/country is outside its supported matrix also
returns `400`, for example `paymentMethod wero is not supported for currency EUR and country IT`.

The example's `returnUrl` host (`merchant.example`) must be allow-listed on your seller
account first — see the note below.

> [!IMPORTANT]
> **`returnUrl` is optional only when another valid return-link source exists.** You may omit
> it when you send an explicit `returnLinks` array or your seller account already has default
> return links. If the request has neither and the seller has no defaults, initialization
> returns `400` (`"valid returnLinks are required"`). The Fynex-hosted status page is a
> fallback after a valid return configuration has been resolved; omitting `returnUrl` alone
> does not create that configuration.
>
> **When you do send `returnUrl`, this path fails closed.** Your seller account must have an
> **allowed-return-hosts whitelist** configured, and the host of `returnUrl` must be on it. A
> `returnUrl` whose host isn't allow-listed — *or any `returnUrl` sent before you've configured
> any allowed hosts at all* — returns `400` (`"returnUrl cannot be used until allowed return
> hosts are configured"`). This fail-closed rule (stricter than the hosted-checkout
> success/failure URLs, which are opt-in) is what keeps the later return-step redirect a safe,
> pre-validated one rather than an open redirect. Configure your allowed return hosts before
> going live.

> [!NOTE]
> **`returnUrl` alone is all you need.** Fynex derives a single default return link
> (`{ "rel": "default", "href": <returnUrl>, "method": "GET" }`) from it, so the redirect
> provider sends the buyer back to that URL for every outcome. If you need per-outcome
> destinations — a different landing page for completed vs. failed vs. cancelled — send an
> explicit `returnLinks` array instead, each entry a `{ "rel", "href", "method": "GET" }`
> object with `rel` one of `default`, `on_completed`, `on_failed`, or `on_cancelled`. When you
> send `returnLinks`, it takes precedence and `returnUrl` is not used to derive a link (it still
> drives the Fynex-hosted status-page fallback). You don't need both: `returnUrl` covers the
> common single-destination case.

### Response — follow the returned buyer action

A fresh request returns `202 Accepted`:

```json
{
  "paymentId": "ORDER-1042",
  "status": "provider_pending",
  "amount": 49.99,
  "currencyCode": "EUR",
  "requiresAction": true,
  "actionUrl": "https://redirect.provider.example/checkout/abc123",
  "redirectFullPage": true
}
```

| Field | Type | Meaning for APMs |
|-------|------|------------------|
| `requiresAction` | boolean | `true` for a successful APM initiation while the buyer still needs to act. |
| `actionUrl` | string | Provider redirect URL when available. Send the buyer's browser here for redirect flows. |
| `paymentInstructions` | object | Structured inline instructions when available, so the buyer can complete on your own checkout. `type` names the format: `payment_reference` (Multibanco) adds `entity` and `reference`; `app_notification` (MB WAY, when you send `apmData.phone`) adds `phone`. Absent when the only action is the redirect. |
| `redirectFullPage` | boolean | When `true`, redirect the whole page (navigate the top-level window), not an iframe. |
| `status` | string | `provider_pending` until the scheme reports back. |
| `paymentId` | string | Your `externalOrderRef`; use it to poll the outcome. |

For a redirect response, your UI drives the redirect — Fynex does not redirect the buyer for
you on this path. Send the browser to `actionUrl` using a full-page navigation when
`redirectFullPage` is true. After the buyer completes or abandons at the scheme, they pass
back through a Fynex-hosted return step that 302s them to your `returnUrl`. See
[The return leg](#the-return-leg) below.

For Multibanco, the same response can include inline instructions:

```json
{
  "paymentId": "ORDER-1043",
  "status": "provider_pending",
  "amount": 49.99,
  "currencyCode": "EUR",
  "requiresAction": true,
  "paymentInstructions": {
    "type": "payment_reference",
    "entity": "11854",
    "reference": "999999964"
  },
  "actionUrl": "https://redirect.provider.example/checkout/def456",
  "redirectFullPage": true
}
```

Display `entity` and `reference` as plain text, alongside the top-level `amount` and
`currencyCode`; never interpret provider values as HTML. Fynex only returns a structured
instruction after validating the Multibanco Entity as five ASCII digits and the Reference as
nine ASCII digits. Do not treat displaying or copying the instructions as payment success;
keep the payment pending until a webhook or payment lookup reports a terminal state. If both
instructions and `actionUrl` are present, you may keep the redirect as a fallback.

### Keeping the buyer on your checkout with MB WAY

By default MB WAY sends the buyer to a provider-hosted page. To keep them on your own
checkout instead, collect their MB WAY phone number and send it as `apmData.phone`:

```json
{
  "externalOrderRef": "ORDER-100106",
  "amount": 10.50,
  "paymentType": "apm",
  "paymentMethod": "mbway",
  "currencyCode": "EUR",
  "countryCode": "PT",
  "apmData": { "phone": "+351912345678" }
}
```

The authorization is then pushed to that number's MB WAY app and the response carries an
`app_notification` instruction:

```json
{
  "paymentId": "ORDER-100106",
  "status": "provider_pending",
  "requiresAction": true,
  "paymentInstructions": {
    "type": "app_notification",
    "phone": "+351912345678"
  },
  "actionUrl": "https://redirect.provider.example/checkout/ghi789",
  "redirectFullPage": true
}
```

There is nothing to render but a waiting state — the buyer approves in their app. Rules:

- **`apmData.phone` must be a valid E.164 number** (`+` and 8–15 digits). A malformed value is
  rejected with `400` before any payment is created. Omitting it is not an error: the payment
  simply keeps the redirect flow.
- **`apmData.phone` is the only source of the number.** `billingDetails.phone` is never used
  for the push, even a Portuguese one — it is a contact detail collected for something else,
  and the buyer whose handset rings has not agreed to that by giving you a billing contact.
  The push goes to the number registered with the buyer's MB WAY account, which need not be
  your billing contact, so ask for it explicitly. No `apmData.phone`, no push.
- **`actionUrl` is still returned** — keep it as a fallback. The push has a short window
  (below) and the same charge is payable either way.
- **The window is 4 minutes.** MB WAY is not a voucher method: if the buyer does not approve
  in time the payment moves to `failed` and you must start a new one.
- **Do not treat the instruction as payment success.** Wait for a terminal status via your
  webhook or by polling `GET /payments-api/v1/payments/{payment_id}`.
- **Send a number the buyer gave you for this payment.** Nothing upstream validates it: a
  number that is not enrolled with MB WAY is accepted and simply never authorizes, so the
  only symptom is a payment that expires. Do not push to a number the buyer supplied for
  some other purpose.

This is a server-to-server capability. Fynex-hosted checkout continues to drive MB WAY through
the provider redirect, and `apmData` is ignored there.

Submitting the same `Idempotency-Key` with the same business intent returns the existing
payment (`200 OK`) rather than creating a duplicate; reusing it with a different `amount` /
`currencyCode` / `externalOrderRef` / `apmData.phone` returns `409`.

`apmData.phone` is part of that intent because it decides where the authorization goes. So if
the buyer mistyped their number, **retrying with a corrected `apmData.phone` under the same
`Idempotency-Key` is a `409`, not a correction** — the original payment is already pushing to
the original number. Start a new payment with a fresh `Idempotency-Key` and `externalOrderRef`
instead, and let the first one expire.

## Hosted checkout

If you already use Fynex-hosted checkout, you get APMs with no extra integration work. Create
the checkout session exactly as you would for a card-only checkout; the Fynex-hosted page
renders whichever APM tiles are available for that session (see [How hosted-checkout
availability is decided](#how-hosted-checkout-availability-is-decided)), and drives the
redirect handshake inside the page. Your integration never sees a provider token and never
calls a provider endpoint — you only observe the final outcome via webhook, polling, or the
return redirect. See [Hosted checkout](https://api.fynex.ai/payments-api/v2/docs#tag/hosted-checkout) for the session-creation
reference.

## The return leg

Both entry paths — server-to-server and hosted checkout — return the buyer through the same
Fynex-hosted return step once they finish authorizing at the scheme:

```
Buyer browser              Scheme / provider        Fynex
─────────────              ─────────────────        ─────
(server-to-server: your
 UI sends the buyer to
 actionUrl; hosted: the
 Fynex page does it)
  ─────────────────────►  authorize
                            (bank page / app / QR)
                          ─── redirect back ────►  Fynex return handler
                                                   (signed token resolved
                                                   server-side; looks up the
                                                   payment's pre-validated
                                                   destination)
  ◄─────────────────────────────────────────────  302 to that destination
lands on:
  • hosted-checkout success / failure URL, or
  • caller returnUrl with ?status=&paymentId=, or
  • Fynex-hosted status page (no caller destination)
```

The return step carries a signed token Fynex issued when it started the payment; Fynex
resolves it **server-side** and 302s to a destination it reads from already-persisted,
already-validated payment data:

1. the hosted-checkout **success / failure URL** configured on the payment, or
2. the caller's **`returnUrl`** with `?status=` and `?paymentId=` query params appended, or
3. a **Fynex-hosted status page** when the payment has neither of the above.

The destination is never taken from the incoming request beyond the signed token, so the step
cannot be turned into an open redirect. A missing, invalid, or expired token renders an
"Invalid Link" page rather than redirecting anywhere.

> [!NOTE]
> An APM payment can still be *pending* when the buyer is returned — account-to-account and
> voucher schemes settle asynchronously. The status page (and the `?status=` on your
> `returnUrl`) can therefore read `pending`; the payment is finalized later. The return
> query uses one of `status=pending`, `status=succeeded`, or `status=failed`, and includes
> `paymentId=<externalOrderRef>`. Confirm the real outcome the same way you would for any
> payment: register a webhook or poll
> `GET /payments-api/v1/payments/{payment_id}` (the returned `?paymentId=` is your
> `externalOrderRef`). Do not treat "returned to my URL" as "paid" — wait for a terminal
> status. See [Polling & SSE](https://api.fynex.ai/payments-api/v2/docs#tag/polling-sse) and [Webhooks](https://api.fynex.ai/payments-api/v2/docs#tag/webhooks).

## How hosted-checkout availability is decided

On **hosted checkout**, whether an APM tile appears on a given session is the **intersection**
of two gates:

1. **The currency/country matrix** above — a method is only a candidate when the checkout's
   currency (and country, for the country-bound schemes) matches the table.
2. **Routability** — your account must have at least one active `apm`-rail terminal whose
   currency / country / operational-mode can carry the checkout. Fynex never renders a tile it
   cannot route, so a buyer can't pick a method that would then fail on submit.

If nothing survives both gates, the hosted checkout simply doesn't show an APM block — the
buyer falls back to card (or whatever else is configured). There is no broken-tile state.

The **server-to-server** path is gated by the same two constraints, but you learn about a
mismatch differently: an instrument that doesn't match the currency/country you sent, or that
your account can't route, is rejected at `initialize-payment` (`400`, or a routing `502`)
rather than silently hidden. Either way, don't hard-code which APMs to offer — discover what
your account supports with the payment-methods endpoint, exactly as you would for any other
instrument.

## Discovering what's enabled

`GET /payments-api/v1/payment-methods` returns the instruments and rails configured on your
seller account. Check `allowedPaymentRails` for `apm` and `allowedPaymentMethods` for the
specific instrument values before you rely on APMs being available:

```bash
curl -sS "$FYNEX_API/payments-api/v1/payment-methods" \
  -H "Authorization: Bearer $FYNEX_TOKEN"
```

```json
{
  "sellerAccountId": 42,
  "allowedPaymentMethods": ["card", "bancontact", "wero"],
  "allowedCurrencies": ["EUR"],
  "allowedPaymentRails": ["card", "apm"]
}
```

See [Payment methods & capabilities](https://api.fynex.ai/payments-api/v2/docs#tag/payment-methods) for the full response shape.

Two things to keep in mind when reading this response for APMs:

- **`allowedPaymentMethods` is the account-level ceiling.** It tells you which instruments
  your account is configured for. It does **not** guarantee a given instrument works on every
  payment — the per-checkout currency/country matrix and terminal routability still apply (see
  above).
- **Use it to decide what to offer, on either path.** For hosted checkout, it tells you
  whether to route a buyer to a Fynex-hosted page at all (the tiles themselves are rendered by
  Fynex). For the server-to-server path, it tells you which `paymentMethod` values are worth
  presenting in your own UI before you call `initialize-payment`.

## See also

- **[Hosted checkout](https://api.fynex.ai/payments-api/v2/docs#tag/hosted-checkout)** — create the checkout session that renders APM tiles for the hosted path.
- **[Payment methods & capabilities](https://api.fynex.ai/payments-api/v2/docs#tag/payment-methods)** — discover the `apm` rail and enabled instruments for your account.
- **[Apple Pay](https://api.fynex.ai/payments-api/v2/docs#tag/apple-pay)** / **[Google Pay](https://api.fynex.ai/payments-api/v2/docs#tag/google-pay)** — the other wallet-like instruments, on the `card` rail; like APMs they also offer a server-to-server path.
- **[Polling & SSE](https://api.fynex.ai/payments-api/v2/docs#tag/polling-sse)** / **[Webhooks](https://api.fynex.ai/payments-api/v2/docs#tag/webhooks)** — confirm the final outcome of an asynchronously-settling APM payment.
