Skip to main content
Track contract events and get event logs with the Circle Contracts API.

Prerequisites

To complete this tutorial, you need:
  1. Node.js v22+ installed
  2. Deployed contract on Arc - Complete the Deploy contracts tutorial first
  3. API credentials - Your API key and Entity Secret from the Developer Console
This tutorial assumes you have a contract already deployed on Arc Testnet with the Circle SDKs installed. If you don’t, complete the Deploy contracts tutorial first.

Step 1: Set up a webhook endpoint

Event monitors send real-time updates to your webhook endpoint when events happen.
  1. Visit webhook.site
  2. Copy your unique webhook URL (for example, https://webhook.site/your-uuid)

Step 2: Register your webhook in Console

Register your webhook URL in the Developer Console:
  1. Go to Developer Console
  2. Navigate to Webhooks (left sidebar)
  3. Click Add a webhook
  4. Enter your webhook URL (from Step 1) and create the webhook
Register your webhook before creating event monitors. This allows Circle to send notifications to your endpoint.

Step 3: Import an existing contract (optional)

If you already have a deployed contract and want to monitor its events, import it to the Developer Console. If you deployed a contract using Circle Contracts (for example, in the Deploy contracts tutorial), skip this step. Your contract is already available in the Console.
import { initiateSmartContractPlatformClient } from "@circle-fin/smart-contract-platform";
import { randomUUID } from "crypto";

const contractClient = initiateSmartContractPlatformClient({
  apiKey: process.env.CIRCLE_API_KEY,
  entitySecret: process.env.CIRCLE_ENTITY_SECRET,
});

async function importContract() {
  try {
    const response = await contractClient.importContract({
      blockchain: "ARC-TESTNET",
      address: process.env.CONTRACT_ADDRESS,
      name: "MyContract",
      idempotencyKey: randomUUID(),
    });

    return response;
  } catch (error) {
    console.error("Error importing contract:", error.message);
    throw error;
  }
}

importContract();
Run the script:
npx tsx --env-file=.env import-contract.ts
If the contract is already imported, you’ll see an error: contract already exists. This means the contract is already available in the Console and you can proceed to create an event monitor.

Step 4: Create an event monitor

Event monitors track specific contract events. They send updates to your webhook endpoint. This example monitors Transfer events:
import { initiateSmartContractPlatformClient } from "@circle-fin/smart-contract-platform";
import { randomUUID } from "crypto";

const contractClient = initiateSmartContractPlatformClient({
  apiKey: process.env.CIRCLE_API_KEY,
  entitySecret: process.env.CIRCLE_ENTITY_SECRET,
});

async function createEventMonitor() {
  try {
    const response = await contractClient.createEventMonitor({
      blockchain: "ARC-TESTNET",
      contractAddress: process.env.CONTRACT_ADDRESS,
      eventSignature: "Transfer(address,address,uint256)",
      webhookUrl: process.env.WEBHOOK_URL, // Your webhook endpoint
      idempotencyKey: randomUUID(),
    });

    return response;
  } catch (error) {
    console.error("Error creating event monitor:", error.message);
    throw error;
  }
}

createEventMonitor();
Run the script:
npx tsx --env-file=.env create-monitor.ts
Response:
{
  "data": {
    "eventMonitor": {
      "id": "019bc5df-9f7a-700d-949e-28bbee978e30",
      "eventSignature": "Transfer(address,address,uint256)",
      "contractAddress": "0x191c1fc66116ac6d857632e533143dab2ebf385e",
      "blockchain": "ARC-TESTNET",
      "webhookUrl": "https://webhook.site/your-uuid",
      "isEnabled": true
    }
  }
}
The idempotencyKey prevents duplicate event monitors. If you run the script again with the same key, you’ll get an error that the monitor already exists.

Step 5: Receive webhook notifications

When events occur, Circle sends updates to your endpoint. Here is what a Transfer event looks like:
{
  "subscriptionId": "f0332621-a117-4b7b-bdf0-5c61a4681826",
  "notificationId": "5c5eea9f-398f-426f-a4a5-1bdc28b36d2c",
  "notificationType": "contracts.eventLog",
  "notification": {
    "contractAddress": "0x4abcffb90897fe7ce86ed689d1178076544a021b",
    "blockchain": "ARC-TESTNET",
    "txHash": "0xe15d6dbb50178f60930b8a3e3e775f3c022505ea2e351b6c2c2985d2405c8ebc",
    "userOpHash": "0x78c3e8185ff9abfc7197a8432d9b79566123616c136001e609102c97e732e55e",
    "blockHash": "0x0ad6bf57a110d42620defbcb9af98d6223f060de588ed96ae495ddeaf3565c8d",
    "blockHeight": 22807198,
    "eventSignature": "Transfer(address,address,uint256)",
    "eventSignatureHash": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
    "topics": [
      "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
      "0x0000000000000000000000000000000000000000000000000000000000000000",
      "0x000000000000000000000000bcf83d3b112cbf43b19904e376dd8dee01fe2758"
    ],
    "data": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000",
    "firstConfirmDate": "2026-01-21T06:53:12Z"
  },
  "timestamp": "2026-01-21T06:53:13.194467201Z",
  "version": 2
}
Key fields:
  • notificationType: Always "contracts.eventLog" for event monitor webhooks
  • notification.eventSignature: The event that was emitted
  • notification.contractAddress: Address of the contract that emitted the event
  • notification.blockchain: The blockchain network (for example, ARC-TESTNET)
  • notification.txHash: Transaction hash where the event occurred
  • notification.userOpHash: User operation hash (for smart contract accounts)
  • notification.blockHash: Hash of the block containing the transaction
  • notification.blockHeight: Block number where the event occurred
  • notification.eventSignatureHash: Keccak256 hash of the event signature
  • notification.topics: Indexed event parameters (for example, from and to addresses)
  • notification.data: Non-indexed event parameters (for example, token amount)
  • notification.firstConfirmDate: Timestamp when the event was first confirmed
  • timestamp: Timestamp when the webhook was sent
  • version: Webhook payload version
You can verify webhook delivery status in the Developer Console under Contracts → Monitoring.

Step 6: Retrieve event logs

You can also query event logs with the API. This is useful for past events or if you prefer polling.
Webhooks vs Polling: Webhooks send real-time updates (push). Polling needs periodic API calls (pull). Use webhooks for production and polling for testing or past queries.
async function getEventLogs(): Promise<void> {
  try {
    const response = await contractClient.listEventLogs({
      contractAddress: process.env.CONTRACT_ADDRESS,
      blockchain: "ARC-TESTNET",
      pageSize: 10,
    });

    return response;
  } catch (error) {
    console.error("Error fetching event logs:", error.message);
    throw error;
  }
}

getEventLogs();
Replace CONTRACT_ADDRESS with your contract address. You can get this address when you deploy the contract, or by listing your contracts with listContracts().
Response:
{
  "data": {
    "eventLogs": [
      {
        "eventSignature": "Transfer(address,address,uint256)",
        "txHash": "0xb9e8774147fe086e5864828457f2bf3f8f25a356f6df4c920a677bfd3c3e9ac7",
        "blockHeight": "21955992",
        "data": "0x000000000000000000000000000000000000000000000000018a59e972118000",
        "topics": [
          "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
        ],
        "createDate": "2026-01-16T08:38:20Z"
      }
    ]
  }
}
You can view, update, and delete event monitors with the Circle Contracts API. See the API Reference for details on managing your monitors.

Summary

After completing this tutorial, you’ve successfully:
  • Set up webhook endpoints using webhook.site or ngrok
  • Registered webhooks in the Developer Console
  • Created event monitors for specific contract events
  • Received real-time webhook updates for contract events
  • Retrieved past event logs with the Circle SDK