> For the complete documentation index, see [llms.txt](https://docs.moneycollect.com/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.moneycollect.com/docs/payment/disbursement.md).

# Disbursement

## Business Overview

MoneyCollect Fund Disbursement is a flexible fund distribution solution designed for merchants. In day-to-day operations, merchants not only need to collect payments from customers but also frequently face the need to distribute funds outward — for example, settling payments to suppliers, distributing commissions to distributors or agents, or issuing refunds to payers in scenarios such as transaction disputes or order cancellations.

MoneyCollect Fund Disbursement was built to address these exact scenarios. Through a standard API, merchants can flexibly transfer funds collected via payment acquiring to supported target platforms and beneficiary accounts. Currently, we support multiple transfer methods including instapay, instapay\_qr, swiftpay\_pesonet, coins, enabling precise and timely fund distribution to beneficiaries' bank accounts or e-wallets.

Compared to traditional offline remittance or manual operations, MoneyCollect Fund Disbursement offers the following core advantages:

* **Fully Automated Online Process**: Merchants can complete the entire workflow — from creating a beneficiary to initiating a transfer — through a standard API, eliminating the need for manual intervention and significantly reducing operational costs.
* **Flexible Transfer Methods**: Supports instapay, instapay\_qr, swiftpay\_pesonet, coins to meet different timing and amount requirements.
* **Complete Lifecycle Management**: Transfers support a step-by-step "Create → Confirm → Complete" workflow. Merchants can review and confirm after creation, or cancel before confirmation to avoid accidental operations.
* **Security & Compliance**: Every transfer requires signature verification and merchant authorization checks. Beneficiary information and transfer operations are subject to strict resource ownership validation to ensure fund security.

## Business Workflow

The fund disbursement process consists of two core steps: **Create a Beneficiary** and **Initiate a Transfer**.

```
+-----------------------------------------------------------------+
|                    Fund Disbursement Workflow                   |
+-----------------------------------------------------------------+
|                                                                 |
|  Step 1: Create a Beneficiary                                   |
|  +--------------+    +--------------+    +------------------+   |
|  |  POST        |    |  Provide     |    |  Returns         |   |
|  |  /beneficiary|--->|  beneficiary |--> |  beneficiary ID  |   |
|  |  /create     |    |  & bank info |    |  (ben_xxx)       |   |
|  +--------------+    +--------------+    +------------------+   |
|         |                                      |                |
|         |  (Optional) Retrieve/Update/Delete   |                |
|         |                                      |                |
|         v                                      v                |
|  Step 2: Initiate a Transfer                                    |
|  +--------------+    +--------------+    +------------------+   |
|  |  POST        |    |  Specify     |    |  Returns         |   |
|  |  /transfer   |--->|  beneficiary |--> |  transfer ID     |   |
|  |  /create     |    |  amount etc  |    |  (trf_xxx)       |   |
|  +--------------+    +--------------+    +--------+---------+   |
|                                                   |             |
|                                                   v             |
|                                          +------------------+   |
|                                          | confirm = true?  |   |
|                                          +---+----------+---+   |
|                                             YES          NO     |
|                                              |            |     |
|                                              v            v     |
|                                     +----------+  +----------+  |
|                                     | Proceeds |  | Awaiting |  |
|                                     | directly |  | manual   |  |
|                                     +----------+  | confirm  |  |
|                                                   +----+-----+  |
|                                                        |        |
|                                          POST          |        |
|                                      /transfer/{id}    |        |
|                                      /confirm <--------+        |
|                                          |                      |
|                                          v                      |
|                                    +----------+                 |
|                                    |processing|                 |
|                                    +----+-----+                 |
|                                         |                       |
|                                         v                       |
|                              +------------------+               |
|                              |  Bank callback   |               |
|                              |  success/failed  |               |
|                              +------------------+               |
|                                                                 |
+-----------------------------------------------------------------+
```

{% stepper %}
{% step %}

## Create a Beneficiary

Before initiating a fund disbursement, the merchant must first create a beneficiary, recording the beneficiary's identity, bank account, and address details. Once created, a unique ID is returned, and all subsequent transfer operations reference this ID.

The same beneficiary can be reused across multiple transfers, so merchants do not need to re-enter bank details for each transfer.

#### Beneficiary Endpoints

| Endpoint                      | Method | Description            | Reference                                                                                               |
| ----------------------------- | ------ | ---------------------- | ------------------------------------------------------------------------------------------------------- |
| `/v1/beneficiary/create`      | POST   | Create a Beneficiary   | [API Reference](https://apireference.moneycollect.com/docs/api-v1/a72d5d17c58a6-create-a-beneficiary)   |
| `/v1/beneficiary/{id}`        | GET    | Retrieve a beneficiary | [API Reference](https://apireference.moneycollect.com/docs/api-v1/6719757b06c99-retrieve-a-beneficiary) |
| `/v1/beneficiary/{id}/update` | POST   | Update a beneficiary   | [API Reference](https://apireference.moneycollect.com/docs/api-v1/5c27cd87c171e-update-a-beneficiary)   |
| `/v1/beneficiary/{id}/delete` | POST   | Delete a beneficiary   | [API Reference](https://apireference.moneycollect.com/docs/api-v1/a4983169ac565-delete-a-beneficiary)   |

#### Request Example -- Create a Beneficiary

```bash
curl -X POST https://api.moneycollect.com/api/v1/beneficiary/create \
  -H "Authorization: sk_your_api_key" \
  -H "Signature: <SHA256withRSA_signature>" \
  -H "Content-Type: application/json" \
  -d '{
    "transferMethod": "instapay",
    "nickname": "Juan Dela Cruz",
    "email": "juan.delacruz@example.com",
    "beneficiary": {
      "entityType": "personal",
      "address": {
        "city": "Manila",
        "countryCode": "PH",
        "postcode": "1000",
        "state": "Metro Manila",
        "streetAddress": "Unit 501, Tower A, BGC Central Square"
      },
      "bankDetail": {
        "accountCurrency": "PHP",
        "accountName": "Juan Dela Cruz",
        "accountNumber": "001234567890",
        "countryCode": "PH",
        "swiftCode": "BNORPHMM",
        "bankName": "Banco de Oro"
      }
    }
  }'
```

#### Response Example

```json
{
  "code": "success",
  "data": {
    "id": "ben_1431153595065380862",
    "transferMethod": "instapay",
    "nickname": "Juan Dela Cruz",
    "email": "juan.delacruz@example.com",
    "beneficiary": {
      "entityType": "personal",
      "address": {
        "city": "Manila",
        "countryCode": "PH",
        "postcode": "1000",
        "state": "Metro Manila",
        "streetAddress": "Unit 501, Tower A, BGC Central Square"
      },
      "bankDetail": {
        "accountCurrency": "PHP",
        "accountName": "Juan Dela Cruz",
        "accountNumber": "001234567890",
        "countryCode": "PH",
        "swiftCode": "BNORPHMM",
        "bankName": "Banco de Oro"
      }
    },
    "createdAt": "2026-06-02T10:30:00.000Z",
    "updatedAt": "2026-06-02T10:30:00.000Z"
  },
  "msg": "success"
}
```

{% endstep %}

{% step %}

## Initiate a Transfer

Using the beneficiary ID created earlier, the merchant can initiate a transfer. When creating a transfer, the merchant specifies the order number, amount, currency, and other details, and can choose whether to confirm immediately (the `confirm` parameter defaults to `true`).

* If `confirm = true`: The transfer proceeds to processing immediately after creation.
* If `confirm = false`: The transfer enters the `requires_confirmation` state. The merchant must call the confirm endpoint to proceed, or call the cancel endpoint to abort the transfer.

Transfer results are delivered asynchronously via the `notifyUrl` configured by the merchant.

#### Transfer Endpoints

| Endpoint                    | Method | Description         | Reference                                                                                            |
| --------------------------- | ------ | ------------------- | ---------------------------------------------------------------------------------------------------- |
| `/v1/transfer/create`       | POST   | Create a Transfer   | [API Reference](https://apireference.moneycollect.com/docs/api-v1/0b7d6b5fb19aa-create-a-transfer)   |
| `/v1/transfer/{id}`         | GET    | Retrieve a transfer | [API Reference](https://apireference.moneycollect.com/docs/api-v1/64015dbd41235-retrieve-a-transfer) |
| `/v1/transfer/{id}/confirm` | POST   | Confirm a transfer  | [API Reference](https://apireference.moneycollect.com/docs/api-v1/129b75dc83c59-confirm-a-transfer)  |
| `/v1/transfer/{id}/cancel`  | POST   | Cancel a transfer   | [API Reference](https://apireference.moneycollect.com/docs/api-v1/490f9afa7f57a-cancel-a-transfer)   |

#### Request Example -- Create a Transfer

```bash
curl -X POST https://api.moneycollect.com/api/v1/transfer/create \
  -H "Authorization: sk_your_api_key" \
  -H "Signature: <SHA256withRSA_signature>" \
  -H "Content-Type: application/json" \
  -d '{
    "orderNo": "MC20260602DISB00001",
    "beneficiaryId": "ben_1431153595065380862",
    "amount": 5000000,
    "currency": "PHP",
    "notifyUrl": "https://merchant.example.com/disburse/notify",
    "remarks": "June 2026 supplier payment",
    "confirm": true,
    "payer": {
      "payerName": "Acme Trading Corp"
    },
    "additional": {
      "reason": "goods_purchased",
      "postscript": "Invoice #INV-2026-0601"
    }
  }'
```

**Response Example**

```json
{
  "code": "success",
  "data": {
    "id": "trf_1431159995065380900",
    "orderNo": "MC20260602DISB00001",
    "beneficiaryId": "ben_1431153595065380862",
    "amount": 5000000,
    "currency": "PHP",
    "notifyUrl": "https://merchant.example.com/disburse/notify",
    "remarks": "June 2026 supplier payment",
    "confirm": true,
    "createdAt": "2026-06-02T12:00:00.000Z",
    "confirmedAt": null,
    "canceledAt": null,
    "returnCode": "SUCCESS",
    "returnMsg": "Transfer has been submitted",
    "status": "processing"
  },
  "msg": "success"
}
```

#### Transfer Reason (`reason`) Options

| Value                              | Description                        |
| ---------------------------------- | ---------------------------------- |
| `wages_salary`                     | Wages / Salary                     |
| `business_expenses`                | Business Expenses                  |
| `goods_purchased`                  | Goods Purchased                    |
| `freight`                          | Freight / Logistics                |
| `bill_payment`                     | Bill Payment                       |
| `investment_capital`               | Investment Capital                 |
| `investment_proceeds`              | Investment Proceeds                |
| `loan_credit_repayment`            | Loan / Credit Repayment            |
| `donation_charitable_contribution` | Donation / Charitable Contribution |
| `education_training`               | Education / Training               |
| `medical_services`                 | Medical Services                   |
| `real_estate`                      | Real Estate                        |
| `construction`                     | Construction                       |
| `living_expenses`                  | Living Expenses                    |
| `pension`                          | Pension                            |
| `technical_services`               | Technical Services                 |
| `professional_business_services`   | Professional / Business Services   |
| `audio_visual_services`            | Audio-Visual Services              |
| `transfer_to_own_account`          | Transfer to Own Account            |
| `travel`                           | Travel                             |
| `taxes`                            | Taxes                              |
| `other_services`                   | Other Services                     |

#### Transfer Status Lifecycle

| Status                  | Description                                                                                                                |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `requires_confirmation` | Pending confirmation — the transfer has been created but not yet confirmed; awaiting merchant to call the confirm endpoint |
| `processing`            | Processing — the transfer is processing                                                                                    |
| `sent`                  | Sent — funds have been sent to the bank or platform                                                                        |
| `succeeded`             | Succeeded — the transfer has been completed successfully                                                                   |
| `failed`                | Failed — the transfer processing has failed                                                                                |
| `canceled`              | Canceled — the transfer has been canceled by the merchant                                                                  |
| {% endstep %}           |                                                                                                                            |
| {% endstepper %}        |                                                                                                                            |

## Signature header with SHA256withRSA

### Signature Generation Rule:

Signature format:

```java
SHA256withRSA (requestPath + "." + requestParameters + "." + requestBody, privateKey);
```

* requestPath: String of requestPath parameters for GET requests or POST requests.
  * Parameters must be sorted in ASCII order by key name.
  * The signature uses the concatenated values of these parameters (e.g., for bb=22\&aa=11, the ordered values are 11 and 22, resulting in 1122).
* requestParameters: String of request parameters for GET requests or POST form submissions.
  * Parameters must be sorted in ASCII order by key name.
  * The signature uses the concatenated values of these parameters (e.g., for bb=22\&aa=11, the ordered values are 11 and 22, resulting in 1122).
* requestBody: The body of the POST request (if present).
* key:
  * For API requests, use the RSA PrivateKey.

If any of the required headers are not applicable for a specific API endpoint, their values should be set as empty strings. When constructing the signature string, omit the . separator if either requestBody or requestParameters is absent.

### Example

* beneficiary/create: Signature=SHA256withRSA (requestBody, privateKey)
* beneficiary/{id}/update: Signature=SHA256withRSA (id + "." + requestBody, privateKey)
* beneficiary/{id}: Signature=SHA256withRSA (id, privateKey)
* beneficiary/{id}/delete: Signature=SHA256withRSA (id, privateKey)

### RSA generate script

After generating the RSA public key (cert.crt) and private key (private\_pkcs8.pem), please safeguard the private key securely and email the public key—along with your MID—to us.

```shell
#!/bin/sh

echo "GENERATING PRIVATE KEY...";
openssl genrsa -des3 -out private.pem 2048

if [ -f private.pem ]
then
echo "=======================\n";
echo "GENERATING NEW CSR...";
openssl req -new -key private.pem -out certfile.csr
else
echo "ERROR in GENERATING PRIVATE KEY...ABORTING";
fi;



if [ -f certfile.csr ]
then
echo "=======================\n";
echo "GENERATING SELF SIGN CERTIFICATE";
openssl x509 -req -days 3650 -in certfile.csr -signkey private.pem -out cert.crt
openssl pkcs8 -topk8 -inform PEM -in private.pem -outform PEM -nocrypt -out private_pkcs8.pem
else
echo "ERROR in GENERATING SELF SIGN CERTIFICATE...ABORTING";
fi;
```

### Java demo

```java
/**
 * Private Key Signing
 */
public static String sign(String data, String privateKeyPemPath){
    try {
        // 1. read Private Key
        String key = Files.readString(Paths.get(privateKeyPemPath));

        // 2. Remove Tags and Line Breaks (for PKCS#8 Format)
        String privateKeyPEM = key
                .replace("-----BEGIN PRIVATE KEY-----", "")
                .replace("-----END PRIVATE KEY-----", "")
                .replaceAll("\\s+", ""); // Remove all spaces and line breaks.

        // 3. Base64 Decoding
        byte[] keyBytes = Base64.getDecoder().decode(privateKeyPEM);

        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory kf = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = kf.generatePrivate(spec);

        Signature signature = Signature.getInstance(SIGN_ALGORITHM);
        signature.initSign(privateKey);
        signature.update(data.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(signature.sign());
    } catch (Exception e) {
        log.error("Private Key Signing Error", e);
        return null;
    }
}

/**
 * Public Key Signature Verification (Supports .crt Certificate Files)
 */
public static boolean verify(String data, String sign, String publicKeyPemPath){
    try {
        PublicKey publicKey;
        // If the certificate file is in .crt or .cer format, using `CertificateFactory` is a safer approach.
        try (FileInputStream fis = new FileInputStream(publicKeyPemPath)) {
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            X509Certificate cert = (X509Certificate) cf.generateCertificate(fis);
            publicKey = cert.getPublicKey();
        }

        Signature signature = Signature.getInstance(SIGN_ALGORITHM);
        signature.initVerify(publicKey);
        signature.update(data.getBytes(StandardCharsets.UTF_8));
        return signature.verify(Base64.getDecoder().decode(sign));
    } catch (Exception e) {
        log.error("Public Key Signature Verification Error", e);
        return false;
    }
}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.moneycollect.com/docs/payment/disbursement.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
