SDK v1.0.0 · TypeScript

Wallet sign-in SDK

No built-in UI — the look and feel are yours. ChainBridge handles authentication and sessions. Browser and Node.js entry points are included, and mobile QR pairing runs over the official WalletConnect relay.

Quick start

Setup steps

The wallet signs; your server binds the challenge and holds the metered API key. The WalletConnect project ID is only for public relay configuration and differs from the ChainBridge API key.

1
Prepare a server key and app origin Create a key with Connect product permissions on the API Keys page in the console. Keep it server-side only, and pin the app origin and domain. QR pairing also needs a public project ID from WalletConnect.
2
Create a session server-side Call POST /api/v1/connect/session to get the nonce, domain, chain, and expiry.
3
Connect and sign in the browser Connect to Ethereum mainnet with the wallet API. The user signs the SIWE message exactly as issued, then your server receives the signature.
4
Verify the signature and open a session Call POST /api/v1/connect/siwe/verify, then issue your own sign-in session.
Never hardcode keys in clients

Treat any key in browser or mobile code as public.cs_live_xxx API keys in that form belong on your server only. QR pairing needs a public 32-character hex WalletConnect project ID; metered API keys and app sessions never leave your server. If a key leaks, disable it in the console right away and review usage.

Integration options

The fastest route is the script include — no build tool, no dependencies. Add the two lines below to your page and the button opens the ChainBridge wallet connect dialog. Copy the project ID in one click from the Wallet Connection page in the console. It is not the same as cs_live_ prefixed API keys — a key belongs on the server.

Three-line setup (HTML)
<script src="/site/sdk/connect.js"></script>
<chainbridge-button project-id="CS-P-XXXXXX"></chainbridge-button>

To control timing, use JS: callChainBridge.init({ projectId }) then call ChainBridge.open(); the connect result arrives through the ChainBridge.on('connect', fn) callback { address, chainId, namespace, sessionNo }. Origins are enforced server-side: sites outside the allowlist get a 403 with a clear reason.

JS control
ChainBridge.init({ projectId: 'CS-P-XXXXXX' });
ChainBridge.on('connect', function (s) {
  console.log(s.address, s.chainId, s.sessionNo);
});

Build the browser example on this page into your app and wire it to the connect button. Save the server example below as server.mjs and start it with the key, platform URL and app origin configured. The example only exposes its own endpoints; your app must forward them on the same origin. In production use HTTPS, shared persistent session storage, and keep the challenge binding and origin checks.

Run the server example locally
export CS_API_KEY='your server-side billing key'
export CS_BASE_URL='https://your-chainbridge-domain'
export APP_ORIGIN='http://localhost:3000'
node --experimental-strip-types server.mjs

Code examples

The browser gets its challenge from a same-origin server and the metered key stays on the server. The app paths in the examples below belong to your app, not to the platform API. The SDK shapes session data into fields such as sessionId, nonce and message; verification must use the same sessionId.

connect.js — browser connection and signing
// This example is handled by the browser bundler; never create a billing-key client in the browser.
async function appJson(path, body, request) {
  const response = await request(path, {
    method: 'POST', credentials: 'same-origin',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(body)
  });
  const payload = await response.json();
  if (!response.ok || payload.code !== 1) {
    const error = new Error(payload.message || 'sign-in request did not succeed, please try again');
    error.fromApp = true;
    throw error;
  }
  return payload.data;
}

