Skip to main content
In a nutshell
The Blockradar Signing API lets you cryptographically sign plain text messages and structured data (typed data) using your wallet’s private keys. Signatures prove wallet ownership to third-party services without moving funds or paying network fees (gas).

Prerequisites

Before using the Signing API, ensure you have:
1

API Key

Get your API key from the Blockradar Dashboard. Navigate to Developers to generate one.
2

Wallet Created

Create a master wallet from the Blockradar Dashboard. Navigate to Wallets and create one for your target blockchain. You’ll need the walletId for signing operations.
3

Environment

Choose between Testnet (for development) or Mainnet (for production). Wallets are isolated per environment.

How It Works

The Signing API produces a cryptographic signature that proves you control a specific wallet address. The signed output can be verified by any third party without accessing your private keys.

Message Signing

Sign plain text messages to prove wallet ownership. Works on all supported blockchains: EVM, Tron, and Solana.

Typed Data Signing

Sign structured data following the EIP-712 standard. Used for gasless approvals (EIP-2612 Permit) and authorized transfers (EIP-3009). EVM-only.

Common use cases

  • Third-party provider registration — Prove you own an address when onboarding with services like Iron, Circle, or other DeFi protocols
  • Gasless token approvals — Sign EIP-2612 Permit messages to authorize token spending without an on-chain transaction
  • Authorized transfers — Sign EIP-3009 TransferWithAuthorization messages for delegated transfers
  • Off-chain attestations — Create verifiable proofs of intent or agreement tied to a wallet address

Master Wallet vs Child Address

The Signing API is available at two levels:

Master Wallet

Sign using the master wallet’s keys. Ideal for treasury-level operations and provider integrations.

Child Address

Sign using a specific child address’s keys. Use when the third party requires a signature from a deposit address.

Endpoints

OperationMaster WalletChild Address
Sign MessagePOST /v1/wallets/{walletId}/signing/messagePOST /v1/wallets/{walletId}/addresses/{addressId}/signing/message
Sign Typed DataPOST /v1/wallets/{walletId}/signing/typed-dataPOST /v1/wallets/{walletId}/addresses/{addressId}/signing/typed-data

Message Signing

Sign a plain text message with your wallet’s private key. The API signs the message, verifies the signature matches the wallet address, and returns both the signature and a transaction record.

Supported Blockchains

BlockchainSigning StandardSignature Format
EVM (Ethereum, Polygon, BSC, Base, Arbitrum, Optimism, Celo)EIP-191 (personal_sign)Hex-encoded with r, s, v components
TronTronWeb signMessageV2Hex-encoded string
SolanaEd25519Base58-encoded string

Request Parameters

ParameterTypeRequiredDescription
messagestringYesThe plain text message to sign. Maximum 4,096 characters.
referencestringNoYour internal tracking ID. Use for idempotency — duplicate references are rejected.
metadataobjectNoCustom key-value pairs stored with the transaction record.

Message Signing Example

curl --request POST \
  --url https://api.blockradar.co/v1/wallets/{walletId}/signing/message \
  --header 'Content-Type: application/json' \
  --header 'x-api-key: <api-key>' \
  --data '{
    "message": "Please sign this message to verify your wallet ownership for Iron provider registration.",
    "reference": "iron-verification-001",
    "metadata": {
      "provider": "iron",
      "purpose": "wallet-verification"
    }
  }'

EVM Response

{
  "message": "Message signed successfully",
  "statusCode": 200,
  "data": {
    "id": "770f9100-7338-4823-b1ce-3658fc67db09",
    "hash": "0xdb095e6cbf235d630cee43e0953e60c351e46897bc4e65abfce3e975810e21335aa3918399dac1e01badb2dc8c59c171e65d0c328c92737de702da9d76b889b31b",
    "status": "SUCCESS",
    "type": "SIGNED",
    "senderAddress": "0x947514e4B803e312C312da0F1B41fEDdbe15ae7a",
    "recipientAddress": "0x947514e4B803e312C312da0F1B41fEDdbe15ae7a",
    "signedTransaction": {
      "r": "0xdb095e6cbf235d630cee43e0953e60c351e46897bc4e65abfce3e975810e2133",
      "s": "0x5aa3918399dac1e01badb2dc8c59c171e65d0c328c92737de702da9d76b889b3",
      "v": 27,
      "signature": "0xdb095e6cbf...b31b"
    },
    "reference": "iron-verification-001",
    "metadata": {
      "provider": "iron",
      "purpose": "wallet-verification"
    },
    "confirmed": true,
    "createdAt": "2025-03-02T19:00:52.000Z"
  }
}

Tron / Solana Response

