Reading invoices

Fetch and list invoices and track their lifecycle.

After creating an invoice with POST /v1/payment, you can read it back at any time using the merchant API key. Both endpoints require the x-api-key header.

GET /v1/payment/:id

Fetch a single invoice by its payzum ID or by your own order identifier.

# By payzum payment_id
curl -s -H "x-api-key: $PAYZUM_API_KEY" \
  "$PAYZUM_BASE/v1/payment/pzi_abc123" | jq .
 
# By your order_id
curl -s -H "x-api-key: $PAYZUM_API_KEY" \
  "$PAYZUM_BASE/v1/payment/ORDER-12345" | jq .

The :id segment accepts either value. If no invoice matches, the endpoint returns 404 INVOICE_NOT_FOUND.

Response fields

| Field | Description | |-------|-------------| | payment_id | Payzum invoice ID | | payment_status | Current status (see lifecycle below) | | pay_address | Deposit address the buyer must send to | | price_amount | Original price as submitted | | price_currency | Fiat (or crypto) currency of the price | | pay_amount | Exact amount the buyer must send | | pay_currency | Crypto currency code | | amount_received | Amount received on-chain so far | | actually_paid | Mirrors amount_received | | order_id | Your order identifier (nullable) | | network | Chain identifier | | created_at | ISO 8601 creation timestamp | | invoice_url | Hosted checkout URL |

GET /v1/payment

List invoices for the authenticated merchant with optional filters.

Query parameters:

| Parameter | Default | Description | |-----------|---------|-------------| | limit | 20 | Results per page (max 100) | | offset | 0 | Pagination offset | | status | — | Filter by invoice status (e.g. finished, waiting) | | order_id | — | Filter by your order identifier |

# Most recent 20 invoices
curl -s -H "x-api-key: $PAYZUM_API_KEY" \
  "$PAYZUM_BASE/v1/payment" | jq .
 
# Finished invoices, page 2
curl -s -H "x-api-key: $PAYZUM_API_KEY" \
  "$PAYZUM_BASE/v1/payment?status=finished&limit=20&offset=20" | jq .
 
# Look up by your order identifier
curl -s -H "x-api-key: $PAYZUM_API_KEY" \
  "$PAYZUM_BASE/v1/payment?order_id=ORDER-12345" | jq '.data[0].payment_status'

The response envelope has a data array of payment objects and a count field with the total number of matching invoices.

Invoice status lifecycle

Invoices move through statuses in one direction. Terminal statuses are final.

waiting
  │
  ├─→ unconfirmed  (on-chain transaction seen, awaiting confirmations)
  │       │
  │       ├─→ finished       ✓ terminal — full payment confirmed
  │       └─→ partially_paid   (under-payment; buyer can top up)
  │               │
  │               └─→ finished ✓ terminal
  │
  ├─→ expired      ✗ terminal — buyer did not pay before deadline
  ├─→ failed       ✗ terminal — internal processing error
  └─→ cancelled    ✗ terminal — buyer cancelled on the hosted page

Status values

| Status | Meaning | |--------|---------| | waiting | Invoice created; deposit address issued; no on-chain activity yet. | | unconfirmed | A transaction has been broadcast but has not reached the required confirmation count. | | partially_paid | Received amount is less than pay_amount. The invoice stays open for the buyer to top up. | | finished | Full payment confirmed. Funds are credited to the merchant. | | expired | Expiry deadline passed before payment was confirmed. | | failed | An internal error prevented the invoice from completing. | | cancelled | Buyer chose to cancel on the hosted checkout page. |

Polling example

If you cannot receive webhooks, poll GET /v1/payment/:id on an interval until the status is terminal:

async function waitForPayment(invoiceId, intervalMs = 5000) {
  while (true) {
    const res = await fetch(
      `${process.env.PAYZUM_BASE}/v1/payment/${invoiceId}`,
      { headers: { 'x-api-key': process.env.PAYZUM_API_KEY } },
    )
    const invoice = await res.json()
    const status = invoice.payment_status
 
    console.log('Status:', status)
 
    if (['finished', 'expired', 'failed', 'cancelled'].includes(status)) {
      return invoice
    }
 
    await new Promise((r) => setTimeout(r, intervalMs))
  }
}

Polling is fine for low-volume scenarios and development, but for production fulfilment prefer push-based delivery. Configure a webhook URL on your merchant and payzum will POST a signed notification as soon as the invoice status changes. See Webhooks overview for signature verification and retry behaviour.