Quickstart
From zero to a paid bill.
1. Get an API key
Sign in to the partner dashboard at https://billy.finfactory.dev/partners and issue a key under Developer → API keys. The key is shown once — Billy stores only a hash and can't recover it later.
2. Set your environment
export KEY=billy_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
export BILLY=https://bills.finfactory.dev/api/v1
3. Check your float
Billy pays billers out of a balance you fund in advance. Confirm you have one before anything else — spendable is what a payment can draw on.
curl -H "Authorization: Bearer $KEY" "$BILLY/wallet"
{
"data": {
"currency": "PHP",
"available": "10000.00",
"held": "0.00",
"total": "10000.00",
"credit_limit": "0.00",
"spendable": "10000.00"
}
}
Empty? See Your float for how to top up.
4. Find a biller
The id in each result is the biller's opaque public_id (a ULID) — use it for detail, quote, and payment calls.
curl -H "Authorization: Bearer $KEY" "$BILLY/billers?search=pldt"
5. Read the biller's fields
The detail response includes the field schema, the current fee, and policies — everything you need to build the payment form.
curl -H "Authorization: Bearer $KEY" "$BILLY/billers/01KTQCYWKEW9ZX0BS1CTHFYR8B"
{
"data": {
"name": "PLDT",
"fields": [
{
"position": 1,
"name": "10 Digit Account Number",
"format": "numeric",
"width": 10,
"required": true,
"validation_regex": "^[0-9]{10}$"
}
]
}
}
position. You send fields back keyed as field_1, field_2… by position — not by name. This catches almost everyone once.6. Quote a payment
Send an amount; get back Billy's fee and the total the customer pays. The quote runs the same calculation the payment does, so it can't disagree with what you're charged.
curl -H "Authorization: Bearer $KEY" \
-d '{"amount": 1500}' \
"$BILLY/billers/01KTQCYWKEW9ZX0BS1CTHFYR8B/quote"
{
"data": {
"amount": "1500.00",
"convenience_fee": "20.00",
"platform_fee": "25.00",
"gateway_fee": "0.00",
"customer_total": "1545.00",
"currency": "PHP"
}
}
Add "funding_source": "collect" to quote a Billy-collects payment. Collect adds a gateway_fee — the payment gateway's charge, surcharged to the payer — so its customer_total is higher than the same bill on wallet. Wallet payments always have gateway_fee of 0.00.
7. Pay the bill
Post the payment with an idempotency key so a retry can never pay twice.
curl -H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"amount": 1500, "fields": {"field_1": "1234567890"}}' \
"$BILLY/billers/01KTQCYWKEW9ZX0BS1CTHFYR8B/payments"
{
"data": {
"id": "01kxjehb1aa3ztdy315q0ffbdh",
"status": "processing",
"customer_total": "1545.00",
"reference": null
}
}
processing means the money is reserved and Billy is posting the bill. It is not yet paid.
8. Find out how it went
Read it back:
curl -H "Authorization: Bearer $KEY" "$BILLY/payments/01kxjehb1aa3ztdy315q0ffbdh"
{
"data": {
"id": "01kxjehb1aa3ztdy315q0ffbdh",
"status": "succeeded",
"reference": "ECPAY-X8MGLSTUPS"
}
}
succeeded with a reference — the bill is paid and that's your receipt. In production, don't poll for this: add a webhook and let Billy tell you.
Next steps
- Your float — balances, holds, top-ups, and the
402you'll eventually hit. - Making a payment — the full flow, including letting Billy collect from your end-user.
- Webhooks — get the outcome pushed to you, and verify it's really Billy.
- Errors & idempotency — retry safely.
- API reference — every endpoint, parameter, and schema.