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.
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.