Skip to main content
An idempotency key lets the SDK recognize when two submissions represent the same user intent and collapse them into one onchain outcome. Use it whenever the same intent might reach the service more than once. Common cases:
  • A caught error you decide to retry across processes.
  • A user who double-clicks the submit button.
  • A queue worker that replays after a deploy.
  • A serverless function that times out and reruns.
  • A webhook consumer that fires the same job twice.
kit.borrow.borrow, kit.borrow.repay, kit.borrow.addCollateral, kit.borrow.withdrawCollateralRepayIfNeeded, and kit.borrow.closeLoan all accept an idempotencyKey on the call.

Prerequisites

Before you begin, ensure that you’ve: These are required so any example below runs with a valid kit and adapter.

Generate one key per user intent

Generate a UUID when the user first submits the intent, persist it alongside the request, and reuse the same key on every later submission of that intent:
TypeScript
The service binds the key to the request parameters and to the Circle-signed execution it produces. A same-key replay behaves differently depending on the execution’s state:
  • While the execution is unsettled and hasn’t expired (default TTL: 1 minute), the replay returns the same signed execution, which gets resubmitted onchain.
  • If the execution has already settled onchain, the service returns IDEMPOTENCY_KEY_ALREADY_EXECUTED. Read this as “the first attempt succeeded, don’t submit again.”
  • If the signed execution’s deadline has passed, the service returns SIGNED_BUNDLE_EXPIRED and the request needs a new key.
For delays longer than the signed execution’s TTL (queue workers replaying after a deploy, serverless functions rerunning much later), reuse the same key if the first attempt has already settled onchain, and mint a new key if it hasn’t. To resume a failed operation from the same process, use kit.borrow.retry instead.