Same request. Same result.
A repeated operation key returns its original result. A changed request with the same key fails.
A CONVEX COMPONENT BY CLIPIN
Credit balances for work that takes time. Reserve before a job starts. Complete when it succeeds. Return credits when it fails.
Open source · Apache-2.0 · Runs inside Convex
Try a successful job, a failure, or a repeated callback.
Browser simulation. No account or real credits are used.
A repeated operation key returns its original result. A changed request with the same key fails.
A successful job has one debit. Its status changes without adding another credit movement.
Your app sets prices and verifies payments. The component controls balance changes and charge transitions.
SMALL API. EXPLICIT OUTCOMES.
Use the same charge throughout your workflow. Keep pricing and provider calls in your app.
Understand the lifecycle ↗const charge = await credits.reserve(ctx, {
owner: userId,
amount: 10,
key: requestId,
reason: "Image generation",
reference: jobId,
});
// After the job succeeds, in a mutation:
await credits.complete(ctx, {
chargeId: charge.chargeId,
key: requestId + ":complete",
});