> ## Documentation Index
> Fetch the complete documentation index at: https://docs.blockradar.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Signing

> Sign messages and typed data with your wallet keys for off-chain verification

<Note>
  In a nutshell<br />
  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).
</Note>

## Prerequisites

Before using the Signing API, ensure you have:

<Steps>
  <Step title="API Key">
    Get your API key from the [Blockradar Dashboard](https://dashboard.blockradar.co). Navigate to **Developers** to generate one.
  </Step>

  <Step title="Wallet Created">
    Create a master wallet from the [Blockradar Dashboard](https://dashboard.blockradar.co). Navigate to **Wallets** and create one for your target blockchain. You'll need the `walletId` for signing operations.
  </Step>

  <Step title="Environment">
    Choose between **Testnet** (for development) or **Mainnet** (for production). Wallets are isolated per environment.
  </Step>
</Steps>

## 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.

<CardGroup cols={2}>
  <Card title="Message Signing" icon="pen">
    Sign plain text messages to prove wallet ownership. Works on all supported blockchains: EVM, Tron, and Solana.
  </Card>

  <Card title="Typed Data Signing" icon="file-signature">
    Sign structured data following the EIP-712 standard. Used for gasless approvals (EIP-2612 Permit) and authorized transfers (EIP-3009). EVM-only.
  </Card>
</CardGroup>

### 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:

<CardGroup cols={2}>
  <Card title="Master Wallet" icon="wallet">
    Sign using the master wallet's keys. Ideal for treasury-level operations and provider integrations.
  </Card>

  <Card title="Child Address" icon="address-card">
    Sign using a specific child address's keys. Use when the third party requires a signature from a deposit address.
  </Card>
</CardGroup>

### Endpoints

| Operation       | Master Wallet                                    | Child Address                                                          |
| --------------- | ------------------------------------------------ | ---------------------------------------------------------------------- |
| Sign Message    | `POST /v1/wallets/{walletId}/signing/message`    | `POST /v1/wallets/{walletId}/addresses/{addressId}/signing/message`    |
| Sign Typed Data | `POST /v1/wallets/{walletId}/signing/typed-data` | `POST /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

| Blockchain                                                   | Signing Standard         | Signature Format                          |
| ------------------------------------------------------------ | ------------------------ | ----------------------------------------- |
| EVM (Ethereum, Polygon, BSC, Base, Arbitrum, Optimism, Celo) | EIP-191 (personal\_sign) | Hex-encoded with `r`, `s`, `v` components |
| Tron                                                         | TronWeb signMessageV2    | Hex-encoded string                        |
| Solana                                                       | Ed25519                  | Base58-encoded string                     |

### Request Parameters

| Parameter   | Type   | Required | Description                                                                         |
| ----------- | ------ | -------- | ----------------------------------------------------------------------------------- |
| `message`   | string | Yes      | The plain text message to sign. Maximum 4,096 characters.                           |
| `reference` | string | No       | Your internal tracking ID. Use for idempotency — duplicate references are rejected. |
| `metadata`  | object | No       | Custom key-value pairs stored with the transaction record.                          |

### Message Signing Example

<CodeGroup>
  ```bash Curl theme={null}
  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"
      }
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    `https://api.blockradar.co/v1/wallets/${walletId}/signing/message`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-api-key': apiKey
      },
      body: JSON.stringify({
        message: 'Please sign this message to verify your wallet ownership for Iron provider registration.',
        reference: 'iron-verification-001',
        metadata: {
          provider: 'iron',
          purpose: 'wallet-verification'
        }
      })
    }
  ).then(r => r.json());

  console.log('Signature:', response.data.hash);
  console.log('Signed transaction:', response.data.signedTransaction);
  ```

  ```php PHP theme={null}
  <?php

  $curl = curl_init();

  curl_setopt_array($curl, [
    CURLOPT_URL => "https://api.blockradar.co/v1/wallets/{walletId}/signing/message",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => "POST",
    CURLOPT_POSTFIELDS => json_encode([
      "message" => "Please sign this message to verify your wallet ownership for Iron provider registration.",
      "reference" => "iron-verification-001",
      "metadata" => [
        "provider" => "iron",
        "purpose" => "wallet-verification"
      ]
    ]),
    CURLOPT_HTTPHEADER => [
      "Content-Type: application/json",
      "x-api-key: <api-key>"
    ],
  ]);

  $response = curl_exec($curl);
  curl_close($curl);

  echo $response;
  ```
</CodeGroup>

### EVM Response

```json theme={null}
{
  "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):

```json theme={null}
{
  "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

| Field               | Description                                                                                                       |
| ------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `id`                | Unique transaction ID for the signing record                                                                      |
| `hash`              | The cryptographic signature. For EVM: hex string. For Tron: hex string. For Solana: base58 string.                |
| `status`            | Always `SUCCESS` for completed signatures                                                                         |
| `type`              | Always `SIGNED` for signing transactions                                                                          |
| `senderAddress`     | The wallet address that produced the signature                                                                    |
| `signedTransaction` | Signature components. EVM includes `r`, `s`, `v`, and full `signature`. Tron and Solana include `signature` only. |
| `reference`         | Your provided reference string (if any)                                                                           |
| `metadata`          | Your 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.

<Warning>
  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.
</Warning>

### Supported Standards

| Standard                             | Use Case                                                                   |
| ------------------------------------ | -------------------------------------------------------------------------- |
| EIP-712                              | Generic 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

| Parameter | Type   | Required | Description                                                                               |
| --------- | ------ | -------- | ----------------------------------------------------------------------------------------- |
| `domain`  | object | Yes      | EIP-712 domain separator. Includes `name`, `version`, `chainId`, and `verifyingContract`. |
| `types`   | object | Yes      | Type definitions for the structured data.                                                 |
| `message` | object | Yes      | The data to sign, conforming to the type definitions.                                     |

### EIP-2612 Permit Example

<CodeGroup>
  ```bash Curl theme={null}
  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"
      }
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    `https://api.blockradar.co/v1/wallets/${walletId}/signing/typed-data`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-api-key': apiKey
      },
      body: JSON.stringify({
        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'
        }
      })
    }
  ).then(r => r.json());

  console.log('Signature:', response.data.hash);
  console.log('r:', response.data.signedTransaction.r);
  console.log('s:', response.data.signedTransaction.s);
  console.log('v:', response.data.signedTransaction.v);
  ```
</CodeGroup>

### Typed Data Response

```json theme={null}
{
  "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

| Field               | Type   | Required | Description                                                        |
| ------------------- | ------ | -------- | ------------------------------------------------------------------ |
| `name`              | string | Yes      | The name of the signing domain (e.g., the token name or dApp name) |
| `version`           | string | Yes      | The version of the domain                                          |
| `chainId`           | number | Yes      | The chain ID. Must match the wallet's blockchain network.          |
| `verifyingContract` | string | Yes      | The contract address that will verify the signature                |
| `salt`              | string | No       | Optional domain salt for EIP-712 v4                                |

<Warning>
  Chain ID validation<br />
  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.
</Warning>

***

## Child Address Signing

Sign messages or typed data using a specific child address instead of the master wallet:

<CodeGroup>
  ```bash Curl theme={null}
  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"
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    `https://api.blockradar.co/v1/wallets/${walletId}/addresses/${addressId}/signing/message`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-api-key': apiKey
      },
      body: JSON.stringify({
        message: 'Verify ownership of deposit address for provider onboarding.',
        reference: 'address-verify-001'
      })
    }
  ).then(r => r.json());

  console.log('Signature:', response.data.hash);
  ```
</CodeGroup>

<Tip>
  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`.
