Skip to main content

Pay-as-you-go

Beta

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​

  • usage in billingModes of your payment account.
  • A token with the charges scope.

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" }
}
statusMeaningTo do
succeededcharged, invoice issuednothing
processingbeing confirmedwait for charge.succeeded or charge.failed
requires_actionthe bank requires strong authentication from your customersend them action_url
faileddeclined (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_url takes your customer to a payment page in your colours to settle this charge; you receive charge.action_required or charge.failed, and new attempts follow dunning of your account.
  • One invoice per successful charge, showing the period (period_start, period_end).

If it does not work​

What you seeCauseFix
Charge rejected for lack of Idempotency-Keyheader required on this chargeadd it
409same Idempotency-Key with a different bodyone key per customer and period
Charge rejected, has_payment_method: false on the customerthe customer has not saved a payment method yetsend them a new setup link
requires_action every monththe customer's bank always asks for authenticationsend action_url; offer PayPal
Setup link expiredttl_seconds exceededcreate a new one

See also Payments troubleshooting.

See also​