> For the complete documentation index, see [llms.txt](https://apc-pay.gitbook.io/apc-pay-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://apc-pay.gitbook.io/apc-pay-docs/getting-started/quick-start.md).

# Quick Start

Updated 2026-10-14

Use this guide to make your first APC Pay payout from a server-side Node.js application.

> ❇️
>
> ### Real payouts
>
> This API creates outbound fiat payouts funded from your merchant USDT balance. The supplied materials do not document a sandbox. Treat `/payout/create` as a real-money operation unless APC Pay has explicitly provided you with a test environment.

## How the integration works

```mermaid
sequenceDiagram
    autonumber
    participant M as Merchant server
    participant P as APC Pay API
    participant C as Payout channel

    M->>P: Query currency and balance
    P-->>M: Signed configuration data
    M->>P: Create signed payout
    P-->>M: Signed ACCEPTED order
    P->>C: Process fiat payout
    C-->>P: Final result
    P->>M: Signed SUCCESS or FAILED callback
    M-->>P: HTTP 200, body: success
    M->>P: Query order when reconciliation is needed
    P-->>M: Signed current order state
```

At a minimum, your integration should:

1. Query the currency configuration and confirm the amount is allowed.
2. Create the payout with a unique merchant order number.
3. Store the platform payout ID and locked rate information.
4. Verify and process the final callback idempotently.
5. Query the order after a timeout or uncertain result.

## Before you begin

Obtain these values from the APC Pay merchant portal:

| Item                      | Purpose                                                                 |
| ------------------------- | ----------------------------------------------------------------------- |
| Merchant number (`mchNo`) | Identifies your merchant account.                                       |
| App ID (`appId`)          | Identifies your app. It is a 24-character lowercase hexadecimal string. |
| Merchant private key      | Signs requests. Keep it only on your server.                            |
| Merchant public key       | Lets APC Pay verify your requests.                                      |
| Platform public key       | Verifies successful responses and callbacks.                            |
| Public server IP          | Must be added to the app IP whitelist.                                  |
| Enabled fiat currencies   | Must be added to the app currency whitelist.                            |
| Public HTTPS callback URL | Receives final payout notifications.                                    |

In the portal:

1. Copy the merchant number from **Account**.
2. Create or select an app under **Apps**, then copy its app ID.
3. Upload the merchant RSA public key in PEM format. It must begin with `-----BEGIN PUBLIC KEY-----`.
4. Add each server public egress IP. CIDR ranges and wildcards are not supported.
5. Enable each fiat currency the app will use.
6. Download the platform public key from **Account**.

> 📘
>
> ### Required configuration
>
> An empty IP whitelist or currency whitelist causes every affected API request to be rejected.

## Environment

The supplied integration package uses:

```
https://pwc-pay-api.chiachair.com/v1
```

| Operation                    | Method and path        |
| ---------------------------- | ---------------------- |
| Query balance                | `POST /balance/query`  |
| Query currency configuration | `POST /currency/query` |
| Create payout                | `POST /payout/create`  |
| Query payout                 | `POST /payout/query`   |

Send requests to the full public URL, including `/v1`. When signing, use only the backend path such as `/payout/create`.

## 1. Install the TypeScript example

The supplied package contains `02-PWC-Pay-TypeScript-Example` and requires Node.js 18 or newer. Run these commands from the extracted `pwc-pay-integration` directory:

```bash
cd 02-PWC-Pay-TypeScript-Example
npm ci
mkdir -p keys
```

## 2. Generate the merchant key pair

Skip this step when you already have the private key that matches the public key configured in the portal.

```bash
(umask 077 && openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 \
  | openssl pkcs8 -topk8 -nocrypt -out keys/private.pem)
openssl pkey -in keys/private.pem -pubout -out keys/public.pem
openssl pkey -pubin -in keys/public.pem -outform DER \
  | openssl dgst -sha256
```

Upload `keys/public.pem` to your app and confirm its SHA-256 fingerprint matches the portal.

> ❇️
>
> ### Keep the private key secret
>
> Never upload `keys/private.pem`, commit it to source control, place it in a frontend app, or paste it into a support ticket.

## 3. Configure the example

Copy the platform public key to `keys/platform_public_key.pem`, verify its fingerprint, then create `.env` with sanitized values:

```dotenv
API=https://pwc-pay-api.chiachair.com/v1
MCH_NO=your-merchant-number
APP_ID=your-app-id
PRIVATE_KEY=./keys/private.pem
PLATFORM_PUBLIC_KEY=./keys/platform_public_key.pem

# Set these only when you are ready to create a real payout.
PAYOUT_MCH_ORDER_NO=your-unique-order-number
PAYOUT_FIAT_AMOUNT=100.00
PAYOUT_FIAT_CURRENCY=PHP
PAYOUT_QR_CONTENT=complete-payee-qr-payload
PAYOUT_USER_EMAIL=payee@example.com
PAYOUT_NOTIFY_URL=https://merchant.example.com/webhooks/apc-pay
PAYOUT_EXT_PARAM=your-internal-reference

# Optional alternative identifier for payout queries.
PAYOUT_ORDER_ID=

# Used by the callback example.
NOTIFY_PORT=3000
```

Use the exact decimal precision returned by `/currency/query`. The QR payload, amount, and currency must agree.

## 4. Run read-only checks

Check the allowed amount, current rates and fees, and available USDT before creating a payout:

```bash
npx ts-node src/currency.ts
npx ts-node src/balance.ts
```

## 5. Start the callback receiver

```bash
npx ts-node src/notify-server.ts
```

Expose the receiver through a public HTTPS URL and set it as `PAYOUT_NOTIFY_URL`. The example deduplicates callbacks in memory; production systems need a durable database unique constraint on `notifyId`.

## 6. Create the payout

Review every payout value in `.env`, then run:

```bash
npx ts-node src/create-payout.ts
```

> ❇️
>
> ### Every run can send a real payout
>
> Use a new `PAYOUT_MCH_ORDER_NO` for each new payout. When retrying the same payout, keep the same order number and business parameters.

A successfully created payout starts in `ACCEPTED`. Store both `mchOrderNo` and `payoutOrderId`.

## 7. Query the payout

```bash
npx ts-node src/query-payout.ts
```

The example uses `PAYOUT_MCH_ORDER_NO`, or `PAYOUT_ORDER_ID` when the merchant order number is empty. Query the payout when a create request times out, the API returns `4001 SYSTEM_ERROR`, a final callback is delayed, or you are reconciling state.

## Continue the integration

1. [Native API Integration](broken://pages/7b501391f08adae344986212af9d57286f6b569e)
2. [Authentication and Request Signing](broken://pages/09fdb741f99cf1deb38cf1b90b063767f12807df)
3. [Balance and Currency](broken://pages/c374e00afa6fb109644d34b6d82fbe7b0d8b38c7)
4. [Create a Payout](broken://pages/85bb23f0c564b16167e4d27ad120123daf5f90b3)
5. [Query a Payout](broken://pages/d322bd86cc349f7eef7630c43fcea7a59ed35e89)
6. [Payout Webhooks](broken://pages/3ddd4c5270f1825eb62c85633eddb69b50a33b8c)
7. [Payout Statuses and Errors](broken://pages/1701152330ec298b264aa8660498f37921c96df6)
8. [Production Checklist](broken://pages/51586ee1dbdda74e18dfca2a30c3f8205ecce9e0)
