Guides
Recipe: API credits
Sell prepaid credits for an API or an AI feature and spend one per request. A short balance answers 402 with a top-up link.
Buyers prepay a pack of credits; every request spends some. Perly Pay is the ledger: spending is one atomic call that refuses an overdraft, and every buyer has their own top-up page. Nothing is ever debited on its own — when credits run out, the buyer tops up. The whole credits feature is in Sell credits; this is the recipe around it.
sell-credits skill of the Perly Pay plugin for Claude Code does this recipe in your project — the plugin and its example, examples/api-credits (MIT), are on their way. Until then, any assistant can read the same skill from /.well-known/skills/perly-pay-sell-credits/SKILL.md.How it works
- 1
A credit pack
A product and a price with
model: "credit_pack",unit_amountin cents andcredits. Made once per mode. - 2
Your users are customers
Made once with
external_id(your user id); from then oncredits.*take that id. - 3
Top up
credits.topUpUrl(userId)is the buyer's own page: they pick a pack and pay. Each paid pack adds credits. - 4
Spend per request
credits.consume(userId, cost, { idempotencyKey })first, then the work. A retry with the same key returns the first spend. - 5
Short?
insufficient_credits(409) spends nothing: answer402with the top-up page, not a 500.
Run the example
- 1
Install
npm installinexamples/api-credits(Node 20.12+). - 2
Key
Copy
.env.exampleto.envand put a test key (sk_test_…) inPERLY_PAY_SECRET_KEY. - 3
Set up
npm run setupmakes the product and price with your key and prints their ids for.env. - 4
Run
npm start(ornpm run dev), as its README says. - 5
Pay without a wallet
Call
POST /v1/shout(402), open the pagePOST /top-upgives, pick the pack, press Simulate payment on the invoice, call again: 200 andX-Credits-Remaining: 499.
Pitfalls
- Spending without an idempotency key: a retried request is charged twice.
- Checking the balance, then spending, as two steps.
consumealone refuses an overdraft; the balance is for display. - Doing the work before spending. Spend first.
- Test ids with a live key. Products, prices and webhook endpoints belong to one mode: run the setup again with
sk_live_…when you go live.