export async function signInWithProvider({ ethereum = window.ethereum, request = fetch } = {}) {
  if (!ethereum) throw new Error('no wallet detected; install a wallet or choose QR sign-in');
  try {
    const accounts = await ethereum.request({ method: 'eth_requestAccounts' });
    const address = accounts[0];
    if (!/^0x[0-9a-fA-F]{40}$/.test(address || '')) throw new Error('invalid wallet account');
    const chain = await ethereum.request({ method: 'eth_chainId' });
    if (Number(chain) !== 1) {
      const error = new Error('switch the wallet to Ethereum mainnet, then connect again');
      error.fromApp = true;
      throw error;
    }
    const challenge = await appJson('/api/connect/session', { address }, request);
    // use the message exactly as issued; never rebuild the domain, nonce or expiry yourself.
    const bytes = new TextEncoder().encode(challenge.message);
    const hex = '0x' + Array.from(bytes, b => b.toString(16).padStart(2, '0')).join('');
    const signature = await ethereum.request({ method: 'personal_sign', params: [hex, address] });
    return await appJson('/api/connect/verify', {
      sessionId: challenge.sessionId, nonce: challenge.nonce,
      message: challenge.message, address, signature
    }, request);
  } catch (error) {
    if (error.code === 4001) throw new Error('the user cancelled the wallet connection or signature; please start again');
    if (error.fromApp) throw error;
    throw new Error('wallet connection or signature failed; check the wallet prompt and your network, then retry');
  }
}
// call this from your connect button handler: await signInWithProvider().

Session API

MethodPathDescriptionAuthentication
POST/api/v1/connect/sessionCreate a connection session — returns nonce, domain, chain, and expiryServer key
GET/api/v1/connect/session/:idGet session status (pending / authenticated / revoked / expired)Server key
POST/api/v1/connect/siwe/verifyVerify a SIWE / SIWX signature and establish a sessionServer key
POST/api/v1/connect/session/:id/revokeRevoke a platform session. The app should also clear its own sign-in state.Server key
GET/api/v1/connect/analyticsConnection analytics (success rate, latency, wallet distribution)Server key

SIWE verification checklist

ChainBridge Connect checks each item below independently. Any mismatch is rejected with a clear reason.

Domain
Must match the domain the challenge was created for. Pin the trusted domain server-side and never trust the browser.
Origin
Your server checks the request origin and pins the challenge URI. The signed message must match the text ChainBridge stored.
Chain ID
Must equal the chain declared at session creation. Cross-chain replay is rejected.
nonce
Single use — invalidated the moment verification succeeds. Reuse returns 400707.
expiry
The nonce lasts 10 minutes by default (expired: 400708). Sessions last 24 hours (expired: 400702). Always trust the create response.
Signature
Recover the signer address under EIP-191 / EIP-4361 and compare it byte for byte with the claimed address

Common error codes

Error codesMeaningWhat to do
400704 / 400705 / 400706Domain, origin, or chain mismatchUse the configured app origin and the original message from this attempt
400707 / 400708Nonce already used or expiredCreate a new challenge; never replay an old signature
400709Signature verification failedConfirm the signer address matches the message. Never send a private key.
400701 / 400702 / 400703Session missing, expired, or revokedCreate a new connection and clear your app's own sign-in state
400013Rate limit exceededWait for the interval in the rate-limit response. Don't resend the signature automatically.
400007Insufficient permissionsCheck that the server key has Connect product permissions
500001 / 500002 / 500006Internal or upstream service errorKeep the request ID and contact support
FAQ

Integration details

No.cs_live_xxx form keys are account credentials and belong on your server only. QR pairing uses a public WalletConnect project ID. Every metered API call is made by your server and bound to the original challenge for the current app session.

Yes. The SDK's connect and sign steps rely only on the browser wallet object and run after client hydration. The server just creates sessions and verifies signatures — it needs no browser API.

If SDK initialization fails it returns a clear error. Your app can then show a specific message and keep a fallback connect flow.

WalletConnect pairing times out after 120 seconds by default and can be raised to 300. Pairing is timed separately from the server nonce lifetime. Nonces last 10 minutes and platform sessions 24 hours today — trust the create response. A used nonce returns 400707, an expired one 400708.

Search the SDK

Can't find the endpoint you need?

Search endpoints, error codes, and setup steps by keyword.

Ready to integrate?

Create a project and API key in the console, then run one end-to-end test.