| Event | Description |
|---|---|
wallets.transfer.in | Tokens transferred into a project wallet |
wallets.transfer.out | Tokens transferred out of a project wallet |
wallets.signer.exported | A wallet’s private key was exported for the first time |
Transfer Webhooks
Transfer webhooks notify you when tokens are transferred in or out of wallets in your project.Supported Configurations
Transfer webhooks have different levels of support depending on the blockchain and wallet type:| Chain | Wallet Types | Token Types |
|---|---|---|
| EVM (Ethereum, Polygon, Base, etc.) | Smart wallets and EOAs | ERC-20 tokens only (native tokens like ETH, MATIC not supported) |
| Solana | Smart wallets and EOAs | All SPL tokens including native SOL |
| Stellar | Smart wallets and EOAs | Soroban tokens (fungible) |
Event Types
Crossmint provides two webhook event types for wallet transfers:wallets.transfer.in
Triggered when tokens are transferred into a wallet in your project. This event is only sent for successful transfers that have been confirmed onchain.
wallets.transfer.out
Triggered when tokens are transferred out of a wallet in your project. This event is sent for both successful and failed transfer attempts, allowing you to track the complete lifecycle of outgoing transactions.
Setup
To start receiving wallet transfer webhooks, configure a webhook endpoint in the Crossmint Console.Prerequisites
- A Crossmint project with API keys configured
- A wallet with tokens to transfer (see Fund a Staging Wallet)
- The
svixpackage installed for webhook signature verification:
- Option 1: Test using Svix Play - Quick testing without setting up a local server
- Option 2: Integrate with your local app - Full integration with your development environment
Option 1: Test using Svix Play
Use Svix Play to inspect webhook payloads without setting up a local server. This is useful for understanding the event structure before building your integration.- Navigate to the Webhooks page in the Crossmint Console
- Click Add Endpoint
- In the dialog that appears, click the “with Svix Play” button (instead of entering a custom URL)
- Select the following event types:
wallets.transfer.in- Receive notifications when tokens arrive in your walletswallets.transfer.out- Receive notifications when tokens leave your wallets
- Click Create
wallet.send(), and the event will appear in Svix Play:
Option 2: Local development with ngrok
For full integration, set up a local server to receive and process webhook events. Before registering a webhook endpoint, you need a publicly accessible URL. If your app runs locally onhttp://localhost:3000, use ngrok to create a public URL:
https://abc123.ngrok.io that forwards to your local server.
Alternatively, if you have a staging or development server with a public URL, you can register that directly.
Register your endpoint
- Navigate to the Webhooks page in the Crossmint Console
- Click Add Endpoint
- Enter your public URL with the webhook path (e.g.,
https://abc123.ngrok.io/api/webhooks/transfers) - Select the following event types:
wallets.transfer.in- Receive notifications when tokens arrive in your walletswallets.transfer.out- Receive notifications when tokens leave your wallets
- Click Create
- Copy the signing secret from the endpoint details - you will need this to verify webhook signatures
Handle and verify events
Create an endpoint to receive and process webhook events. The following example shows how to handle both incoming and outgoing transfer events.- Node.js (Express)
- Next.js (App Router)
- Python (Flask)
For more details on securing and verifying webhook requests, see Verify Webhooks.
Test your endpoint
Execute a transfer using the Transfer Tokens guide and observe the webhook event in your server logs. For a successful outgoing transfer, you should see output like:Event Schema
Bothwallets.transfer.in and wallets.transfer.out events share a common structure with some key differences based on the transfer direction and outcome.
Common Fields
All wallet transfer events include the following fields:| Field | Type | Description |
|---|---|---|
id | string | Unique identifier for the webhook event |
type | string | Event type: "wallets.transfer.in" or "wallets.transfer.out" |
data.sender | object | Information about the sender wallet |
data.sender.address | string | Blockchain address of the sender |
data.sender.chain | string | Chain identifier (e.g., "ethereum", "polygon", "solana", "stellar") |
data.sender.locator | string | Wallet locator in the format chain:address |
data.sender.owner | string (optional) | Owner identifier if the sender is a Crossmint-managed wallet |
data.recipient | object | Information about the recipient wallet |
data.recipient.address | string | Blockchain address of the recipient |
data.recipient.chain | string | Chain identifier |
data.recipient.locator | string | Wallet locator in the format chain:address |
data.recipient.owner | string (optional) | Owner identifier for the recipient wallet |
data.token | object | Information about the transferred token |
data.token.type | string | Token type, currently only "fungible" is supported |
data.token.chain | string | Chain where the token exists |
data.token.locator | string | Token locator in the format chain:contractAddress |
data.token.amount | string | Human-readable amount (adjusted for decimals) |
data.token.rawAmount | string | Raw amount in smallest unit (e.g., wei for ETH) |
data.token.contractAddress | string (EVM) | Token contract address for EVM chains |
data.token.mintHash | string (Solana) | Token mint address for Solana |
data.token.contractId | string (Stellar) | Token contract ID for Stellar |
data.token.decimals | number | Number of decimals for the token |
data.token.symbol | string (optional) | Token symbol (e.g., "USDC", "ETH") |
data.status | string | Transfer status: "succeeded" or "failed" |
data.transferId | string (optional) | Unique identifier for the transfer, can be used with the Get Transaction API |
data.completedAt | string | ISO 8601 timestamp when the transfer was completed. Timestamp may be off by a few seconds from the actual onchain transaction |
Type-Specific Differences
Incoming Transfers (wallets.transfer.in):
data.statusis always"succeeded"(only successful transfers are reported)data.onChainis always present with transaction details
wallets.transfer.out):
data.statuscan be"succeeded"or"failed"data.onChainis present only whenstatusis"succeeded"data.erroris present only whenstatusis"failed"
The
transferId field is only available for transfers initiated through the Crossmint API. It can be used to retrieve the transfer details from the Get Transaction API.Event Examples
Incoming Transfer Example
Incoming Transfer Example
Incoming Transfer (Stellar) Example
Incoming Transfer (Stellar) Example
Outgoing Transfer (Success) Example
Outgoing Transfer (Success) Example
Outgoing Transfer (Failed) Example
Outgoing Transfer (Failed) Example
Error Fields (Outgoing Transfers Only)
When an outgoing transfer fails, the following error fields are included:| Field | Type | Description |
|---|---|---|
data.error.message | string | Error message |
data.error.reason | string | Error reason (e.g., "execution_reverted", "program_error", "build_failed") |
data.error.revert | object | Revert details from smart contract |
data.error.revert.type | string | Revert type: "contract_call", "wallet_authorization", or "wallet_deployment" |
data.error.revert.reason | string | Revert reason message |
data.error.logs | any (optional) | Additional error logs |
Best Practices
For comprehensive guidance on implementing reliable webhook handlers, see Webhook Best Practices.Signer Export Webhook
Thewallets.signer.exported event is triggered when a user exports the private key of a wallet for the first time. This webhook is sent once per wallet — subsequent exports of the same wallet do not trigger additional events.
This is useful for compliance monitoring, alerting, or updating internal records when a user gains direct access to the underlying key material.
The webhook payload does not contain any private key material. It only identifies which wallet and signer were involved in the export.
Event Schema
| Field | Type | Description |
|---|---|---|
id | string | Unique identifier for the webhook event |
type | string | "wallets.signer.exported" |
data.owner | string | Signer locator of the wallet owner (e.g., "email:user@example.com") |
data.walletAddress | string | Blockchain address of the exported wallet |
data.chain | string | Chain type: "evm", "solana", or "stellar" |
data.signerType | string | Signer type that was exported: "email" or "phone" |
Event Example
Signer Export Example
Signer Export Example
Setup
To start receiving signer export webhooks, add a webhook endpoint in the Crossmint Console and select thewallets.signer.exported event type. For detailed setup instructions, see Add an Endpoint.
- Respond quickly: Return a 2xx status within 15 seconds to prevent retries
- Verify signatures: Always verify webhook signatures before processing
Related Resources
- Add an Endpoint - Configure webhook endpoints
- Verify Webhooks - Verify webhook signatures
- Best Practices - Webhook implementation best practices
- Create Wallet - Create wallets to receive transfers
- Transfer Tokens - Initiate token transfers
- Export Private Key - Allow users to export private keys

