A debit card your users fund with stablecoins. Issued in seconds.

Your users sign in with email or social and get an embedded wallet and a virtual Visa card in the same flow. They fund it gaslessly from their own stablecoin balance and spend it anywhere Visa is accepted - issue, fund, and reveal the card in a handful of calls.

@dynamic-labs-sdk/client@dynamic-labs-sdk/react-hooks@dynamic-labs-sdk/evm
  1. Create the wallet

    Docs

    One Dynamic client per app. The EVM extension gives every user an embedded wallet - the card's funding source and the signer for gasless transfers.

    lib/dynamic-client.ts
    import { createDynamicClient } from "@dynamic-labs-sdk/client";
    import { addEvmExtension } from "@dynamic-labs-sdk/evm";
    
    export const client = createDynamicClient({
      environmentId: process.env.NEXT_PUBLIC_DYNAMIC_ENVIRONMENT_ID!,
    });
    addEvmExtension(client);
  2. Issue the card

    On your server - the Rain Api-Key never touches the browser. Submit the KYC application for a userId, then issue a virtual card for that user.

    server/issue-card.ts
    const RAIN = "https://api-dev.raincards.xyz/v1/issuing";
    const auth = {
      "Api-Key": process.env.RAIN_API_KEY!,
      "Content-Type": "application/json",
    };
    
    // POST /v1/issuing/applications/user  ->  KYC, returns the Rain userId
    const { userId } = await fetch(`${RAIN}/applications/user`, {
      method: "POST",
      headers: auth,
      body: JSON.stringify(application),
    }).then((r) => r.json());
    
    // POST /v1/issuing/users/:userId/cards  ->  the virtual card
    const card = await fetch(`${RAIN}/users/${userId}/cards`, {
      method: "POST",
      headers: auth,
      body: JSON.stringify({ type: "virtual" }),
    }).then((r) => r.json());
  3. Reveal card details

    The plaintext PAN/CVC never touch your server. The browser mints an AES key and passes its SessionId; Rain returns the secrets ENCRYPTED, your server relays them, and the browser decrypts locally.

    server/card-secrets.ts
    // GET /v1/issuing/cards/:cardId/secrets   (SessionId = the browser's key)
    const encrypted = await fetch(`${RAIN}/cards/${cardId}/secrets`, {
      headers: { "Api-Key": process.env.RAIN_API_KEY!, SessionId: sessionId },
    }).then((r) => r.json());
    
    // Relay `encrypted` to the browser, which decrypts with its own key.
    const pan = await decryptSecret(encrypted.encryptedPan, secretKey);
    const cvc = await decryptSecret(encrypted.encryptedCvc, secretKey);
  4. Read the balance

    Spending power comes straight from Rain, keyed by the userId. Read it on your server and surface it to the UI.

    server/balance.ts
    // GET /v1/issuing/users/:userId/balances
    const balance = await fetch(`${RAIN}/users/${userId}/balances`, {
      headers: { "Api-Key": process.env.RAIN_API_KEY! },
    }).then((r) => r.json());
    
    balance.spendingPower; // what the card can spend right now
  5. Get the deposit address

    Each user has a per-chain Rain deposit contract; stablecoins sent to it fund the card. Fetch it (or create it once) for the funding chain.

    server/deposit-address.ts
    // GET /v1/issuing/users/:userId/contracts
    // (POST the same path with { chainId } to create one the first time)
    const contracts = await fetch(`${RAIN}/users/${userId}/contracts`, {
      headers: { "Api-Key": process.env.RAIN_API_KEY! },
    }).then((r) => r.json());
    
    const depositAddress = contracts.find(
      (c) => c.chainId === 84532, // Base Sepolia
    )?.depositAddress;
  6. Fund it gaslessly

    Docs

    Back in the browser: a sponsored stablecoin transfer from the user's embedded wallet to that Rain deposit address - EIP-7702, no native gas, no approval popups.

    hooks/use-fund-card.ts
    import { sendSponsoredTransaction } from "@dynamic-labs-sdk/evm";
    
    const { transactionHash } = await sendSponsoredTransaction({
      walletAccount,
      calls: [
        {
          target: USDC_ADDRESS,
          data: encodeTransfer(depositAddress, amount),
        },
      ],
    });
Stablecoin Card - Dynamic Demos