The billing decisions nobody talks about
Retries never double-charge#
Every usage event carries an idempotencyKey. The same key twice means billed once.
await recordUsage({
idempotencyKey: req.headers['idempotency-key'],
endpoint: '/tools/search',
status: 'completed',
})
// same idempotencyKey again → 200 OK, not billed twiceThe guarantee lives in a UNIQUE constraint at the database level, enforced by catching the P2002 violation. It is not a SELECT before INSERT, which would leave a race window open under concurrency.
Partial failures are not billed by default#
A call that dies mid-way is recorded with status: "partial" and kept out of Stripe unless you say otherwise.
await recordUsage({
idempotencyKey,
endpoint: '/tools/search',
status: 'partial', // client disconnected mid-call
})
// logged for audit, excluded from billing by defaultStreaming bills once, at the end#
One usage event per completed stream, not one per token. Accumulate units across chunks and send a single event when the stream finishes.
stream.on('end', () =>
recordUsage({ idempotencyKey, endpoint: '/tools/search', status: 'completed' })
)
// interrupted mid-stream → status: 'partial', same rule as aboveWhere these came from#
These were not designed upfront. They emerged from a real implementation problem: deciding what to do when Stripe confirmation arrives after the tool has already run. The write-up on Dev.to covers the full reasoning, including the exchange with an engineering lead at AppSignal who validated the approach.
Related: how billing works, known trade-offs.