Examples
Prepaid credits
Sell a balance up front, take your margin at the top-up, and let the meter run it down.
The credit model: a customer buys $20 of credit, you keep a share, and the rest is spendable. The markup is taken once, at the top-up, not added to every call, so show that arithmetic plainly in your product. Top-ups always land on the money wallet in micros; they are not tied to a bundle’s named credit currency.
How the markup lands
| They pay | Markup | They can spend | You earn |
|---|---|---|---|
| $10.00 | 20% | $8.33 | $1.67 |
| $25.00 | 20% | $20.83 | $4.17 |
| $100.00 | 10% | $90.91 | $9.09 |
A customer who reads "20% markup" as "+20% on each call" will mis-price their product. The console shows this worked example on the bundle editor so you can explain it the same way.
Granting credit after payment
// your Stripe webhook, after checkout.session.completed
export async function POST(req: Request) {
const event = verifyStripe(req)
if (event.type !== "checkout.session.completed") return new Response(null, { status: 204 })
const user = await db.user.findUnique({ where: { stripeId: event.data.object.customer } })
await seams.grants.issue({
endUsers: [user.id],
amountUnits: String(event.data.object.amount_total * 10_000), // cents → micro-dollars
reason: "top_up",
// the same idempotency key on a retry grants once, not twice
idempotencyKey: event.id,
})
return new Response(null, { status: 204 })
}# your Stripe webhook, after checkout.session.completed
@router.post("/stripe")
async def stripe_webhook(request: Request):
event = verify_stripe(request)
if event.type != "checkout.session.completed":
return Response(status_code=204)
user = await db.user.find_by(stripe_id=event.data.object.customer)
seams.grants.issue(
end_users=[user.id],
amount_units=str(event.data.object.amount_total * 10_000), # cents → micro-dollars
reason="top_up",
# the same idempotency key on a retry grants once, not twice
idempotency_key=event.id,
)
return Response(status_code=204)Pass the payment event id as idempotencyKey. Stripe retries webhooks, and a double grant is money you gave away.