- Authenticates users with a one-time passcode (OTP) sent by email
- Creates a user-owned wallet and connects it to your app
- Displays the wallet address and the USDC balance it holds
Prerequisites
Before you begin, ensure you have:- A Mailtrap account with Email Sandbox enabled.
- A Circle Developer Console account.
- A Circle Developer API key:
Console → Keys → Create a key → API key → Standard Key. - Node.js 18+ installed.
Step 1. Get Mailtrap SMTP credentials
In this step, you copy SMTP credentials from Mailtrap so Circle can send OTP codes to users.- Log in to your Mailtrap account.
- In the left navigation, click Transactional → Sandboxes.
- Open the default sandbox project (My Sandbox) or create a new one.
- In the sandbox view, select the SMTP Settings tab.
-
Copy the following SMTP values:
- Host
- Port
- Username
- Password
Step 2. Configure the Circle Console
In this step, you add your Mailtrap SMTP credentials to the Circle Console so Circle can send emails with OTP codes. You also obtain your App ID, which identifies your user-controlled wallets configuration in the Circle Console.- Log in to the Circle Developer Console.
- Navigate to Wallets → User Controlled → Configurator.
- Under Authentication Methods, click Email.
- Enter a From email address (for example,
no-reply@example.com). - Enter the SMTP values you copied from Mailtrap:
- Host
- Port
- Username
- Password
- (Optional) Customize your OTP email from, subject, and message body.
- Go to the Configurator page and copy your App ID. You need it for the next step.
Step 3. Create the web application
In this step, you create a web app that lets users authenticate with an OTP code sent to their email address, and create a blockchain wallet.3.1. Create the Next.js project
In your terminal:3.2. Install dependencies
Install the user-controlled wallets Web SDK:3.3. Add environment variables
Create a.env.local file in your project directory:
.env.local file and add the following:
.env.local
YOUR_CIRCLE_API_KEYis your Circle Developer API key.YOUR_CIRCLE_APP_IDis the Circle Wallet App ID obtained in Step 2.
3.4. Simplify the default layout
Replace the contents ofapp/layout.tsx with the minimal layout below:
app/layout.tsx
Next.js requires an
app/layout.tsx file, but the default one created by
create-next-app includes fonts and styling that can cause build errors in
some environments.3.5. Add unified backend route
Create a file namedapp/api/endpoints/route.ts and add the code below:
app/api/endpoints/route.ts
| Handler | Description |
|---|---|
requestEmailOtp | calls POST /v1/w3s/users/email/token to initiate email authentication and return temporary verification tokens required by the Web SDK to verify the OTP entered by the user. |
initializeUser | calls POST /v1/w3s/user/initialize to create or initialize a user and return a challengeId required for wallet creation. |
listWallets | calls GET /v1/w3s/wallets to retrieve the wallets associated with the authenticated user. |
getTokenBalance | calls GET /v1/w3s/wallets//balances to retrieve digital asset balances for the specified user-controlled wallet. |
This quickstart calls
listWallets and getTokenBalance directly for
simplicity. In production, apps typically store wallet and balance data in a
backend database and keep it in sync using Circle webhooks for scalability.3.6. Add UI and frontend code
Replace the contents ofapp/page.tsx with the code below:
app/page.tsx
Step 4. Run the app flow
- Start the dev server:
- Open http://localhost:3000 in your browser to view the app.
-
Complete the email OTP authentication and wallet creation flow:
- Enter an email address: Choose an email address for the user who will authenticate. This email address is used only to receive a one-time passcode (OTP) during sign-in.
-
Click Send email OTP: The Web SDK generates a unique
deviceId, which identifies the user’s browser. Your backend sends thedeviceIdand email address to Circle, which emails an OTP code and returns temporary verification tokens (deviceToken,deviceEncryptionKey,otpToken) used by the Web SDK to verify the OTP. -
Open your Mailtrap Sandbox → Inbox to view the OTP email sent by
Circle. When using a Mailtrap Email Sandbox, OTP emails are received in
the Mailtrap UI by default and are not delivered to the user’s inbox,
unless email forwarding is configured.
In a production app, you should configure your SMTP provider to deliver OTP codes directly to users’ email inboxes.
-
Click Verify email OTP: Circle opens a hosted OTP verification window.
The user enters the code they received. The Web SDK verifies the OTP with
Circle, which then returns a
userTokenandencryptionKey. Together, they enable an authenticated Circle user session. -
Click Initialize user: Your backend initializes the user using the
userToken. If the user hasn’t created a wallet yet, Circle returns achallengeIdto create one. If the user is already initialized, the app loads the existing wallet instead. -
Click Create wallet: The Web SDK executes the challenge using the
challengeId. The user approves the action, and Circle creates the wallet.
-
Once the flow completes:
- The app displays the wallet’s address, blockchain, and USDC balance.
- You can verify the user was created in the
Circle Dev Console:
Wallets → User Controlled → Users.
Step 5. Fund the wallet
In this step, you fund the new wallet manually using the Circle Faucet and confirm the updated balance in the app.- Copy the wallet address (
0x...) from the web app UI. - Visit the official Circle Faucet.
- Select Arc Testnet as the blockchain network.
- Paste the wallet address in the Send to field.
- Click Send USDC.
- Return to the app and walk through the flow again.
Note: Use the same email address to show the same wallet. - The app will display the updated USDC balance.
In this step, you’re acting as the end user to fund your user-controlled
wallet for testing. In production, app developers don’t control user wallets
or private keys. Instead, users typically fund wallets themselves, but apps
may also fund using faucets or airdrops without requiring wallet access.