Ledger API · v1

A balance you can actually trust.

Drop-in ledger for gems, credits, coins, boosts — anything countable your users earn and spend. Atomic spends, idempotent grants, double-entry underneath. You keep your own Stripe.

No card required·5-minute integration·Auth-provider agnostic
POST /v1/spend200 ok
curl https://api.ledge.dev/v1/spend \
  -H "Authorization: Bearer sk_live_51H8x" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"external_id":"user_42",
       "currency":"gems",
       "amount":1600,
       "reason":"gacha_10_pull"}'
{ "transactionId": "ed005177-58e4…",
  "balances": { "gems": 400 } }
Atomic by default
Concurrent spends can't cross zero. No mutex, no retry loop.
Idempotent grants
A retried webhook returns the first result. It never grants twice.
Double-entry underneath
Every entry nets to zero against a reserved issuance account.

If your users can spend it, Ledge can count it.

A 10-pull costs 1,600 gems. Ship it without writing a mutex.
Two taps on a flaky connection can't double-spend, and a retried request can't double-charge. The rejection path is boring on purpose: nothing deducted, balance untouched.
POST /v1/spend
{
  "external_id": "user_42",
  "currency": "gems",
  "amount": 1600,
  "reason": "gacha_10_pull"
}
Six endpoints, that's the whole surface
POST /v1/currenciesdefine gems, credits, coins
POST /v1/grantcredit an account
POST /v1/spenddebit, atomically
POST /v1/transferaccount to account
POST /v1/convertgems → coins, your rate
GET /v1/accounts/…/balanceevery currency, always
No mobile app. No metering problem.
Just a balance and a button.

Everything else assumes you're an app-store business or that you want your billing platform to own your usage data. Ledge assumes neither.