Wallets

Web SDK

Set up the client-side web SDK for user-controlled wallets in your web application.

The Circle Web SDK enables user-controlled wallets within your web application. Three authentication methods are supported, namely social logins, email, or PIN, which includes security questions for recovery. This allows you to authenticate your users in a seamless way and create user-controlled wallets for them.

By integrating this client-side SDK, your users can securely create wallets and make transactions using social accounts or email. If you choose the PIN authentication method, your users can input sensitive data, like PINs or security answers, in a secure way. Moreover, the SDK encrypts the request body sent by the application, protecting your users' information.

At Circle, we understand the importance of end-to-end security for your application and the need to create a tailored and seamless user experience for your end-users. Hence, Circle’s SDK also exposes functionality for you to customize the description and layout. See the Web SDK UI Customization API article to customize the SDK.

Install using npm:

Shell
npm install @circle-fin/w3s-pw-web-sdk

You must use Web, iOS, or Android SDKs to access the user-controlled Programmable Wallet product. The SDK secures, manages, and communicates with your server to ensure your user’s keyshare, always stays with them and is not exposed to your servers.

To learn more, see SDK Architecture for User-Controlled Wallets.

The Web SDK supports the API reference enums listed in the following sections.

Enumerates the types of challenges supported.

JavaScript
enum ChallengeType {
  INITIALIZE,
  SET_PIN,
  RESTORE_PIN,
  CHANGE_PIN,
  SET_SECURITY_QUESTIONS,
  CREATE_WALLET,
  CREATE_TRANSACTION,
  ACCELERATE_TRANSACTION,
  CANCEL_TRANSACTION,
  CONTRACT_EXECUTION,
  SIGN_MESSAGE,
  SIGN_TYPEDDATA,
  SIGN_TRANSACTION,
  WALLET_UPGRADE,
  UNKNOWN,
}

Enumerates the possible status for a challenge.

JavaScript
enum ChallengeStatus {
  COMPLETE,
  EXPIRED,
  FAILED,
  IN_PROGRESS,
  PENDING,
}

Enumerates the types of security questions.

JavaScript
enum QuestionType {
  DATE,
  TEXT,
}

Enumerates the types of error code.

JavaScript
enum ErrorCode {
  unknown = -1,
  success = 0,
  apiParameterMissing = 1,
  apiParameterInvalid = 2,
  forbidden = 3,
  unauthorized = 4,
  retry = 9,
  customerSuspended = 10,
  pending = 11,
  invalidSession = 12,
  invalidPartnerId = 13,
  invalidMessage = 14,
  invalidPhone = 15,
  userAlreadyExisted = 155101,
  userNotFound = 155102,
  userTokenNotFound = 155103,
  userTokenExpired = 155104,
  invalidUserToken = 155105,
  userWasInitialized = 155106,
  userHasSetPin = 155107,
  userHasSetSecurityQuestion = 155108,
  userWasDisabled = 155109,
  userDoesNotSetPinYet = 155110,
  userDoesNotSetSecurityQuestionYet = 155111,
  incorrectUserPin = 155112,
  incorrectDeviceId = 155113,
  incorrectAppId = 155114,
  incorrectSecurityAnswers = 155115,
  invalidChallengeId = 155116,
  invalidApproveContent = 155117,
  invalidEncryptionKey = 155118,
  userPinLocked = 155119,
  securityAnswersLocked = 155120,
  notEnoughFunds = 155201,
  notEnoughBalance = 155202,
  exceedWithdrawLimit = 155203,
  minimumFundsRequired = 155204,
  invalidTransactionFee = 155205,
  rejectedOnAmlScreening = 155206,
  tagRequired = 155207,
  gasLimitTooLow = 155208,
  transactionDataNotEncodedProperly = 155209,
  fullNodeReturnedError = 155210,
  walletSetupRequired = 155211,
  lowerThenMinimumAccountBalance = 155212,
  rejectedByBlockchain = 155213,
  droppedAsPartOfReorg = 155214,
  operationNotSupport = 155215,
  amountBelowMinimum = 155216,
  wrongNftTokenIdNumber = 155217,
  invalidDestinationAddress = 155218,
  tokenWalletChainMismatch = 155219,
  wrongAmountsNumber = 155220,
  walletIsFrozen = 155501,
  maxWalletLimitReached = 155502,
  walletSetIdMutuallyExclusive = 155503,
  metadataUnmatched = 155504,
  userCanceled = 155701,
  launchUiFailed = 155702,
  pinCodeNotMatched = 155703,
  insecurePinCode = 155704,
  hintsMatchAnswers = 155705,
  networkError = 155706,
  invalidUserTokenFormat= 155718,
  walletIdNotFound = 156001,
  tokenIdNotFound = 156002,
  transactionIdNotFound = 156003,
  entityCredentialNotFound = 156004,
  walletSetIdNotFound = 156005,
}

