# Create Payment


> Create single or bulk payment transactions.

Canonical: https://docs.chiwapay.com/payments

`POST /payments`

Creates payment transactions. The request can contain a single transaction or a bulk payload through the `payments` field.

## Headers

| Header | Required | Description |
| --- | --- | --- |
| `Authorization` | Yes | `Bearer sk_xxx` |
| `Content-Type` | Yes | `application/json` |
| `Idempotency-Key` | No | Unique ID for a single request. For bulk, use `payments[].idempotency_key`. |

## Body Fields

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `amount` | integer | Yes for single request | Order amount. |
| `currency` | string | No | Default `IDR`. |
| `payment_method` | string | No | Default `qris`. Currently only `qris` is supported. |
| `provider` | string | No | `gopay` or `shopeepay`. Defaults to `gopay` for compatibility. Also applies to each `payments[]` item. The provider must be enabled for the merchant. |
| `merchant_reference_id` | string | No | Order ID from the merchant system. |
| `customer` | object | No | Customer data. |
| `metadata` | object | No | Extra merchant data. |
| `payments` | array | No | Transaction list for bulk create. Maximum `50` items per request. |
| `payments[].idempotency_key` | string | Recommended | Unique ID per bulk item. |

## Payment Method Fields

| Field | Description |
| --- | --- |
| `payment_method` | Payment method code. If empty, the API uses `qris`. |
| `provider` | QRIS provider. Internal provider accounts are selected automatically and omitted from responses. |
| `qris_payload` | Payment payload in QRIS responses. |
| `qris_image_url` | QR image URL in QRIS responses. |

## Single Request Example

```tsx
<ApiExample
  method="POST"
  path="/payments"
  idempotencyKey="ORDER-1024"
  body={{
    amount: 150000,
    payment_method: "qris",
	provider: "gopay",
    merchant_reference_id: "ORDER-1024",
    customer: {
      name: "Nara",
      email: "nara@example.com"
    }
  }}
/>
```

## Bulk Request Example

```tsx
<ApiExample
  method="POST"
  path="/payments"
  body={{
    payments: [
      {
        amount: 150000,
        payment_method: "qris",
        merchant_reference_id: "ORDER-1024",
        idempotency_key: "ORDER-1024"
      },
      {
        amount: 89000,
        payment_method: "qris",
        merchant_reference_id: "ORDER-1025",
        idempotency_key: "ORDER-1025"
      }
    ]
  }}
/>
```

## Single Response

```json
{
  "payment": {
    "id": "f2b1d5b0-7b1f-4c5d-9c37-93f0c8f6a001",
    "reference_id": "PAY-LXAMPLE",
    "merchant_reference_id": "ORDER-1024",
    "payment_method_code": "qris",
    "provider": "gopay",
    "currency": "IDR",
    "amount": 150000,
    "fee_amount": 1050,
    "net_amount": 150000,
    "total_amount": 151050,
    "status": "pending",
    "qris_payload": "000201010212...",
    "qris_image_url": "<qris_image_url>",
    "expires_at": "2026-05-19T10:30:00Z",
    "created_at": "2026-05-19T10:00:00Z",
    "updated_at": "2026-05-19T10:00:00Z"
  }
}
```

## Bulk Response

```json
{
  "payments": [
    {
      "id": "f2b1d5b0-7b1f-4c5d-9c37-93f0c8f6a001",
      "reference_id": "PAY-LXAMPLE",
      "merchant_reference_id": "ORDER-1024",
      "payment_method_code": "qris",
      "amount": 150000,
      "fee_amount": 1050,
      "net_amount": 150000,
      "total_amount": 151050,
      "status": "pending",
      "expires_at": "2026-05-19T10:30:00Z"
    }
  ]
}
```

## Response Fields

| Field | Description |
| --- | --- |
| `payment.id` / `payments[].id` | Transaction UUID. |
| `payment.reference_id` / `payments[].reference_id` | Chiwa Pay transaction ID. |
| `payment.merchant_reference_id` | Merchant order ID. |
| `payment.payment_method_code` | Payment method. |
| `payment.amount` | Order amount. |
| `payment.fee_amount` | Payment fee. |
| `payment.net_amount` | Amount recorded for the merchant. |
| `payment.total_amount` | Amount the customer must pay. |
| `payment.status` | Transaction status. |
| `payment.expires_at` | Payment deadline; after it passes, pending transactions become `expired`. |

## Fee Payer

| Value | Customer pays | Merchant receives |
| --- | --- | --- |
| `buyer` | `amount + fee_amount` | `amount` |
| `merchant` | `amount` | `amount - fee_amount` |

QRIS is created dynamically by the provider and validated with provider transaction IDs, not amount matching.

## HTTP Error Code

| HTTP | Code | Description |
| --- | --- | --- |
| `400` | `invalid_json` | Body is not valid JSON. |
| `400` | `invalid_amount` | `amount` must be greater than 0. |
| `400` | `invalid_bulk_size` | `payments` must contain 1 to 50 items. |
| `400` | `unsupported_payment_method` | Payment method is not supported. |
| `400` | `payment_create_failed` | Transaction could not be created. |
| `401` | `invalid_api_key` | Secret key is invalid. |
| `403` | `merchant_not_approved` | Merchant is not active. |
| `429` | `rate_limited` | Rate limit exceeded. |
