Skip to main content

Documentation Index

Fetch the complete documentation index at: https://developers.circle.com/llms.txt

Use this file to discover all available pages before exploring further.

Create a pool of developer-controlled wallets before users arrive so wallets are ready to assign instantly. When a new user signs up, assign an available wallet by updating its name and refId fields. This approach reduces sign-up latency because wallet creation happens ahead of time rather than during registration.
Cost consideration for Externally Owned Account (EOA) walletsCreating EOA wallets on mainnet incurs a minor expense per wallet. To optimize costs, forecast user demand and batch-create wallets accordingly. For example, prepare enough wallets to cover the expected demand for the next 30 days to avoid unnecessary expenses.

Prerequisites

Before you begin, ensure that you’ve:

Step 1. Create a pool of unassigned wallets

Call the create wallets endpoint with a count value but without metadata. Omitting metadata creates wallets that have no name or refId, leaving them available for assignment later.
You can create up to 200 wallets per request. If you need more, make additional requests until you reach the required total.
import { initiateDeveloperControlledWalletsClient } from "@circle-fin/developer-controlled-wallets";

const client = initiateDeveloperControlledWalletsClient({
  apiKey: process.env.CIRCLE_API_KEY!,
  entitySecret: process.env.CIRCLE_ENTITY_SECRET!,
});

const response = await client.createWallets({
  walletSetId: "your-wallet-set-id",
  blockchains: ["ARC-TESTNET"],
  count: 50,
  accountType: "SCA",
});

console.log(response.data?.wallets);
The response contains the newly created wallets. The name and refId fields are omitted because no metadata was provided:
Response
{
  "data": {
    "wallets": [
      {
        "id": "66b67097-307e-5b46-a1d5-0b1577d67fd4",
        "state": "LIVE",
        "walletSetId": "018b42d2-cc38-7a1e-a47a-5927d2c97f16",
        "custodyType": "DEVELOPER",
        "address": "0xe55628c98f5d81daaa79b72899b38a3535d10990",
        "blockchain": "ARC-TESTNET",
        "accountType": "SCA",
        "updateDate": "2024-01-22T22:57:20Z",
        "createDate": "2024-01-22T22:57:20Z"
      },
      {
        "id": "cda61d8d-7d46-5a39-a8a6-6b4a3d6fdac3",
        "state": "LIVE",
        "walletSetId": "018b42d2-cc38-7a1e-a47a-5927d2c97f16",
        "custodyType": "DEVELOPER",
        "address": "0x29b27e792b8b854e48e85ab4f456cf5a9f1579fb",
        "blockchain": "ARC-TESTNET",
        "accountType": "SCA",
        "updateDate": "2024-01-22T22:57:20Z",
        "createDate": "2024-01-22T22:57:20Z"
      }
    ]
  }
}

Step 2. Store wallet IDs

Persist the returned wallet IDs in your system and mark each one as unassigned. The storage mechanism is application-specific—you might use a database table, a key-value store, or any other persistence layer your application already uses. Track each wallet’s assignment status so that when a new user signs up, your application can quickly select an unassigned wallet and avoid double-assigning the same wallet to multiple users. A simple boolean flag or status column (for example, assigned: false) works for most implementations.

Step 3. Assign a wallet to a new user

When a user registers, select an unassigned wallet from the pool and call the update wallet endpoint to set its name and refId. The refId field is designed for linking wallets to entities in your own system, such as a user ID. This endpoint does not require entitySecretCiphertext, so no entity secret encryption is needed for this call.
const walletId: string = "66b67097-307e-5b46-a1d5-0b1577d67fd4";
const userId: string = "d4f2c8a1-9b3e-4f7d-a6e5-1c8b9d0e3f2a";

const updated = await client.updateWallet({
  id: walletId,
  name: "User Wallet",
  refId: userId,
});

console.log(updated.data?.wallet);
The response confirms the wallet now has the assigned name and refId:
Response
{
  "data": {
    "wallet": {
      "id": "66b67097-307e-5b46-a1d5-0b1577d67fd4",
      "state": "LIVE",
      "walletSetId": "018b42d2-cc38-7a1e-a47a-5927d2c97f16",
      "custodyType": "DEVELOPER",
      "refId": "d4f2c8a1-9b3e-4f7d-a6e5-1c8b9d0e3f2a",
      "name": "User Wallet",
      "address": "0xe55628c98f5d81daaa79b72899b38a3535d10990",
      "blockchain": "ARC-TESTNET",
      "accountType": "SCA",
      "updateDate": "2024-01-22T23:15:42Z",
      "createDate": "2024-01-22T22:57:20Z"
    }
  }
}
After the update succeeds, mark the wallet as assigned in your own system so it is no longer available in the unassigned pool.

Step 4. Verify the assignment

Call the list wallets endpoint filtered by refId to confirm the wallet is correctly assigned to the user.
const userId: string = "d4f2c8a1-9b3e-4f7d-a6e5-1c8b9d0e3f2a";

const wallets = await client.listWallets({
  refId: userId,
});

console.log(wallets.data?.wallets);
The response returns only wallets matching the specified refId:
Response
{
  "data": {
    "wallets": [
      {
        "id": "66b67097-307e-5b46-a1d5-0b1577d67fd4",
        "state": "LIVE",
        "walletSetId": "018b42d2-cc38-7a1e-a47a-5927d2c97f16",
        "custodyType": "DEVELOPER",
        "refId": "d4f2c8a1-9b3e-4f7d-a6e5-1c8b9d0e3f2a",
        "name": "User Wallet",
        "address": "0xe55628c98f5d81daaa79b72899b38a3535d10990",
        "blockchain": "ARC-TESTNET",
        "accountType": "SCA",
        "updateDate": "2024-01-22T23:15:42Z",
        "createDate": "2024-01-22T22:57:20Z"
      }
    ]
  }
}