The Web SDK supports the interfaces listed in the following sections.

Holds application settings.

  • appId <string> Application ID, retrieved from Circle Developer Services Console

Holds authentication information.

Holds login configuration information.

  • google: Configuration object for Google login.
    • clientId: The Client ID for Google login.
    • redirectUri: The Redirect URI for Google login.
    • selectAccountPrompt: Whether to prompt the user to select an account when signing in.
  • facebook: Configuration object for Facebook login.
    • appId: The App ID for Facebook login.
    • redirectUri: The Redirect URI for Facebook login.
  • apple: Configuration for Apple login, using Firebase.
  • FirebaseOptions: The Firebase configuration object.
  • deviceToken: The token used to identify the device.
  • deviceEncryptionKey: The encryption key used for the device.
  • otpToken: The optional OTP token for verification.

Holds information about a challenge.

Holds the result of a challenge.

Holds the result of a sign message or sign typed-data challenge.

  • signature <string> Signature result after signing

Holds the result of a sign transaction challenge.

  • signature <string> Signature result after signing
  • txHash <string> Transaction hash
  • signedTransaction <string> Signed transaction

Holds the result of a social login.

Holds the result of an email login.

Holds the OAuth information.

Holds error information.

Callback function for social login completion.

Holds information about a custom security question.

Holds localization settings.

Holds localization settings for common texts.

Holds localization settings for ConfirmInitPincode or ConfirmNewPincode screen.

Holds localization settings for EnterPincode screen.

Holds localization settings for InitPincode or NewPincode screen.

Holds localization settings for RecoverPincode screen.

Holds localization settings for SecurityConfirm screen.

Holds localization settings for SecurityIntros screen.

Holds localization settings for SecurityQuestions screen.

Holds localization settings for SecuritySummary screen.

Holds localization settings for SocialEmailConfirmationUI screen.

Holds localization settings for TransactionRequest screen.

Holds localization settings for a contract interaction screen.

Holds localization settings for a signature request screen.

Holds localization settings for an email OTP (One-Time Password) screen.

Holds customization color settings.

Holds resource urls and properties, such as images or font-family settings. These resource properties should be hosted on a public server. SDK will load these resources from the urls provided.

Holds custom links.

The Web SDK supports the class definitions listed in the following sections.

Initializes a new instance of W3SSdk.

Executes a challenge.

Sets the application settings.

Sets the authentication information.

Updates the configurations.

Gets the device ID.

Performs a social login.

Verifies the OTP.

Executes a challenge.

Sets custom security questions.

Sets custom localizations

Sets custom resources

Sets custom theme colors

Sets custom links

Sets callback function for ForgotPin button click event

Sets callback function for Resend OTP Email button click event

JavaScript
import React, { useCallback, useEffect, useState } from 'react'
import { ToastContainer, toast } from 'react-toastify'
import TextField from '@mui/material/TextField'
import Button from '@mui/material/Button'
import { W3SSdk } from '@circle-fin/w3s-pw-web-sdk'

let sdk: W3SSdk

