Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion api-reference/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Reference groups:
- [On-Ramp](https://unigox.gitbook.io/unigox-api/api-documentation/api-reference/on-ramp)
- [Off-Ramp](https://unigox.gitbook.io/unigox-api/api-documentation/api-reference/off-ramp)
- [Third-party payouts](./third-party-payouts.md)
- [USD bank payments to China](./china-usd-payments.md)
- [USD bank payments to China, Hong Kong and Singapore](./china-usd-payments.md)
- [Orders](https://unigox.gitbook.io/unigox-api/api-documentation/api-reference/orders)
- [Webhooks](https://unigox.gitbook.io/unigox-api/api-documentation/api-reference/webhooks)

Expand Down
63 changes: 59 additions & 4 deletions api-reference/china-usd-payments.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
# USD payments to China
# USD payments to China, Hong Kong and Singapore

The dollar reaches three destinations, each with its own rail and its own rollout: mainland China
(`usd-wire-china`), Hong Kong (`usd-wire-hong-kong`) and Singapore (`usd-wire-singapore`). Most of
this page is the mainland contract, which is the strictest of the three; the Hong Kong and Singapore
contract is at the end and differs in what it asks for. One country being open says nothing about
another, so read availability per destination and never from the currency alone.

USD beneficiary details and private invoices can be saved. Whether a payment can be executed is a per-deployment rollout setting, off by default. Onshore business accounts need matching liquidity; NRA/OSA accounts additionally require the original invoice, and stay refused until the original-invoice channel is confirmed. A general USD offer alone cannot enable the corridor. These settings are deployment controls, not request parameters.

## Confirmed bank contract
## Confirmed bank contract (mainland China)

Use country `CN`, currency `USD`, network `usd-wire-china` and institution `china-usd-wire`. This is one generic bank method: the beneficiary's own `bank_name` and `swift_code` route the payment. Never replace `bank_name` with the catalogue label “Bank in China (USD)”. `bank_code` is not used.

Expand All @@ -23,11 +29,11 @@ Account details are strings. Whitespace is removed from account numbers before v

## Customer APIs

The authenticated account session at `GET /api/v1/bill-payment/session` returns USD with `available` derived from the rollout setting, `preparation_available: true` and `bank_rails: ["usd-wire-china"]`. When disabled, the reason is `provider_confirmation_pending`. Availability means permission to execute; preparation availability only permits saving details and documents. Missing preparation metadata fails closed.
The authenticated account session at `GET /api/v1/bill-payment/session` returns one USD row per destination — this one is `country: "CN"` with `bank_rails: ["usd-wire-china"]` — each with its own `available` derived from that destination's rollout setting and `preparation_available: true`. When disabled, the reason is `provider_confirmation_pending`. Availability means permission to execute; preparation availability only permits saving details and documents. Missing preparation metadata fails closed.

Use `payout_currency=USD` on `GET /api/v1/bill-payment/payment-rails` and `/institutions`. The institution's actual rail is resolved on our side. To add a separate USD account to an existing supplier, POST `/api/v1/bill-payment/recipients/:id/destinations` with `institution_id`, `payout_currency`, `details` and an `idempotency_key`. Include `beneficiary_type: "business"` in widget details. The recipient's other destinations are retained. Replaying the same key/body returns the saved destination; a changed body returns 409. A caller cannot add to someone else's recipient.

`POST /api/v1/bill-payment/preflight` checks the saved account, amount and live quote. A refusal uses HTTP 200 with `ok: false`, `may_collect: false`, `price: null`; direct bill-create is refused before collection. An enabled onshore account with live liquidity can return `may_collect: true`, then `POST /bills` opens a real USD bill with immutable intent and idempotency. A USD preflight must name `recipient_destination_id`, or it is refused with `destination_required`. An amount below USD 25 is refused with `CHINA_USD_AMOUNT_OUT_OF_RANGE`. NRA/OSA remains refused with `CHINA_USD_INVOICE_CHANNEL_UNAVAILABLE` until its original-invoice channel is confirmed. After that, preflight and `POST /bills` for an NRA/OSA account must name the uploaded invoice in `invoice_document_id`, or they are refused with `INVOICE_DOCUMENT_REQUIRED`. Validation errors use the endpoint's existing 400/422 envelopes; do not treat a successful discovery response as permission to fund.
`POST /api/v1/bill-payment/preflight` checks the saved account, amount and live quote. A refusal uses HTTP 200 with `ok: false`, `may_collect: false`, `price: null`; direct bill-create is refused before collection. An enabled onshore account with live liquidity can return `may_collect: true`, then `POST /bills` opens a real USD bill with immutable intent and idempotency. A USD preflight must name `recipient_destination_id`, or it is refused with `destination_required`. An amount below USD 25 is refused with `CHINA_USD_AMOUNT_OUT_OF_RANGE` on this rail; the Hong Kong and Singapore rails answer with `USD_AMOUNT_OUT_OF_RANGE`. NRA/OSA remains refused with `CHINA_USD_INVOICE_CHANNEL_UNAVAILABLE` until its original-invoice channel is confirmed. After that, preflight and `POST /bills` for an NRA/OSA account must name the uploaded invoice in `invoice_document_id`, or they are refused with `INVOICE_DOCUMENT_REQUIRED`. Validation errors use the endpoint's existing 400/422 envelopes; do not treat a successful discovery response as permission to fund.

Private documents use `/api/v1/bill-payment/documents/:uuid`, where `:uuid` is a client-generated UUID in canonical lowercase form: PUT multipart `document`, `recipient_destination_id`, `payout_currency`; GET metadata; GET `/content`; DELETE an unbound draft. GET, GET `/content` and DELETE take `recipient_destination_id` and `payout_currency` as query parameters; to read the invoice retained on a payment, GET and GET `/content` also take that payment's `bill_id`. PDF/JPEG/PNG, 8 MiB maximum. The server binds the original bytes and SHA-256 to the owner, destination and currency. An identical retry is safe; different bytes with the same UUID return 409 `invoice_document_mismatch`. Drafts expire after 7 days; a bound invoice is retained as payment evidence. Storing an invoice here is not the same as the provider accepting it.

Expand Down Expand Up @@ -66,6 +72,55 @@ Use the currency agreed with the supplier. CNY and USD require separate saved de

`usd-wire-china` is a payout (off-ramp) network only. The supported-currencies and supported-payment-rails responses do not filter by direction, so do not offer a rail as an on-ramp option because it is listed. Discovery does not replace execution eligibility checks.

## Hong Kong and Singapore

Confirmed by the provider and probed live on 18 September 2026. Use country `HK` with network
`usd-wire-hong-kong` and institution `hong-kong-usd-wire`, or country `SG` with
`usd-wire-singapore` and `singapore-usd-wire`. The pair must agree: a Hong Kong rail sent with
country `CN` is refused as a route mismatch rather than resolved to either.

These rails are SWIFT only — the provider has no domestic alternative outside the mainland — and
they are one generic bank method each: the beneficiary's own `swift_code` routes the payment. A
`bank_name` may be saved for the payer's own reference and is not sent to the provider. Like the mainland rail, they list their fields at the top level and have no `formats`, and
they pay business beneficiaries.

| Detail | Constraint |
| --- | --- |
| `company_name` | Required, at most 100 characters |
| `swift_code` | Required, 8–16 alphanumeric characters |
| `account_number` | Required, 6–30 letters and digits with no spaces; retain leading zeros |
| `bank_name` | Optional, at most 100 characters |

What these two do NOT ask for, and what a client must therefore not send: the beneficiary's postal
address, city, state or postal code, and a purpose-of-remittance code. Hong Kong has no postal code
at all. There is also no NRA/OSA rule here: the provider publishes one account field, the BIC picks
the bank, and `CHINA_USD_ACCOUNT_UNCONFIRMED` has no counterpart beyond the field itself — an
account the field cannot hold is refused with `USD_ACCOUNT_UNCONFIRMED`.

No invoice is required on either rail, before or after the bill opens, so
`INVOICE_DOCUMENT_REQUIRED` and `CHINA_USD_INVOICE_CHANNEL_UNAVAILABLE` cannot arise. An invoice may
still be uploaded and retained as payment evidence.

The platform minimum is USD 25 here too, refused with `USD_AMOUNT_OUT_OF_RANGE`; the maximum is what
the executable quote serves. The provider's flat service charge is the same USD 3 as on the mainland
rail. Correspondent bank charges on a SWIFT payment are the correspondents' own and are not quoted
here, so a beneficiary may receive less than the amount sent. There is no field on these rails for a
payment reference or remark: an order number a supplier asks to see on the wire cannot be carried.

Delivery is what the provider reports for SWIFT: usually two working days. A beneficiary bank
without a direct SWIFT connection can take longer, and public holidays move the date. Provider
acceptance is not bank finality, and a returned payment is refunded through the same manual process
as the mainland rail.

`GET /api/v1/bill-payment/session` lists one payout option per destination, each with its own
`available`, `preparation_available`, `reason` and `bank_rails`. A disabled destination answers
`provider_confirmation_pending`. `GET /api/v1/bill-payment/payment-rails?payout_currency=USD`
returns all three rails; `/institutions` is per rail. Everything else — preflight, `POST /bills`,
documents, destination removal — behaves as described above.

Advisory recognition imports a Hong Kong or Singapore beneficiary onto that country's rail. It
refuses a country none of the three rails reach, by name.

## Removing bank details

DELETE `/api/v1/bill-payment/recipients/:id/destinations/:destination_id` removes
Expand Down