Skip to main content
When signing messages or data, you need to properly encode your data:

Message Signing

For signing messages (personal signatures), encode your data as base64:
TypeScript
const personalSign = async (data: string) => {
  // Encode message as base64
  const message = Buffer.from(data, 'utf-8').toString('base64');
  
  const body = { message_base64: message };
  return await fetch('/v2/wallet/sign/message', { 
    method: 'POST', 
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${YOUR_JWT_TOKEN}`,
      'X-Magic-API-Key': 'YOUR_MAGIC_API_KEY',
      'X-OIDC-Provider-ID': 'YOUR_OIDC_PROVIDER_ID',
      'X-Magic-Chain': 'ETH'
    },
    body: JSON.stringify(body) 
  });
};

Data Signing

For signing transaction data or other structured data, provide a keccak256 hash:
import { typedSignatureHash } from '@metamask/eth-sig-util';

const signTypedDataV1 = async (data: TypedDataV1) => {
  // Compute hash for typed data V1
  const rawDataHash = typedSignatureHash(data);
  
  const body = { raw_data_hash: rawDataHash };
  return await fetch('/v2/wallet/sign/data', { 
    method: 'POST', 
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${YOUR_JWT_TOKEN}`,
      'X-Magic-API-Key': 'YOUR_MAGIC_API_KEY',
      'X-OIDC-Provider-ID': 'YOUR_OIDC_PROVIDER_ID',
      'X-Magic-Chain': 'ETH'
    },
    body: JSON.stringify(body) 
  });
};
import {
  MessageTypes,
  SignTypedDataVersion,
  TypedDataUtils,
  TypedMessage,
} from '@metamask/eth-sig-util';

const computeEip712Hash = (
  data: TypedMessage<MessageTypes>,
  version: SignTypedDataVersion.V3 | SignTypedDataVersion.V4,
): string => {
  const hashBuffer = TypedDataUtils.eip712Hash(data, version);
  return '0x' + hashBuffer.toString('hex');
};

const signTypedDataV3 = async (data: TypedMessage<MessageTypes>) => {
  // Compute EIP-712 hash for typed data V3
  const rawDataHash = computeEip712Hash(data, SignTypedDataVersion.V3);
  
  const body = { raw_data_hash: rawDataHash };
  return await fetch('/v2/wallet/sign/data', { 
    method: 'POST', 
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${YOUR_JWT_TOKEN}`,
      'X-Magic-API-Key': 'YOUR_MAGIC_API_KEY',
      'X-OIDC-Provider-ID': 'YOUR_OIDC_PROVIDER_ID',
      'X-Magic-Chain': 'ETH'
    },
    body: JSON.stringify(body) 
  });
};

const signTypedDataV4 = async (data: TypedMessage<MessageTypes>) => {
  // Compute EIP-712 hash for typed data V4
  const rawDataHash = computeEip712Hash(data, SignTypedDataVersion.V4);
  
  const body = { raw_data_hash: rawDataHash };
  return await fetch('/v2/wallet/sign/data', { 
    method: 'POST', 
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${YOUR_JWT_TOKEN}`,
      'X-Magic-API-Key': 'YOUR_MAGIC_API_KEY',
      'X-OIDC-Provider-ID': 'YOUR_OIDC_PROVIDER_ID',
      'X-Magic-Chain': 'ETH'
    },
    body: JSON.stringify(body) 
  });
};
import { resolveProperties, Signature, Transaction, TransactionLike, TransactionRequest } from 'ethers';

const signTransaction = async (tx: TransactionRequest) => {
  // Resolve any promises in transaction properties
  const resolvedTx = await resolveProperties(tx);
  const txForSigning = { ...resolvedTx };
  delete txForSigning.from;

  // Create transaction object and get unsigned hash
  const btx = Transaction.from(txForSigning as TransactionLike);
  
  const body = { raw_data_hash: btx.unsignedHash };
  const res = await fetch('/v2/wallet/sign/data', { 
    method: 'POST', 
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${YOUR_JWT_TOKEN}`,
      'X-Magic-API-Key': 'YOUR_MAGIC_API_KEY',
      'X-OIDC-Provider-ID': 'YOUR_OIDC_PROVIDER_ID',
      'X-Magic-Chain': 'ETH'
    },
    body: JSON.stringify(body) 
  });
  
  const { r, s, v } = await res.json();
  
  // Attach signature to transaction
  btx.signature = Signature.from({ r, s, v });
  return btx.serialized;
};