For Tron and Solana, the signedTransaction object contains only the signature field (no r, s, v components):
{
  "message": "Message signed successfully",
  "statusCode": 200,
  "data": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "hash": "3xYkZ9...",
    "status": "SUCCESS",
    "type": "SIGNED",
    "senderAddress": "TJRabPrwbZy45sbavfcjinPJC18kjpRT9Y",
    "recipientAddress": "TJRabPrwbZy45sbavfcjinPJC18kjpRT9Y",
    "signedTransaction": {
      "signature": "3xYkZ9..."
    },
    "reference": "tron-verification-001",
    "confirmed": true,
    "createdAt": "2025-03-02T19:00:52.000Z"
  }
}

Response Fields

FieldDescription
idUnique transaction ID for the signing record
hashThe cryptographic signature. For EVM: hex string. For Tron: hex string. For Solana: base58 string.
statusAlways SUCCESS for completed signatures
typeAlways SIGNED for signing transactions
senderAddressThe wallet address that produced the signature
signedTransactionSignature components. EVM includes r, s, v, and full signature. Tron and Solana include signature only.
referenceYour provided reference string (if any)
metadataYour provided metadata object (if any)

Typed Data Signing (EVM Only)

Sign structured data following the EIP-712 standard. This is used for gasless approvals, delegated transfers, and other on-chain authorization flows that require a structured signature.
Typed data signing is only available for EVM-compatible blockchains (Ethereum, Polygon, BSC, Base, Arbitrum, Optimism, Celo). Tron and Solana do not support EIP-712.

Supported Standards

StandardUse Case
EIP-712Generic structured data signing
EIP-2612 (Permit)Gasless token approvals — approve spending without an on-chain transaction
EIP-3009 (TransferWithAuthorization)Delegated transfers — authorize a transfer that a third party submits

Request Parameters

ParameterTypeRequiredDescription
domainobjectYesEIP-712 domain separator. Includes name, version, chainId, and verifyingContract.
typesobjectYesType definitions for the structured data.
messageobjectYesThe data to sign, conforming to the type definitions.

EIP-2612 Permit Example

curl --request POST \
  --url https://api.blockradar.co/v1/wallets/{walletId}/signing/typed-data \
  --header 'Content-Type: application/json' \
  --header 'x-api-key: <api-key>' \
  --data '{
    "domain": {
      "name": "USD Coin",
      "version": "2",
      "chainId": 11155111,
      "verifyingContract": "0xa0b86a33e6441b8c4c8c0c077bcdd28571685701"
    },
    "types": {
      "Permit": [
        { "name": "owner", "type": "address" },
        { "name": "spender", "type": "address" },
        { "name": "value", "type": "uint256" },
        { "name": "nonce", "type": "uint256" },
        { "name": "deadline", "type": "uint256" }
      ]
    },
    "message": {
      "owner": "0x742d35cc6634c0532925a3b8d4c9db96c4b4d8b6",
      "spender": "0x8ba1f109551bd432803012645aac136c4c8c8c0c",
      "value": "1000000000",
      "nonce": "0",
      "deadline": "1641081600"
    }
  }'

Typed Data Response

{
  "message": "Typed data signed successfully",
  "statusCode": 200,
  "data": {
    "id": "770f9100-7338-4823-b1ce-3658fc67db09",
    "hash": "0xdb095e6cbf235d630cee43e0953e60c351e46897bc4e65abfce3e975810e21335aa3918399dac1e01badb2dc8c59c171e65d0c328c92737de702da9d76b889b31b",
    "status": "SUCCESS",
    "type": "SIGNED",
    "senderAddress": "0x947514e4B803e312C312da0F1B41fEDdbe15ae7a",
    "recipientAddress": "0x947514e4B803e312C312da0F1B41fEDdbe15ae7a",
    "signedTransaction": {
      "r": "0xdb095e6cbf235d630cee43e0953e60c351e46897bc4e65abfce3e975810e2133",
      "s": "0x5aa3918399dac1e01badb2dc8c59c171e65d0c328c92737de702da9d76b889b3",
      "v": 27,
      "signature": "0xdb095e6cbf...b31b"
    },
    "confirmed": true,
    "createdAt": "2025-03-02T19:00:52.000Z"
  }
}

Domain Object Fields

FieldTypeRequiredDescription
namestringYesThe name of the signing domain (e.g., the token name or dApp name)
versionstringYesThe version of the domain
chainIdnumberYesThe chain ID. Must match the wallet’s blockchain network.
verifyingContractstringYesThe contract address that will verify the signature
saltstringNoOptional domain salt for EIP-712 v4
Chain ID validation
The chainId in your domain object must match the chain ID of the wallet’s blockchain network. If they don’t match, the API returns a 400 Chain ID mismatch error.

Child Address Signing

