Guides

Invoices & Payments

Manage invoices and process payments through multiple providers.

PimaBill automatically generates invoices for subscriptions and processes payments through your configured providers.

Invoice Lifecycle

DRAFT → PENDING → PAID
                → FAILED → PAID (after retry)
                → CANCELED (voided)
StatusMeaning
DRAFTBeing prepared; can still be changed. Finalize it to send it.
PENDINGSent and waiting for payment. If amountPaid is above zero, it has been partially paid.
PAIDPayments cover the whole amount. paidAt is when that happened.
FAILEDAn automatic charge failed; it is retried, and it can still be paid by link or marked paid.
CANCELEDVoided; it can no longer be paid.

Every invoice has amount (the total) and amountPaid (what has been paid so far). What's still due is amount − amountPaid.

Paying in parts

An invoice can be paid in several payments: a deposit, then instalments. Each payment is added to amountPaid; the invoice stays PENDING until the payments cover it, then becomes PAID.

  • Online: POST /api/invoices/{id}/checkout with { "amount": 50000 } charges that much. Without amount, a checkout charges everything still due, so a second link after a deposit asks only for the rest.
  • Offline (cash, bank transfer, mobile money to your own number): POST /api/invoices/{id}/mark-paid with { "paymentMethod": "cash", "amount": 50000 }. Without amount, it records everything still due. In the dashboard, Mark paid has an Amount received field.
  • At creation: checkout.amount on POST /api/invoices takes a deposit in the same call.

Each part payment sends invoice.partially_paid (with amountPaid, amountDue and total); the last one sends invoice.paid. See One-time products & partial payments for a full walkthrough.

List Invoices

curl "http://localhost:4000/api/invoices?status=PENDING&page=1&limit=20" \
  -H "Authorization: Bearer sk_live_a1b2c3d4..."

Create a Manual Invoice

curl -X POST http://localhost:4000/api/invoices \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer sk_live_a1b2c3d4..." \
  -d '{
    "customerId": "cust_x1y2z3",
    "dueDate": "2025-02-28",
    "items": [
      {"description": "Pro Plan - Monthly", "quantity": 1, "unitAmount": 180000}
    ]
  }'

Finalize and Pay

# Finalize a draft invoice
curl -X POST http://localhost:4000/api/invoices/inv_abc123/finalize \
  -H "Authorization: Bearer sk_live_a1b2c3d4..."

# Mark as manually paid (add "amount" to record only part of it)
curl -X POST http://localhost:4000/api/invoices/inv_abc123/mark-paid \
  -H "Authorization: Bearer sk_live_a1b2c3d4..." \
  -H "Content-Type: application/json" \
  -d '{"paymentMethod": "bank_transfer"}'

# Void an invoice
curl -X POST http://localhost:4000/api/invoices/inv_abc123/void \
  -H "Authorization: Bearer sk_live_a1b2c3d4..."

Download PDF

curl "http://localhost:4000/api/invoices/inv_abc123/pdf" \
  -H "Authorization: Bearer sk_live_a1b2c3d4..." \
  -o invoice.pdf

Checkout

Generate a hosted checkout URL for an invoice so customers can pay online. It charges what is still due, or amount if you pass one (see Paying in parts). Pass providerName to choose a provider; otherwise your highest-priority active provider is used, and managed payments when none of yours can take it:

curl -X POST http://localhost:4000/api/invoices/inv_abc123/checkout \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer sk_live_a1b2c3d4..." \
  -d '{}'

Payments

Payments are created automatically when invoices are processed. You can list and refund them.

List Payments

curl "http://localhost:4000/api/payments?page=1&limit=20" \
  -H "Authorization: Bearer sk_live_a1b2c3d4..."

Refund a Payment

curl -X POST http://localhost:4000/api/payments/pay_abc123/refund \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer sk_live_a1b2c3d4..." \
  -d '{
    "amount": 50000,
    "reason": "Customer overcharged"
  }'

The refund goes back through the provider that took the payment (pass "recordOnly": true if you already refunded it elsewhere), and a payment can be refunded once. What was refunded comes off the invoice's amountPaid:

  • An open invoice (a deposit or instalment was refunded) is due that much more again.
  • A paid invoice stays PAID; the refund is recorded on the payment, and payment.refunded is sent.
  • A duplicate payment (money that arrived after the invoice was already paid or voided, flagged by payment.duplicate) never counted toward the invoice, so refunding it leaves the invoice as it is.

Payment Statuses

StatusDescription
PENDINGPayment initiated but not yet processed
PROCESSINGPayment is being processed by the provider
SUCCEEDEDPayment completed successfully
FAILEDPayment attempt failed
REFUNDEDPayment has been refunded
Copyright © 2026