Strimz
Concepts

Idempotency

How Strimz makes sure retries are safe at the API, the scheduler, and on-chain.

Idempotency means an operation can be run more than once but only takes effect once. Without it, a network blip during a refund could turn into a double refund.

Strimz enforces idempotency at three separate layers. Any retry logic you write on top of the SDK is safe to run as many times as needed.

At the API

Every POST endpoint that creates a resource accepts an Idempotency-Key header. If you send the same key twice within 24 hours, you get the original response. The row is not created twice.

const session = await strimz.paymentSessions.create(
  { amount: '50000000', currency: 'USDC', description: 'Pro plan, August' },
  { idempotencyKey: 'session-' + crypto.randomUUID() },
)

Generate the key once per logical operation, persist it in your DB alongside the request you're about to make, and re-send the same key on retry. The SDK does this for you on every retryable verb.

At the queue layer

When the API enqueues a job onto BullMQ (webhook delivery, subscription charge, agent action), the job ID is derived from the resource ID. It is not random. Two API replicas processing the same incoming request can't enqueue duplicate jobs.

The scheduler then processes each job exactly once. If the job fails partway through, BullMQ marks it failed and the worker can retry. The partial work it did is itself idempotent (see below).

On-chain

This is the layer where stablecoins genuinely pull their weight. The Strimz contracts use deterministic identifiers for every state-changing action:

  • PaymentSession.id is passed as bytes32 ref on the on-chain pay() call. The contract emits it in PaymentExecuted. The indexer keys the resulting Transaction row on (onchainTxHash, ref). Replays no-op.
  • chargeAttemptId is keccak256(subscriptionId, periodEndAt). The contract has a mapping(bytes32 => bool) usedAttempts. If you try to charge a sub for a period that's already been charged, the call reverts cheaply.
  • Refund tx hashes are recorded in Refund.refundTxHash after the merchant signs the transfer. The indexer matches incoming ERC-20 Transfer events by hash. Replays of the same hash flip nothing.

This differs from ACH or card processors where idempotency is a database guarantee. Here the chain itself enforces it, so even a maliciously-replayed signed transaction can't cause a duplicate charge.

When you don't need to think about it

If you're using @strimz/sdk, idempotency keys are added automatically:

  • A fresh crypto.randomUUID() per call by default.
  • 429 and 5xx responses are retried with exponential backoff, re-using the same key.

The only reason to set the key yourself is when your own business logic might fire the same operation more than once and you want them to collapse to one. For example: a customer clicks "Pay" twice, both clicks reach your server, both go on to create a session. Pass the same cartId as the idempotency key on both, and the second call returns the first call's session.

On this page