</Tip>

***

## Webhook Events

Signing operations trigger a webhook with the transaction record:

| Event            | Description                               |
| ---------------- | ----------------------------------------- |
| `signed.success` | Message or typed data signed and verified |

### Webhook Payload

```json theme={null}
{
  "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:

```javascript theme={null}
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

<AccordionGroup>
  <Accordion title="Wallet Not Found">
    ```json theme={null}
    {
      "message": "Wallet not found",
      "statusCode": 404
    }
    ```

    The `walletId` does not exist or does not belong to your business.
  </Accordion>

  <Accordion title="Address Not Found">
    ```json theme={null}
    {
      "message": "Address not found",
      "statusCode": 404
    }
    ```

    The `addressId` does not exist or is not associated with the specified wallet.
  </Accordion>

  <Accordion title="Unsupported Blockchain (Typed Data)">
    ```json theme={null}
    {
      "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.
  </Accordion>

  <Accordion title="Chain ID Mismatch">
    ```json theme={null}
    {
      "message": "Chain ID mismatch",
      "statusCode": 400
    }
    ```

    The `chainId` in your typed data domain object does not match the wallet's blockchain network.
  </Accordion>

  <Accordion title="Signature Verification Failed">
    ```json theme={null}
    {
      "message": "Signature verification failed",
      "statusCode": 400
    }
    ```

    Internal round-trip verification failed. This indicates a system error — contact support.
  </Accordion>
</AccordionGroup>

***

## 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

| Endpoint                                                              | Description                  |
| --------------------------------------------------------------------- | ---------------------------- |
| [Sign Message](/en/api-reference/signing/master-wallet-sign-message)  | Sign a plain text message    |
| [Sign Typed Data](/en/api-reference/signing/master-wallet-typed-data) | Sign EIP-712 structured data |

### Child Address Endpoints

| Endpoint                                                              | Description                                       |
| --------------------------------------------------------------------- | ------------------------------------------------- |
| [Sign Message](/en/api-reference/signing/child-address-sign-message)  | Sign a plain text message from a child address    |
| [Sign Typed Data](/en/api-reference/signing/child-address-typed-data) | Sign EIP-712 structured data from a child address |
