Stripe & webhooks¶
Gringotts sells credits through your Stripe account with Stripe Checkout, and keeps balances correct as payments settle, get refunded, or are disputed.
Configuration¶
Set two secrets (directly on GringottsConfig or via the environment):
export STRIPE_SECRET_KEY=sk_live_...
export STRIPE_WEBHOOK_SECRET=whsec_...
Define your packs in code — no Stripe Dashboard product setup is needed:
GringottsConfig(
packs=[
CreditPack(credits=100, price_cents=500, name="Starter"),
CreditPack(credits=1000, price_cents=4000, name="Pro"),
],
stripe_secret_key="sk_live_...",
stripe_webhook_secret="whsec_...",
)
All packs must share one currency.
Webhook events to register¶
Point a Stripe webhook at POST {mount_path}/webhook and subscribe to:
Event |
Why |
|---|---|
|
Grant credits once a payment is |
|
Delayed methods (e.g. ACH) settle after the completed event — credit only then. |
|
Claw back a proportional share of the granted credits when a payment is refunded. |
|
Claw back the purchase when a dispute pulls funds. |
|
Re-credit if the dispute is later resolved in your favor. |
Every event is signature-verified against STRIPE_WEBHOOK_SECRET; an invalid
signature is rejected with 400.
Crediting¶
Credits are granted only once the checkout session’s payment_status is paid
(or no_payment_required). Before redirecting the buyer, Gringotts persists the
authorized user, credits, amount, and currency in checkout_orders. Fulfillment
requires the signed Session to match that local order exactly; unrelated Checkout
integrations on the same Stripe account are ignored. Idempotency is keyed on the
checkout session id, so Stripe re-delivering an event—or sending more than one
event for the same session—never double-credits.
Clawback (refunds and disputes)¶
When a payment is reversed, gringotts reverses the credits it granted:
Refunds claw back proportionally: a refund of
Rof a payment ofCthat grantedNcredits reversesround(N × R ⁄ C). Multiple partial refunds are tracked cumulatively, so rounding never over- or under-claws.Disputes claw back on
funds_withdrawnand re-credit onfunds_reinstated. Inquiry (warning_*) events move no money and are ignored.Clawback is clamped at zero — it never drives a balance negative, deducting only the credits the user still holds. When it can’t fully recover, it logs a warning so you can follow up.
It’s idempotent on the Stripe
Refund/Disputeid, and correlates events to the original purchase by the PaymentIntent recorded at Checkout time.
Zero-decimal currencies¶
price_cents is the amount in the currency’s smallest unit. For zero-decimal
currencies (JPY, KRW, and others), that unit is the whole currency — price_cents=500
means ¥500, not ¥5.00 — and gringotts displays it accordingly.
Purchase, refund, dispute, and reinstatement rows retain the ISO currency, so
historical revenue is totaled separately per currency.
Local testing¶
stripe listen --forward-to localhost:8000/gringotts/webhook
Upgrading¶
Run gringotts migrate after upgrading. Drain Checkout Sessions created by 0.3.x
before moving to 0.4.0; the new release fulfills only Sessions backed by a local
checkout_orders row. Two older caveats remain:
Purchases recorded by 0.1.x were keyed on the Stripe event id, not the checkout session. Drain any in-flight delayed payments before upgrading so a settlement arriving afterward isn’t credited twice.
Clawback correlates only purchases made on 0.3.0+ (older rows have no stored PaymentIntent); a refund or dispute on a pre-0.3 purchase is logged, not auto-clawed.