Payments

A payment represents a single KHQR charge. It moves through a strict lifecycle from creation to a terminal state.

Lifecycle

State machine
pending ──▶ scanned ──▶ paid          (terminal)
   │           │
   ├───────────┴──▶ expired            (terminal)
   ├──────────────▶ failed             (terminal)
   └──────────────▶ cancelled          (terminal)

paid ──▶ refunded / partially_refunded

Transitions are one-way — a terminal payment never changes state (except a paid payment being refunded).

Create a payment

FieldTypeNotes
amountstringRequired. Decimal string, e.g. "1.50".
currencystringRequired. USD or KHR.
reference_idstringYour order id. Returned on the payment and in webhooks.
descriptionstringOptional. Shown on checkout / receipts.
expires_innumberOptional. Seconds until expiry (default set by the provider).
metadataobjectOptional. Key/value pairs echoed back to you.
POST /v1/payments
curl https://api.paykh.cambobia.com/v1/payments \
  -H "Authorization: Bearer bk_test_your_key" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order_1001" \
  -d '{ "amount": "12.00", "currency": "USD", "reference_id": "order_1001" }'
ℹ️ Idempotency
Send an Idempotency-Key header on create. Retrying with the same key returns the original payment instead of creating a duplicate — safe against network retries. A conflicting reuse returns 409 idempotency_conflict.

Retrieve, list, cancel

curl
# Retrieve one
curl https://api.paykh.cambobia.com/v1/payments/pay_123 \
  -H "Authorization: Bearer bk_test_your_key"

# List (paginated)
curl "https://api.paykh.cambobia.com/v1/payments?limit=20" \
  -H "Authorization: Bearer bk_test_your_key"

# Cancel a still-pending payment
curl -X POST https://api.paykh.cambobia.com/v1/payments/pay_123/cancel \
  -H "Authorization: Bearer bk_test_your_key"

Getting notified

Don’t poll in production. Register a webhook and react to payment.completed. For a live UI, the hosted checkout page streams status over SSE.