Single Payments
Not every charge needs a group. The payments API charges one payer a
one-off amount with the same hosted checkout: create a payment, share the
returned checkout_url, get webhooks when it’s paid. Under the hood a single
payment is a one-slot group payment, so it inherits the whole engine - provider
cascade, state machine, reminders and expiry handling - without a second
integration.
Full request/response shapes live in the interactive API Reference .
Create a payment
Amounts are in currency units (e.g. 50.00), not cents. expires_at
defaults to 24h from now and is capped at 7 days. The optional customer
pre-assigns the payer - Payylo can then email them reminders before the payment
expires, and the checkout is smoother because the payer is already known.
curl https://api.payylo.com/v1/payments \
-H "Authorization: Bearer $PAYYLO_SECRET_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"amount": 50.00,
"currency": "USD",
"description": "Consulting - June",
"customer": { "email": "payer@example.com", "name": "Alice" },
"metadata": { "invoice": "INV-042" }
}'description (max 80 chars) is shown to the payer at checkout. Add an
Idempotency-Key header to make POSTs safe to retry.
Understand the response
{
"payment": {
"id": "eda0165c-7c2f-4b1e-9a3d-1f2e3d4c5b6a",
"merchant_id": "…",
"amount": 50.0,
"currency": "USD",
"status": "pending",
"description": "Consulting - June",
"expires_at": "2026-06-21T18:00:00Z",
"metadata": { "invoice": "INV-042" },
"created_at": "2026-06-20T18:00:00Z",
"updated_at": "2026-06-20T18:00:00Z"
},
"checkout_url": "https://checkout.payylo.com/g/eda0165c-…"
}Send checkout_url to the payer - by email, WhatsApp, a QR code, or a redirect
from your site. They open it, pick their payment method and pay; you’re
notified via webhooks.
Payment statuses
The group state machine is mapped to a simple status:
| Status | Meaning |
|---|---|
pending | Created, awaiting payment. |
authorized | Funds held (card preauthorisation), not yet captured. |
paid | Captured - the money is yours. |
expired | expires_at passed without payment (holds released). |
cancelled | Cancelled before completion. |
refunded | Captured money was refunded (fully or partially). |
failed | A capture or refund failed and needs attention. |
Retrieve and list
# Retrieve one payment
curl https://api.payylo.com/v1/payments/eda0165c-… \
-H "Authorization: Bearer $PAYYLO_SECRET_KEY"
# → { "payment": { … }, "checkout_url": "…" }
# List, most recent first
curl "https://api.payylo.com/v1/payments?limit=20&offset=0" \
-H "Authorization: Bearer $PAYYLO_SECRET_KEY"
# → { "payments": [...], "pagination": { "limit", "offset", "total", "has_more" } }Webhooks for single payments
A single payment is a group payment, so the webhook events are
the same - group_payment.paid fires when it’s paid, and
data.group_payment_id equals the payment id:
{
"type": "group_payment.paid",
"data": {
"group_payment_id": "eda0165c-…",
"state": "paid"
}
}Expiry works the same way too: a daily sweep closes unpaid payments past
expires_at - see
Group expiry and automatic refunds.
Next Steps
- Payment Flow - how charges move through the state machine
- Webhooks - real-time events and signature verification
- Embedded Checkout - take the payment inside your own site
- API Reference - every endpoint, try it live