Skip to main content
Restore a user’s wallet access when they forget their PIN. The user answers the security questions they set during sign-up, then sets a new PIN. The answers to security questions are the user’s responsibility to remember.
Circle has no way to recover an account when both the PIN and the security answers are lost. The user is permanently locked out of their account and all wallets and assets.

Prerequisites

Before you begin, ensure that you’ve:
  • Obtained a Circle Developer API key from the Circle Console.
  • Completed the Build a Wallet App tutorial with the PIN method, which sets up a user-controlled wallet, stores the user’s userId, and configures the user’s security questions.
  • Integrated a user-controlled wallet client-side SDK in your app to walk the user through the recovery challenge: Web SDK, iOS SDK, Android SDK, or React Native SDK.
  • Installed the user-controlled wallet server-side SDK in your backend to create the recovery challenge: Node.js or Python.

Steps

1

Acquire a session token

Request a 60-minute session token for the user. The token authorizes the recovery challenge later in the flow.
import { initiateUserControlledWalletsClient } from "@circle-fin/user-controlled-wallets";

const client = initiateUserControlledWalletsClient({
  apiKey: process.env.CIRCLE_API_KEY!,
});

const response = await client.createUserToken({
  userId: "2f1dcb5e-312a-4b15-8240-abeffc0e3463",
});

const userToken: string = response.data!.userToken;
const encryptionKey: string = response.data!.encryptionKey;
2

Initialize the recovery challenge

Use the userToken to create a recovery challenge. The SDK returns a challengeId that your client-side SDK uses to walk the user through answering their security questions and setting a new PIN.
const response = await client.restoreUserPin({
  userToken,
});

const challengeId: string = response.data!.challengeId;
Include an idempotencyKey (a UUID) on the call to safely retry the request without creating duplicate challenges. See Idempotent requests for details on idempotency key usage.
3

Have the user answer their security questions

Pass the userToken, encryptionKey, and challengeId to your client-side SDK. The SDK presents the recovery UI to the user, who:
  1. Answers their pre-set security questions.
  2. Enters and confirms a new PIN.
The SDK completes the challenge with Circle.
4

Check the challenge status

Confirm the recovery completed. Use webhooks (push) or polling (pull) to detect when the challenge reaches a terminal status: COMPLETED, FAILED, or EXPIRED. A COMPLETED status means the account was successfully recovered and the new PIN is active.
Subscribe to user challenge notifications and listen for the event matching your challengeId. The notification includes the challenge status and type (RESTORE_PIN for account recovery).
Webhook notification
{
  "subscriptionId": "d4c07d5f-f05f-4fe4-853d-4dd434806dfb",
  "notificationId": "acab8c14-92ae-481a-8335-6eb5271da014",
  "notificationType": "challenges.initialize",
  "notification": {
    "id": "c4d1da72-111e-4d52-bdbf-2e74a2d803d5",
    "userId": "2f1dcb5e-312a-4b15-8240-abeffc0e3463",
    "type": "RESTORE_PIN",
    "status": "COMPLETE",
    "correlationIds": ["54399e5a-1bf6-4921-9559-10c1115678cd"],
    "errorCode": 0,
    "errorMessage": ""
  },
  "timestamp": "2026-01-15T14:33:17.785131449Z",
  "version": 2
}
For webhook setup, see Webhook Notifications.
For a full list of possible statuses, see Asynchronous States and Statuses.

Error handling

Handle these common failure cases when integrating account recovery:
  • Expired session token (error code 155104): The userToken from Step 1 expires after 60 minutes. If you get this error, request a new session token and retry.
  • Incorrect security answers (error code 155115): The user’s answers must match what they set during sign-up. After three incorrect attempts, recovery locks for 30 minutes (155120).
  • Security questions not set (error code 155111): The user must have set security questions during sign-up to use account recovery. If they haven’t, recovery isn’t available.
  • Security questions already used: Security questions can be set only once during sign-up and can’t be reset (155108). If the user can’t remember their answers, no recovery path exists.
For a complete error code reference, see Wallets error codes.