Skip to main content
Bondify ships two official JS/TS packages. Both include full TypeScript definitions — no separate @types/ package needed. Current versions: @bondify/node 3.0.2, @bondify/react 3.0.1 (Node ≥ 18; React 18/19; Next.js 14–16).
Upgrading from 1.x or 2.x? Version 3.0.0 has breaking changes: verifyProof() is now async, and its returned fields are camelCase instead of snake_case. See SDK 3.0.0 in the changelog for the full migration guide. 1.x is deprecated and unsupported — upgrade straight to 3.x.

@bondify/react

<BondifyProvider config={…}>

Wrap your app once. config is a BondifyConfig:
string
required
Your project ID (proj_…). Public.
string
default:"https://api.bondify.dev"
Override the API base URL.
'redirect' | 'inline'
default:"'redirect'"
redirect opens the Telegram deep link in a new tab on startAuth. inline leaves opening the deep link to you (e.g. render a QR with <BondifyQR>).
number
default:"1500"
Status poll interval, in milliseconds.
number
default:"120000"
How long the client polls before giving up (POLLING_TIMEOUT), in milliseconds.
(user: BondifyUser) => void
Called when the user confirms.
(error: BondifyError) => void
Called on failure.
() => void
Called when the user cancels in Telegram.

Hooks

Components

<BondifyButton>label?, theme?: 'telegram' | 'dark' | 'light' | 'custom', size?: 'sm' | 'md' | 'lg', showIcon?: boolean, className?. Plus standard <button> attributes. Success/error/cancel are handled by the provider’s config callbacks. <BondifyModal>open?, onOpenChange?, title?, description?, className?. A dialog that runs the flow with a QR + button. <BondifyQR>size? (default 200), showLink?, className?. Renders a QR for the current session’s deep link.

Types

Server helpers — @bondify/react/server

Next.js App Router only. getServerUser and requireAuth read the JWT secret from an explicit jwtSecret argument first; if omitted, they fall back to environment variables in this order: BONDIFY_WEBHOOK_SECRETBONDIFY_JWT_SECRETSERVER_SECRET. Use BONDIFY_WEBHOOK_SECRET unless you already have one of the other two set for another purpose in your project.
This subpath is server-only, enforced at build time, not just by convention. As of v3.0.0, @bondify/react/server imports the server-only package, so calling any of these exports from a file marked 'use client' (or anything only reachable from one) fails the build immediately with a clear message. If you need one of these functions in response to a client event (e.g. after <BondifyButton onSuccess>), don’t call it directly — wrap it in its own Server Action module and call that module from the Client Component instead. This was previously just a code comment, and the most common report of these helpers “not working” was actually this import-location mistake, surfacing as a confusing runtime error from next/headers instead of a clear build-time one.
See the Next.js guide for usage.

@bondify/node

new BondifyServer(config)

string
required
Your project’s webhook secret (whsec_…). Verifies the proof JWT.
string
default:"= jwtSecret"
Secret used to verify webhook signatures. It’s the same whsec_…, so you can omit it.
string
default:"https://api.bondify.dev"
Methods
verifyProof / safeVerifyProof are async even though verification is fully local (no network call is made) — this matches the convention used by other auth SDKs (Clerk, NextAuth, Passport, …), so await and .then() both behave as expected. verifyWebhook / safeVerifyWebhook remain synchronous.
Proofs expire 5 minutes after issuance. The JWT’s exp claim is set 5 minutes after the user confirms in Telegram. Verify a proof promptly after receiving it — a late one (slow network, a user idling on a confirmation screen, etc.) throws BondifyVerificationError with code TOKEN_EXPIRED. Handle that case explicitly rather than treating it the same as an invalid signature:
BondifyUser (returned by verifyProof) is camelCase — the same shape @bondify/react returns on the client. WebhookEvent (from verifyWebhook) stays snake_case, since it mirrors the raw JSON Bondify sends over the wire for webhook deliveries — a deliberate, separate convention from the SDK’s own ergonomic surface. The old snake_case type name BondifyProofPayload is kept as a deprecated alias for BondifyUser so existing type-only imports keep compiling.

Middleware — @bondify/node/middleware

  • createBondifyMiddleware(server, options?) → Express RequestHandler. Reads the proof from Authorization: Bearer …, a custom getter, or the bondify_proof cookie, verifies it (awaits verifyProof internally), and sets req.bondifyUser. Options: cookieName, headerName, tokenGetter, onUnauthorized.
The cookie fallback reads req.cookies, which Express only populates if you’ve applied the cookie-parser middleware before this one (app.use(cookieParser())). Without it, req.cookies is undefined and cookie-based auth silently falls through to a 401 — if you’re only using the Authorization: Bearer … header, you don’t need it.
  • verifyNextRequest(server, request, cookieName?)Promise<BondifyUser | null>. Async — always await it. For Next.js App Router Route Handlers. Reads the proof from the Authorization: Bearer … header first, then falls back to the bondify_proof cookie (or the custom cookieName you pass); never throws — a missing header/cookie, invalid signature, or expired proof (5-minute lifetime) all resolve to null, which you should treat as “unauthorized”. It’s a thin wrapper around safeVerifyProof, so it doesn’t distinguish why verification failed — call verifyProof directly if you need that.

Webhooks — @bondify/node/webhooks

Both verify the HMAC signature automatically and dispatch to your handlers:
See the Webhooks guide.

Admin client

The admin client wraps the developer REST API — see the REST API reference.

Errors