Pay-as-you-go
Being rolled out. The interface described here is the one of the next release: it may still change, and may not be enabled on your tenant yet.
What it is for
When the amount changes every month (consumption, hours, volume), your customer saves their payment method once; then your application sends the cart of their consumption every month and the platform charges it right away, then issues the invoice.
Prerequisites
usageinbillingModesof your payment account.- A token with the
chargesscope.
1. Register the customer
curl -s -X PUT https://billing-api.dev.stackngo.fr/v1/customers \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{
"external_ref": "user-381",
"name": "Dupont Conseil",
"email": "compta@dupont.example",
"vat_number": "FR40552100554",
"address": { "line1": "3 place Bellecour", "postal_code": "69002", "city": "Lyon", "country": "FR" }
}'
{ "id": "cus_01J9ZR1A2B3C4D5E6F7G", "external_ref": "user-381", "name": "Dupont Conseil", "has_payment_method": false, "created_at": "2026-10-08T10:30:00Z", "…": "…" }
PUT /v1/customers creates the customer, or updates it if one already exists with this
external_ref.
2. Have them save their payment method
curl -s -X POST https://billing-api.dev.stackngo.fr/v1/customers/cus_01J9ZR1A2B3C4D5E6F7G/setup-links \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{ "provider": "stripe", "return_url": "https://shop.acme.example/compte", "ttl_seconds": 86400 }'
{ "url": "https://pay.dev.stackngo.fr/acme/…", "expires_at": "2026-10-09T10:31:00Z" }
Send this link to your customer. They save their card there (or their PayPal account with
"provider": "paypal") without paying anything. Afterwards, GET /v1/customers/{id} returns
"has_payment_method": true.
3. Charge the month's cart
curl -s -X POST https://billing-api.dev.stackngo.fr/v1/customers/cus_01J9ZR1A2B3C4D5E6F7G/charges \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-H "Idempotency-Key: usage:user-381:2026-10" \
-d '{
"currency": "EUR",
"period_start": "2026-10-01",
"period_end": "2026-10-31",
"lines": [
{ "label": "Appels API", "quantity": "182000", "unit_amount": "0.0004", "tax_category": "S", "tax_rate": "20.00" },
{ "label": "Stockage", "quantity": "37", "unit_code": "E34", "unit_amount": "0.10", "tax_category": "S", "tax_rate": "20.00" }
],
"tags": { "shop": "api", "period": "2026-10" }
}'
Idempotency-Key is required: use a key that identifies the customer and the period
(usage:<customer>:<month>). If your monthly job is run again, the same call returns the same
charge instead of charging twice.
What you get
{
"id": "chg_01J9ZS3C4D5E6F7G8H9J",
"customer_id": "cus_01J9ZR1A2B3C4D5E6F7G",
"status": "succeeded",
"currency": "EUR",
"totals": { "subtotal": "76.50", "tax": "15.30", "total": "91.80", "taxes": [ { "category": "S", "rate": "20.00", "basis": "76.50", "amount": "15.30" } ] },
"payment_id": "pay_01J9ZS3D…",
"invoice_id": "inv_01J9ZS3E…",
"created_at": "2026-11-01T06:00:00Z",
"tags": { "shop": "api", "period": "2026-10" }
}
status | Meaning | To do |
|---|---|---|
succeeded | charged, invoice issued | nothing |
processing | being confirmed | wait for charge.succeeded or charge.failed |
requires_action | the bank requires strong authentication from your customer | send them action_url |
failed | declined (failure_code) | send them action_url; the platform retries at next_retry_at |
What you can expect
- Never a double charge for the same
Idempotency-Key. Reusing a key with a different body is rejected (409). - The charge is immediate, without your customer having to do anything, as long as their bank accepts it.
- On strong authentication or decline,
action_urltakes your customer to a payment page in your colours to settle this charge; you receivecharge.action_requiredorcharge.failed, and new attempts followdunningof your account. - One invoice per successful charge, showing the period (
period_start,period_end).
If it does not work
| What you see | Cause | Fix |
|---|---|---|
Charge rejected for lack of Idempotency-Key | header required on this charge | add it |
409 | same Idempotency-Key with a different body | one key per customer and period |
Charge rejected, has_payment_method: false on the customer | the customer has not saved a payment method yet | send them a new setup link |
requires_action every month | the customer's bank always asks for authentication | send action_url; offer PayPal |
| Setup link expired | ttl_seconds exceeded | create a new one |
See also Payments troubleshooting.