Skip to main content
Gnosis Ramp supports wallet-based authentication via Sign-In with Ethereum (SIWE) for Gnosispay users. This enables KYC sharing — users who completed KYC with Gnosispay can skip re-verification when using your ramp integration.

Why Use External Auth?

Skip Re-KYC

Users who verified with Gnosispay don’t need to complete KYC again.

Faster Onboarding

Compliance steps complete in seconds instead of minutes.

How KYC Sharing Works

  1. User authenticates via SIWE with their Gnosispay wallet
  2. You create a customer with the resulting token
  3. When creating intents, the system recognizes existing KYC
  4. Compliance auto-completes or fast-tracks

SIWE Authentication Flow

1

Request a nonce

Call GET /gnosispay/auth/nonce to retrieve a one-time nonce.
2

User signs SIWE message

Construct a SIWE message and have the user sign it with their wallet.
3

Verify the signature

Call POST /gnosispay/auth/challenge with the signed message.
4

Create customer with token

Use the returned token as subject_token when creating the customer.

Step 1: Get a Nonce

curl https://api.ramp.gnosis.io/v1/gnosispay/auth/nonce
Response (plain text):
2bfa23fbac97a5bb9d0282061452c284810b294bf983b558ecd86d63047d74f3

Step 2: Sign the SIWE Message

Construct and sign the SIWE message on the client side. The message must use chain ID 100 (Gnosis Chain).
import { SiweMessage } from 'siwe';

const message = new SiweMessage({
  domain: window.location.host,
  address: walletAddress,
  statement: 'Sign in with Ethereum to Gnosis Pay',
  uri: 'https://api.gnosispay.com/',
  version: '1',
  chainId: 100,
  nonce: nonce, // from Step 1
});

const messageString = message.prepareMessage();
const signature = await signer.signMessage(messageString);
Example message format:
gnosispay-api-siwe-demo.vercel.app wants you to sign in with your
Ethereum account:
0x8480d6166F9dd6bd74394fc6c514F10bd20a6d4C

Sign in with Ethereum to Gnosis Pay

URI: https://api.gnosispay.com/
Version: 1
Chain ID: 100
Nonce: 2bfa23fbac97a5bb9d0282061452c284...
Issued At: 2026-03-29T10:00:00.000Z

Step 3: Verify the Signature

curl -X POST https://api.ramp.gnosis.io/v1/gnosispay/auth/challenge \
  -H "Content-Type: application/json" \
  -d '{
    "message": "<SIWE_MESSAGE_STRING>",
    "signature": "0x70bd2ce7f51cda4f02a82cd1b4f0c62c1da1f2ec..."
  }'
FieldDescription
messageThe full SIWE message string
signatureThe wallet signature
ttlInSecondsOptional. Token time-to-live (default: 3600)
Response:
{
  "token": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Step 4: Create Customer with Token

Use the token from Step 3 as subject_token:
curl -X POST https://api.ramp.gnosis.io/v1/customers \
  -u "${CLIENT_ID}:${CLIENT_SECRET}" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "gp-0x8480d6166F9dd6bd74394fc6c514F10bd20a6d4C",
    "subject_token": "<TOKEN_FROM_CHALLENGE>"
  }'
Response:
{
  "id": "gp-0x8480d6166F9dd6bd74394fc6c514F10bd20a6d4C",
  "accessToken": "eyJhbGciOiJIUzI1NiIs...",
  "createdAt": "2026-03-29T10:00:00.000Z",
  "updatedAt": "2026-03-29T10:00:00.000Z"
}

Complete JavaScript Example

import { SiweMessage } from 'siwe';

async function createCustomerWithSIWE(walletAddress, signer) {
  // 1. Get nonce
  const nonce = await fetch('https://api.ramp.gnosis.io/v1/gnosispay/auth/nonce')
    .then(r => r.text());

  // 2. Sign SIWE message
  const message = new SiweMessage({
    domain: window.location.host,
    address: walletAddress,
    statement: 'Sign in with Ethereum to Gnosis Pay',
    uri: 'https://api.gnosispay.com/',
    version: '1',
    chainId: 100,
    nonce,
  });
  const messageString = message.prepareMessage();
  const signature = await signer.signMessage(messageString);

  // 3. Verify signature
  const challengeResponse = await fetch(
    'https://api.ramp.gnosis.io/v1/gnosispay/auth/challenge',
    {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ message: messageString, signature }),
    }
  ).then(r => r.json());

  // 4. Create customer with token
  const credentials = btoa(`${CLIENT_ID}:${CLIENT_SECRET}`);
  const customerResponse = await fetch(
    'https://api.ramp.gnosis.io/v1/customers',
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Basic ${credentials}`,
      },
      body: JSON.stringify({
        id: `gp-${walletAddress}`,
        subject_token: challengeResponse.token,
      }),
    }
  ).then(r => r.json());

  return customerResponse.accessToken;
}

What Happens During Compliance

When a customer created with external auth creates an intent:
  1. Auto-complete: If all KYC requirements are already satisfied, the intent skips to COMPLIANCE_APPROVED status immediately
  2. Fast-track: If some requirements are satisfied, only the remaining steps are shown in the onboarding iframe
See Handling Compliance for details on how auto-complete works.

Prerequisites

For KYC sharing to work:
  • User must have a Gnosispay account
  • User must have completed KYC verification with Gnosispay
  • Your ramp provider must support KYC sharing (contact our business team for details)

Next Steps

Create an Intent

Start a ramp operation for the customer.

Handling Compliance

Learn how auto-complete works for KYC-shared users.