Sign messages or typed data using a specific child address instead of the master wallet:
curl --request POST \
  --url https://api.blockradar.co/v1/wallets/{walletId}/addresses/{addressId}/signing/message \
  --header 'Content-Type: application/json' \
  --header 'x-api-key: <api-key>' \
  --data '{
    "message": "Verify ownership of deposit address for provider onboarding.",
    "reference": "address-verify-001"
  }'
Child address signing follows the same request and response format as master wallet signing. The only difference is the endpoint URL, which includes the addressId.

Webhook Events

Signing operations trigger a webhook with the transaction record:
EventDescription
signed.successMessage or typed data signed and verified

Webhook Payload

{
  "event": "signed.success",
  "data": {
    "id": "770f9100-7338-4823-b1ce-3658fc67db09",
    "hash": "0xdb095e6cbf...b31b",
    "status": "SUCCESS",
    "type": "SIGNED",
    "senderAddress": "0x947514e4B803e312C312da0F1B41fEDdbe15ae7a",
    "recipientAddress": "0x947514e4B803e312C312da0F1B41fEDdbe15ae7a",
    "signedTransaction": {
      "r": "0xdb095e6cbf...2133",
      "s": "0x5aa3918399...89b3",
      "v": 27,
      "signature": "0xdb095e6cbf...b31b"
    },
    "reference": "iron-verification-001",
    "metadata": {
      "provider": "iron",
      "purpose": "wallet-verification"
    },
    "wallet": {
      "id": "d236a191-c1d4-423c-a439-54ce6542ca41",
      "name": "Ethereum Master Wallet"
    },
    "blockchain": {
      "name": "ethereum",
      "network": "testnet"
    },
    "confirmed": true,
    "createdAt": "2025-03-02T19:00:52.000Z"
  }
}

Complete Flow Example

Here’s a full implementation for signing a message and submitting the signature to a third-party provider:
async function signAndVerifyWithProvider(walletId, providerMessage) {
  const apiKey = process.env.BLOCKRADAR_API_KEY;
  const baseUrl = 'https://api.blockradar.co/v1';

  // Step 1: Sign the message
  const signResponse = await fetch(
    `${baseUrl}/wallets/${walletId}/signing/message`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-api-key': apiKey
      },
      body: JSON.stringify({
        message: providerMessage,
        reference: `provider-verify-${Date.now()}`
      })
    }
  ).then(r => r.json());

  if (signResponse.statusCode !== 200) {
    throw new Error(`Signing failed: ${signResponse.message}`);
  }

  const { hash, senderAddress } = signResponse.data;

  // Step 2: Submit the signature to the third-party provider
  // The provider can verify the signature matches the wallet address
  // without accessing your private keys
  return {
    address: senderAddress,
    signature: hash,
    message: providerMessage
  };
}

// Usage
signAndVerifyWithProvider(
  'wallet-uuid',
  'I authorize Iron to manage assets on my behalf.'
);

Error Responses

{
  "message": "Wallet not found",
  "statusCode": 404
}
The walletId does not exist or does not belong to your business.
{
  "message": "Address not found",
  "statusCode": 404
}
The addressId does not exist or is not associated with the specified wallet.
{
  "message": "Typed data signing is only supported for EVM blockchains",
  "statusCode": 400
}
Typed data signing (EIP-712) is only available on EVM-compatible chains. Use message signing for Tron and Solana.
{
  "message": "Chain ID mismatch",
  "statusCode": 400
}
The chainId in your typed data domain object does not match the wallet’s blockchain network.
{
  "message": "Signature verification failed",
  "statusCode": 400
}
Internal round-trip verification failed. This indicates a system error — contact support.

Best Practices

Security

  • Use references — Track signing operations with unique reference IDs for audit trails and idempotency
  • Verify the message — Before signing, confirm the message content matches what the third-party service expects
  • Limit message length — Messages are capped at 4,096 characters. Keep messages concise and specific

Integration

  • No gas fees — Signing operations are off-chain and do not require native token balance
  • Immediate response — Signatures are generated synchronously. No polling or webhook waiting required for the signature itself
  • Listen for webhooks — Use webhooks to maintain an audit trail of all signing events

Typed Data

  • Match chain IDs — The chainId in your domain must match the wallet’s network. Use sandbox (testnet) chain IDs for testing and production (mainnet) chain IDs for live operations
  • Check the contract — The verifyingContract must be the contract that will verify the signature on-chain

API Reference

Master Wallet Endpoints

EndpointDescription
Sign MessageSign a plain text message
Sign Typed DataSign EIP-712 structured data

Child Address Endpoints

EndpointDescription
Sign MessageSign a plain text message from a child address
Sign Typed DataSign EIP-712 structured data from a child address