function App() {
  useEffect(() => {
    sdk = new W3SSdk({
      configs: {
        appSettings: { appId: 'someAppId' },
        authentication: {
          userToken: 'someUserToken',
          encryptionKey: 'someEncryptionKey'
        },
        socialLoginConfig: {}
      },
      socialLoginCompleteCallback: (error, result) => {
        if (error) {
          toast.error(`Social Login Error: ${error.message ?? 'Error!'}`)
          return
        }
        toast.success(`Social Login Success: ${result?.userToken}`)
      }
    })
  }, [])

  const [appId, setAppId] = useState(localStorage.getItem('appId') || 'someAppId')
  const [userToken, setUserToken] = useState(localStorage.getItem('userToken') || 'someUserToken')
  const [encryptionKey, setEncryptionKey] = useState(localStorage.getItem('encryptionKey') || 'someEncryptionKey')
  const [challengeId, setChallengeId] = useState(localStorage.getItem('challengeId') || 'someChallengeId')

  const onChangeHandler = useCallback(
    (setState, key) => (e) => {
      const value = e.target.value
      setState(value)
      localStorage.setItem(key, value)
    },
    []
  )

  const onSubmit = useCallback(() => {
    sdk.setAppSettings({ appId })
    sdk.setAuthentication({ userToken, encryptionKey })

    sdk.execute(challengeId, (error, result) => {
      if (error) {
        toast.error(`Error: ${error?.message ?? 'Error!'}`)
        return
      }
      toast.success(`Challenge: ${result?.type}, Status: ${result?.status}`)
    })
  }, [appId, userToken, encryptionKey, challengeId])

  return (
    <div className="p-4">
      <TextField
        label="App Id"
        onChange={onChangeHandler(setAppId, 'appId')}
        value={appId}
      />
      <TextField
        label="User Token"
        onChange={onChangeHandler(setUserToken, 'userToken')}
        value={userToken}
      />
      <TextField
        label="Encryption Key"
        onChange={onChangeHandler(setEncryptionKey, 'encryptionKey')}
        value={encryptionKey}
      />
      <TextField
        label="Challenge Id"
        onChange={onChangeHandler(setChallengeId, 'challengeId')}
        value={challengeId}
      />
      <Button variant="contained" color="primary" onClick={onSubmit}>
        Verify Challenge
      </Button>
      <ToastContainer />
    </div>
  )
}
JavaScript
// Assume W3SSdk is globally available
let sdk = new W3SSdk({
  configs: {
    appSettings: { appId: 'someAppId' },
    authentication: {
      userToken: 'someUserToken',
      encryptionKey: 'someEncryptionKey'
    },
    socialLoginConfig: {}
  },
  socialLoginCompleteCallback: (error, result) => {
    if (error) {
      console.error(`Social Login Error: ${error.message ?? 'Error!'}`)
      return
    }
    console.log(`Social Login Success: ${result?.userToken}`)
  }
})

// Initialize settings
const initSettings = () => {
  sdk.setAppSettings({
    appId: 'someAppId',
  })
  sdk.setAuthentication({
    userToken: 'someUserToken',
    encryptionKey: 'someEncryptionKey',
  })
}

// Handle form submission
const handleSubmit = () => {
  const challengeId = document.getElementById('challengeId').value

  sdk.execute(challengeId, (error, result) => {
    if (error) {
      console.error(`Error: ${error?.message ?? 'Error!'}`)
      return
    }
    console.log(`Challenge: ${result?.type}, Status: ${result?.status}`)
  })
}

// Initialization
initSettings()

// Listen for button click event
document.getElementById('submitBtn').addEventListener('click', handleSubmit)sdk.execute(challengeId, (error, result) => {
  if (error) {
    toast.error(`Error: ${error?.message ?? 'Error!'}`)
    return
  }
  toast.success(`Challenge: ${result?.type}, Status: ${result?.status}`)
})
Did this page help you?
© 2023-2025 Circle Technology Services, LLC. All rights reserved.