How Programmable Wallets & Debit Cards can Enable USDC-Powered Fiat Payments

Web3 Services Programmable Wallets Developer



USDC is a digital dollar that runs on the blockchain, enabling anyone in the world to access and transact with a stable store of value. This accessibility is a game-changer, as it allows individuals and businesses to participate in the global economy regardless of their geographic location or traditional banking access.

When you couple USDC with a debit card, the possibilities expand even further. USDC holders can now seamlessly spend their digital dollars virtually anywhere card processing networks are supported, bridging the gap between the digital and physical worlds. This integration of USDC and debit card functionality removes the need for conversions and off-ramps, providing a streamlined user experience for spending digital currency in the real world.

Connecting Debit Cards to Wallets for Real-World Spending

We'll build this solution using the developer-controlled wallets model within Circle's Programmable Wallets API.

The challenge with creating a solution for linking debit cards to USDC is that when a user tries to use a debit card, the system needs to know within seconds if the user has enough USDC to cover the purchase. 

But Circle has the wallet infrastructure needed to support this flow. With Circle’s tools, you can receive the request, check the user’s USDC balance, and return an authorization quickly, allowing users to spend their USDC in real-time. 

Let’s walk through the architecture of the app as we follow the user journey through six steps. Before starting this flow, note that you will need your company to have a traditional USD bank account and access to USDC on/off ramps.

The general flow looks like this:

  1. User opens an account to the developer’s app
  2. Wallet is created
  3. User funds card
  4. Card presented
  5. Transaction approved
  6. Funds released

Let’s go into detail for each step.

Step 1. User opens an account

First, you need to onboard the user. For these steps, you can rely on building blocks from fintech solutions:

  • The user fills out an application for the debit card on the developer’s site
  • The user completes a KYC process
  • Developer’s app will route the information for approval
  • If the user is approved, a card is issued

Step 2. Embedded wallet created

Before the approved and issued card is actually given to the user, you need to create the user’s embedded wallet. You’ll do this automatically behind the scenes.

Let’s look at an overview of how to create developer-controlled wallets in your app. For a more thorough walkthrough, please read our detailed guide.

First, you need to create a wallet set. A wallet set is a collection of wallets that are controlled by the same cryptographic key. Before you start, be sure to create and set up your project including creating the ciphertext and adding it to the Configurator page.

To create a wallet set, use the following call to the API:

const { initiateDeveloperControlledWalletsClient } = require('@circle-fin/developer-controlled-wallets')

const client = initiateDeveloperControlledWalletsClient({
  apiKey: '',
  entitySecret: '',

async function createWalletSet() {

    const walletSetResponse = await client.createWalletSet({
        name: "WalletSet A",

    return walletSetResponse

Once you have your wallet set, you need to create our actual wallet. To do this, you will deploy a smart contract account (SCA) wallet.

async function createWallets() {

    const walletSetResponse = await createWalletSet()

    const walletResponse = await client.createWallets({
        blockchains: ["MATIC-AMOY"],
        count: 1,
        accountType: "SCA",

    return walletResponse

You can view your wallets in Console.


Once the wallets are created, the backend of the app can simply assign a wallet (or a wallet set) to the user.

Step 3: User funds card

Before the user can spend USDC, the user must first have USDC in the user’s wallet. There are several ways users can deposit USDC. You could add a flow for users to fund that wallet. Or you could simply expose the address of the developer-controlled wallet and the user could deposit funds directly from a self-custodial wallet or from a digital asset exchange.

When your app needs to know the balance of the wallet, you can use the Developer-Controlled Programmable Wallets SDK to retrieve it:

async function getBalance(walletId) {

    const balances = await client.getWalletTokenBalance({
        id: walletId,

    return balances;

Note that you will use the wallet ID (created by Programmable Wallets) when inquiring for balance and not the wallet address.

The above command lists the balances of all tokens by default. You can show only USDC balances with the following request:

async function getUsdcBalance(walletId) {

    const balances = await client.getWalletTokenBalance({
        id: walletId,
        tokenAddresses: [
            // USDC Contract address on Mumbai

    return balances

Step 4: Card transaction initiated

Now that the infrastructure is in place, the user can spend USDC. In this step, the user can present the card at a retailer as they would any other card.

Step 5: Transaction approved

The approval happens in a series of steps:

  1. You receive the request from card network and check to be sure the user’s wallet has sufficient USDC
  2. If yes, you approve the transaction and route the request to appropriate card network for authorization
  3. Card network approves the user purchase at the retailer
  4. Card network debits USD from our USD bank account

Step 6: Funds released

The purchase above was paid for using your app’s company bank account. The final step is to debit the appropriate amount of USDC from the user’s developer-controlled wallet. 

Since you control the private keys of the wallet, you don’t need permission from the user to debit the USDC, and users can’t block access to the wallets after the purchase but before the debit.

Since this is an SCA wallet, you also have the option to pay the network gas fees and abstract away the details of the blockchain from the user using Circle’s Gas Station. Or if you’d rather, you can charge the user for the network gas fees but give it a more friendly name such as transaction fees.

Here’s a code snippet that transfers funds out of the user’s wallet and into our company wallet:

async function transfer(walletId) {

    const trxResponse = await client.createTransaction({
        idempotencyKey: "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11",
        walletId: walletId,
        tokenAddress: "0xe6b8a5CF854791412c1f6EFC7CAf629f5Df1c747",
        destinationAddress: "",
        amount: [
        fee: "MEDIUM",

    return trxResponse;

Learn More

By leveraging Circle’s USDC and Programmable Wallets, developers can build a powerful solution that allows users to spend their USDC for everyday purchases. And with the right design, transacting with USDC can be as easily integrated in traditional payment methods.

New call-to-action

*Services are provided by Circle Technology Services, LLC (“CTS”). Services do not include financial, investment, tax, legal, regulatory, accounting, business, or other advice. CTS is only a provider of software and related technology and is not engaged in any regulated money transmission activity in connection with the services it provides. For additional details, please click here to see the Circle Developer terms of service.

Back to top