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.

Signing APIs let you build a transaction in your application and have Circle sign it. You then broadcast the signed transaction using your own node provider. Use this flow when Circle doesn’t provide full blockchain infrastructure for your blockchain, or when you prefer to manage broadcasting yourself. For an overview, see How Signing APIs Work.

Prerequisites

Before you begin, make sure you have:
Only EOA wallets are supported for this signing flow.

Step 1. Set up your project

1.1. Create the project and install dependencies

# Create the project directory and initialize Node.js
mkdir sign-transactions
cd sign-transactions
npm init -y

# Set up module type and a script for EVM signing
npm pkg set type=module
npm pkg set scripts.sign-evm="tsx --env-file=.env sign-evm.ts"

# Install runtime dependencies
npm install @circle-fin/developer-controlled-wallets viem

# Install dev dependencies
npm install --save-dev tsx typescript @types/node

1.2. Configure TypeScript (optional)

This step is optional. It helps prevent missing types in your IDE or editor.
Create a tsconfig.json file:
npx tsc --init
Then, update the tsconfig.json file:
cat <<'EOF' > tsconfig.json
{
  "compilerOptions": {
    "target": "ESNext",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,
    "types": ["node"]
  }
}
EOF

1.3. Set environment variables

Create a .env file in the project directory:
.env
CIRCLE_API_KEY=YOUR_API_KEY
CIRCLE_ENTITY_SECRET=YOUR_ENTITY_SECRET
  • CIRCLE_API_KEY is your Circle Developer API key.
  • CIRCLE_ENTITY_SECRET is your registered entity secret.
The npm run command in this tutorial loads variables from .env using Node.js native env-file support.

Step 2. Create a signing wallet

const response = await client.createWallets({
  accountType: "EOA",
  blockchains: ["EVM-TESTNET"],
  count: 1,
  walletSetId: "YOUR_WALLET_SET_ID",
});
Use count to create up to 200 wallets per request.
If you already created a native wallet on Ethereum, Polygon, Avalanche, Arbitrum, or another EVM-compatible chain, a generic EVM wallet under the same wallet set maps to the same address. Do not use the generic EVM wallet in place of the native wallet on those chains, or transactions may become stuck.

Step 3. Build and sign a transaction

sign-evm.ts
import { initiateDeveloperControlledWalletsClient } from "@circle-fin/developer-controlled-wallets";
import { arcTestnet } from "viem/chains";

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

async function main() {
  // Set signing inputs
  const walletId = "YOUR_WALLET_ID";
  const walletAddress = "YOUR_WALLET_ADDRESS";

  // Build an EVM transaction object for a signing test
  const txObject = {
    chainId: arcTestnet.id,
    nonce: "0",
    to: walletAddress,
    value: "0",
    gas: "21000",
    maxFeePerGas: "41500000000",
    maxPriorityFeePerGas: "1500000000",
  };

  // Sign the transaction
  const response = await client.signTransaction({
    walletId,
    transaction: JSON.stringify(txObject),
  });

  console.log(response.data);
}

main().catch((err) => {
  console.error("Error:", err.message || err);
  process.exit(1);
});
The transaction object must match the Ethereum JSON-RPC transaction shape. Use your own tooling to prepare it before calling signTransaction(). Include the correct chainId for your network. For supported EVM-TESTNET chains, see Chain IDs for Signing Transactions. When building EIP-1559 transactions, include both maxFeePerGas and maxPriorityFeePerGas.

Step 4. Review the response

The signing response includes:
  • signature
  • signedTransaction
  • txHash
You can use signedTransaction with your own broadcast flow or chain tooling.