---
updatedAt: 2026-09-04T14:31:53.000Z
---

Fetch the complete documentation index at: https://developer.benjipays.com/llms.txt. Use this file to discover all available pages before exploring further. Append .md to any documentation page URL to get its markdown version.

# Charge an Invoice

Charge a stored payment method against an invoice with POST /v2/transactions, then poll GET /v2/transactions when the status is not final.

Use `POST /v2/transactions` to charge a stored payment method against one invoice.

You need:

* An `x-api-key` with `organizations:transactions:create`
* A required `Idempotency-Key` header — see [Idempotency](./idempotency.md)

```bash
curl -X POST https://api.benjipays.com/v2/transactions \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Idempotency-Key: a1b2c3d4e5f6" \
  -H "Content-Type: application/json" \
  -d '{
    "invoiceId": "1042",
    "paymentMethodId": "507f1f77bcf86cd799439011",
    "amount": 50.00,
    "sendReceipt": true
  }'
```

## Body

| Field             | Required | Description                                                                                                                                                     |
| ----------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `invoiceId`       | yes      | Invoice `id` from `GET /v2/invoices`.                                                                                                                           |
| `paymentMethodId` | yes      | Stored payment method for that invoice's customer. Must be a 24-character hex id.                                                                               |
| `amount`          | no       | Amount to charge. Omit this field to charge the invoice open balance. Must be greater than `0`, at most two decimal places, and not more than the open balance. |
| `sendReceipt`     | no       | `true` (or omit) sends a receipt email after a successful charge. `false` skips the receipt.                                                                    |

Only `paymentMethodId` is charged. If that method cannot be used, the request fails — another stored method is not tried.

A payment method still pending verification returns `400` with detail `This payment method is still pending verification and cannot be used.`

## Response

**HTTP 200** means the charge was attempted. Read `data` (the transaction) and `meta.effects` (charge, accounting apply, receipt).

A card decline is still `200`. Check `meta.effects.charge.status` (`succeeded`, `failed`, `voided`, or `skipped`) and `data.status`.

**RFC 7807** (`400`, `409`, …) means the charge did not run: bad input, invoice not chargeable, invoice locked, missing `Idempotency-Key`, and similar setup errors.

`503` also means the charge did not run. It is returned when idempotency protection is temporarily unavailable, so we refuse the charge rather than risk a duplicate. Wait `Retry-After` seconds and send the same request again with the same `Idempotency-Key`.

Save `data.id` from the `200` body. Use that id when you look the transaction up later.

## After you charge

Many card charges are finished on the `POST`. `data.status` is then `approved`, `approved_with_error`, or `declined`.

Some charges stay in progress. Poll `GET /v2/transactions` and find the row with your `data.id`. Filter with `invoiceId`, or use `status=inprocess` (that filter ignores `startDate` / `endDate`).

Do not send another `POST` to check status. Use `GET`. A new `POST` can charge again if the original `Idempotency-Key` is no longer cached.

| What you charged              | `data.status` while you wait                                                                                                          | Stop polling when                                                                 |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
| Card                          | Usually already final                                                                                                                 | `approved`, `approved_with_error`, `declined`                                     |
| Bank (for example Bambora)    | `queued` — accepted, not sent to the bank yet. Then `pending` — sent to the bank, waiting on settlement (often business days).        | `approved`, `declined`, `returned`, `bank_failed`, `submit_failed`                |
| Benji Payments void or refund | `approved_void_pending` (usually minutes). This status is not in `status=inprocess` — look up the transaction by `id` or `invoiceId`. | `approved_voided` or `void_failed` (refunds: a completed or failed refund status) |

`GET ?status=inprocess` returns `queued`, `pending`, `pending_account_validation`, and `notified`.

## Retry the accounting writeback

The card can be charged while the writeback to QuickBooks, Xero, or Business Central fails. That is `200` with `meta.effects.charge.status=succeeded` and `meta.effects.accounting.status=failed`.

Keep `data.id`. When your accounting system is back, retry only the writeback — the payment method is never charged again and no receipt is sent:

```bash
curl -X POST https://api.benjipays.com/v2/transactions/66f1a2b3c4d5e6f789012345/retry-accounting \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Idempotency-Key: f6e5d4c3b2a1"
```

No body. `Idempotency-Key` is required, and the scope is the same `organizations:transactions:create`.

The response is always `200` with the current transaction in `data` and one effect:

| `meta.effects.accounting.status` | What it means                                                                                                                                                                                                                                                                                 |
| -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `succeeded`                      | Applied. `data.accountingPaymentId` and `data.paymentApplied` are set.                                                                                                                                                                                                                        |
| `failed`                         | Accounting is still unavailable. Retry later.                                                                                                                                                                                                                                                 |
| `skipped`                        | Nothing to apply. Read `data.status`: a voided status (for example `approved_voided`) means the charge was auto-voided after the first apply failed, so charge again instead of retrying. Otherwise the payment was already applied, or the apply is deferred until a bank payment completes. |

**RFC 7807** means the charge can never have accounting retried: it was declined, it has no invoice, or it is a void / refund / prepayment. A `404` means the id is unknown or belongs to another organization.

## Amount, credit memos, and installments

The amount you charge is the open balance, or the `amount` you send. Open credit memos are not applied on this request.

If the invoice has an installment plan, you still choose the amount (or the full open balance). Charging does not close installment rows. Example: a `$400` invoice with four `$100` rows, charge `$200` — about `$200` remains on the invoice, and the four rows stay open.