Stripe Webhook
POST /io/wallet/webhook — Stripe webhook that credits the wallet on a completed top-up payment. Idempotent.
The endpoint Stripe calls to confirm top-up payments. On a checkout.session.completed event for a wallet top-up, the wallet grants credits to the user. You do not call this endpoint yourself — Stripe does.
POST https://api.misar.io/io/wallet/webhook
Authentication
Authenticated by the Stripe webhook signature (Stripe-Signature header), verified against the endpoint's signing secret. There is no Misar API key on this route. Requests with a missing or invalid signature are rejected with 400.
Behavior
Verify the signature
The raw request body is verified against the Stripe signing secret. Invalid signatures are rejected.
Match the event
Only checkout.session.completed events whose session metadata type is wallet_topup grant credits. All other event types are acknowledged and ignored.
Grant credits
Base credits = amount_subtotal / 100 — the pre-tax subtotal (Stripe reports amounts in cents, so $25.00 → 2500 cents → 25 base credits; 1 credit = $1). When automatic tax is enabled, tax is charged on top of the credit price and never mints extra credits. The applicable volume-discount bonus is added on top. The bonus is recomputed from the Stripe-confirmed amount — session metadata is never trusted.
Record the invoice
The Stripe invoice id, hosted receipt URL, billing country, and collected tax amount are stored on the ledger entry (best-effort — a failure here never blocks the credit grant). The receipt URL is exposed as receipt_url on List Transactions.
Acknowledge
The wallet returns 200 so Stripe marks the event delivered.
Idempotency
Safe to redeliver
The webhook is idempotent. Stripe may deliver the same event more than once; the wallet keys the credit grant on the Stripe session id, so a given top-up is credited exactly once no matter how many times the event arrives. Redelivering a processed event is a no-op.
Credit conversion
Base credits equal the pre-tax dollars charged for credits; the volume-discount bonus is then added. Any tax collected on top (when automatic tax is enabled) is excluded from the conversion.
Stripe amount_subtotal (cents) | Dollars | Bonus | Credits granted |
|---|---|---|---|
1000 | $10 | 0% | 10 |
2500 | $25 | 0% | 25 |
5000 | $50 | 3% | 51 |
25000 | $250 | 6% | 265 |
100000 | $1,000 | 10% | 1100 |
Credits = amount_subtotal / 100 + bonus.
Configuration
Point a Stripe webhook endpoint at https://api.misar.io/io/wallet/webhook and subscribe to checkout.session.completed. Set the endpoint's signing secret in the wallet service's environment so signature verification succeeds.