# Accepting a payment

A collection moves money from your customer into your balance: create it, show the next action, learn the result.

```mermaid
sequenceDiagram
  autonumber
  participant C as Customer
  participant S as Your server
  participant API as Partner API
  participant H as Your webhook endpoint
  C->>S: Checkout
  S->>API: POST /payments (direction: collection)
  API-->>S: 201 — state: created
  S->>API: GET /payments/{id}/next_action
  API-->>S: display_qr or redirect
  S->>C: Show QR / redirect
  C->>C: Pays in banking app
  API->>H: payment.succeeded
  H-->>API: 2xx
  S->>API: GET /payments/{id}
  API-->>S: state: succeeded
  S->>C: Order confirmed
```

## 1. Create

```http
POST /v1/payments HTTP/1.1
Authorization: Bearer <your API key>
Idempotency-Key: order-4821-attempt-1
Content-Type: application/json

{
  "direction": "collection",
  "amount": "150.00",
  "currency": "MYR",
  "method": "duitnow",
  "country": "MY",
  "merchant_reference": "order-4821"
}
```

- `201` → payment in state `created`. Store its `id`.
- `merchant_reference` is yours, echoed on every read and event.
- Available `method` values depend on your account and country.

## 2. Show the next action

- Usually **not** in the create response. It appears once the payment is `processing`.
- Fetch it: `GET /payments/{id}/next_action`.
- `404` `no_next_action` while still `created` → retry in a second.

| `type` | Do | Expires |
|---|---|---|
| `display_qr` | Render `fields.qr_payload` as a QR code. Never as text. | At `expires_at` (~1 min) |
| `redirect` | Send the browser to `url` | No |
| Anything else | Show "action pending". New types get added. | — |

### Keep the QR fresh

```mermaid
sequenceDiagram
  participant S as Checkout page
  participant API as Partner API
  S->>API: GET /payments/{id}/next_action
  API-->>S: QR A, expires 09:32:22
  S->>API: 09:32:15 — GET /payments/{id}/next_action
  API-->>S: QR B, expires 09:33:21
```

- Re-fetch a few seconds before `expires_at`. Don't cache.

## 3. Learn the result

| Event | State | Do |
|---|---|---|
| `payment.succeeded` | `succeeded` | Fulfil |
| `payment.partial` | `partial` | Handle shortfall (`settled_total`) |
| `payment.failed` | `failed` | Offer a retry (new payment) |

- Events can repeat and arrive out of order. On any event, `GET /payments/{id}` and act on `state`.
- **No event on expiry.** No answer by your checkout timeout → read the payment.

## 4. Reconcile

- `settled_total` = credited to you, after fee.
- `fee_amount` = our fee.
- `settled_total + fee_amount` = what the customer paid.

## Troubleshooting

| You see | Do |
|---|---|
| Timeout on `POST /payments` | Retry, **same** key |
| `409` `idempotency_conflict` | New payment → new key |
| `404` `no_next_action` on `created` | Retry in a second |
| `502` `processing_error` on `next_action` | Retry shortly |
| Still `processing` after your timeout | Check later |

Next: [Sending a payout](/guides/sending-a-payout).

---

Part of the Partner API guides: https://docs.beever.xyz/guides/. Full reference: https://docs.beever.xyz
