Content

Circle API transfers and the idempotency key you must reuse

Circle puts idempotencyKey, a UUID v4, in the transfer body. Reuse that key on a retry. A new key starts a second transfer. Code 1083 means the body changed.

EngineeringOct 30, 2026

Key takeaways

  • -In this article we explore the Circle API for stablecoin transfers and the idempotency key in the JSON body.
  • -idempotencyKey is a UUID v4. The same key returns the first transfer. A new key can create a second transfer.
  • -HTTP 409 code 1083 means that key is already bound to a different request body.
  • -An internal transfer that returns status complete has finished. A second create with a new key moves funds again.

The transfer call to Circle times out. The agent catches the error, generates a fresh UUID, and posts again. Both calls were valid. Both used a different idempotencyKey. Circle accepted both. An internal transfer can come back complete immediately. A transfer out to a blockchain address is not something you claw back by calling the endpoint a third time. The safety net was the first UUID, and the retry threw it away.

This post is how Circle binds that key, what HTTP 409 and code 1083 mean, and how an agent should retry without creating a second movement of funds.

The key is a field in the JSON, and it is required

Circle's idempotent requests guide says that for endpoints which require a key, you send a UUID version 4. The same key returns the original response instead of running the operation again. Create an account transfer puts that value in the body as idempotencyKey, next to destination and amount. It is not an optional header you add if you remember. The field description says the key is there so the mutating request runs once.

A minimal shape, with placeholders rather than real ids:

{
  "idempotencyKey": "<uuid v4 generated once>",
  "destination": { "type": "verified_blockchain", "addressId": "<address id>" },
  "amount": { "amount": "3.14", "currency": "USD" }
}

Generate the UUID before the first attempt. Persist it with the destination and the amount. If the socket dies, send that JSON again, byte for byte on the fields Circle binds to the key.

Circle's catalog page is separate from CircleCI. swy search circle can print both names. Get the Circle provider, not the CI one, then copy a method id from swy list methods. Do not invent circle.transfer.create.

swy search circle
swy list methods

There is no .env file in this project. Swytchcode keeps credentials in its own local store and reads them when a call runs. The bearer token stays in that store.

A new UUID is a new transfer

Circle's rule rewards the same key and punishes a careless new one. Same key, same request: you get the first record. Same key, different body: error code 1083, HTTP 409. Circle's wording is that the key is bound to another request. Fetch that record, or mint a new key only when you truly want a new transfer.

1083 is the alarm you want. It means the agent changed the amount or the destination and reused the key. Do not "fix" it by generating a new key and hoping. Look up the original transfer. If the amount was wrong, that is a new business decision, with a new key, after a person looks. If the amount was right and only the retry differed by a timestamp field, stop sending fields that are not part of the transfer.

Circle's error table also says a malformed request can be retried with the same idempotencyKey after you fix validation. A risk denial is different: review the parties, then resubmit with a new key. A timeout or a 5xx is a retry with the same key. Those three cases are the runbook. An agent that uses one strategy for all three will either double-send or get stuck on 1083.

Crypto and digital-asset data APIs cover reading prices and chains. A transfer is not a read. Policy as code should cap the amount and deny a destination type you have not reviewed. The policy does not generate the UUID. Your caller does, once.

Complete on an internal move, final on a chain

Circle's internal-transfer how-to shows an account-to-account move that returns status complete in the response. They describe that path as instant, with no blockchain fee. If you saw complete, the money has moved between those accounts. A second key moves it again.

A destination of type verified_blockchain is a transfer toward an address you already verified. You do not get a card-network refund call for that. The idempotency key is how you avoid a duplicate. It is not how you reverse one that succeeded. Insufficient funds (1093 on the core codes, or a payout insufficient-balance signal) is a reason to top up and retry with the same key, not a reason to change the key and fire a smaller surprise amount.

Sandbox calls in Circle's examples use api-sandbox.circle.com. Production uses the live host. A sandbox complete does not debit a production wallet. Keep the host and the key in the same log line so a retry cannot drift from sandbox to live with a new UUID.

A retry of this POST is safe only when the same idempotencyKey is in the body. If each attempt mints a new key, Circle can accept a second transfer. Store the key and pass that same value if you send the call again.

Hold large transfers for a person. Approval on Slack or Telegram exists on Business and Enterprise, fails closed after 48 hours, and does not run if the approval arrives late. The approver should see the amount, the destination, and the idempotencyKey you will reuse if the call times out after they approve.

Generate the UUID once. Write it down. Send it on every retry of that same transfer. Treat 1083 as "this key already belongs to a different body" and go read that transfer before you send anything else.

FAQ

Where does Circle's idempotency key go?

In the JSON body, as idempotencyKey, on the transfer create that requires it. It is a UUID v4. Circle's guide says the same key returns the original response instead of running the operation again.

What is error 1083?

HTTP 409. The key is already bound to a different request. Fetch the original transfer. Mint a new key only when you intend a new transfer, not when you are retrying the same one.

If the status is complete, can I undo it with the same endpoint?

An internal account transfer that returns complete has finished. Calling create again with a new key starts another transfer. A blockchain destination is not reversed by a second create either. The key prevents the duplicate. It does not refund.

Will any new key on a timeout still be safe?

No. Circle has never seen that new key, so it can accept a second transfer. Reuse the UUID from the first attempt on timeouts and 5xx responses. Use a new UUID after a risk denial, which is the case Circle tells you to resubmit that way.

More content