Skip to content

Direct Payments

A direct payment is a payment for one specific payment_method — QRIS or a bank virtual account — with no hosted Baiyar page involved. Use this when you want to render the QR code or virtual account number inside your own app instead of sending the customer to a payment link.

POST /v1/payments
Idempotency-Key: order-2026-0002-attempt-1
{
"project_id": "018f1f29-7c00-73e4-a310-744d2167fc60",
"reference": "ORDER-2026-0002",
"amount": 15000,
"payment_method": { "type": "qris" }
}

Idempotency-Key is required — a unique string you generate per payment attempt (a UUID works well). Retrying the same key with an identical body returns the original payment (200) instead of creating a duplicate (201); retrying with a different body is rejected with 409. This makes it safe to retry on a network timeout without risking a duplicate charge.

The response includes instructions, shaped differently per method:

  • QRISqr_string (the raw QRIS payload, if you want to render your own QR code) and qr_image_url (a ready-to-display QR code image as a data: URI).
  • Virtual accountbank_name, virtual_account_number, and payment_steps (human-readable instructions you can display as-is).
QRIS response
{
"id": "018f1f29-9b21-73e4-a310-744d2167fca1",
"project_id": "018f1f29-7c00-73e4-a310-744d2167fc60",
"reference": "ORDER-2026-0002",
"amount": 15000,
"currency": "IDR",
"fee_bearer": "merchant",
"fee_amount": 105,
"merchant_net": 14895,
"status": "pending",
"checkout_url": "https://checkout.baiyar.id/sandbox/payments/sandbox_018f...",
"payment_method": { "type": "qris" },
"instructions": {
"qr_string": "BAIYAR-SANDBOX-QRIS|sandbox_018f...|15000|IDR",
"qr_image_url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
},
"expires_at": "2026-09-02T09:15:00Z",
"created_at": "2026-09-02T09:00:00Z"
}
Virtual account response (instructions only)
{
"bank_name": "Bank BNI",
"virtual_account_number": "8808123456789",
"payment_steps": [
"Open mobile banking.",
"Choose virtual account transfer.",
"Enter the virtual account number."
]
}

amount is in IDR (whole rupiah). The minimum depends on the method:

Method Minimum amount
qris 100
virtual_account 10,000

expires_in_minutes is optional. It defaults to 15 minutes for qris and 24 hours for virtual_account, and is capped at 60 minutes for qris and 7 days for virtual_account.

Poll GET /v1/payments/{paymentID} for status (pending, processing, succeeded, failed, expired), or — better — configure a project webhook so Baiyar notifies you instead. See Payment Statuses for what each value means and Webhooks for push notifications.