Deduct credits
POST /io/wallet/deduct — atomically charge credits for a feature. Service-key only, fail-closed, idempotent.
Atomically charges credits against a user's balance for a billable feature. The check (does the user have enough?) and the debit happen in a single atomic operation, so concurrent calls can never overspend.
POST https://api.misar.io/io/wallet/deduct
Service key only
Charging credits is never client-initiated. This endpoint requires x-wallet-service-key and rejects SSO bearer tokens.
Authentication
x-wallet-service-key: <WALLET_SERVICE_KEY>
Content-Type: application/json
Body parameters
user_idstringrequiredThe Misar SSO user id to charge.
featurestringrequiredThe billable feature key (e.g. blog.article.generate). The number of credits charged is count multiplied by the feature's per-unit rate from the credit rate table.
countnumberdefault: 1How many units of the feature to charge. Defaults to 1.
idempotency_keystringA stable key (e.g. article slug, job/run id) that makes retries safe. Re-sending the same idempotency_key will not double-charge — the original result is returned. See Idempotency & concurrency.
Request
curl -X POST "https://api.misar.io/io/wallet/deduct" \
-H "x-wallet-service-key: $WALLET_SERVICE_KEY" \
-H "Content-Type: application/json" \
-d '{
"user_id": "usr_123",
"feature": "blog.article.generate",
"count": 1,
"idempotency_key": "article:my-post-slug"
}'Response
When the charge succeeds:
{
"allowed": true,
"balanceBefore": 42,
"balanceAfter": 41,
"deducted": 1
}When the user lacks sufficient credits, nothing is debited:
{
"allowed": false,
"balanceBefore": 0,
"required": 1
}allowedbooleantrue if the credits were debited; false if the balance was insufficient or the request failed. Always check this before granting the feature.
balanceBeforenumberThe balance immediately before this operation.
balanceAfternumberThe balance after a successful debit. Present only when allowed is true.
deductednumberThe number of credits actually debited. Present only when allowed is true.
requirednumberHow many credits the operation needed. Present when allowed is false so you can prompt the user to top up by the shortfall.
Fail-closed behavior
A failure denies usage — never grants it
If the ledger is unreachable, the request times out, or the response is malformed, the wallet (and the SDK) return allowed: false. Treat allowed: false as "do not run the billable feature." A billing outage must never result in free usage. See Errors & fail-closed.
Recommended flow
Deduct first
Call deduct with a stable idempotency_key before doing the billable work.
Gate on allowed
If allowed is false, stop and surface a top-up prompt (use required to show the shortfall).
Run the feature
Only proceed when allowed is true.