@botparty/nextjs
Next.js SDK for BotParty auth — middleware, server auth(), auto route handlers, and SSR provider. Clerk-like DX for BotParty identity and payments.
Quick Start
npx @botparty/nextjs init
This interactive command will:
- Scaffold a Next.js project (if run in an empty directory) with a demo landing page, authenticated dashboard, and sample API routes
- Generate an ES256 keypair for client authentication and service JWT signing
- Register your domain with id.botparty.club via DNS TXT verification (sends the public key to the server)
- Write all env vars to
.env
- Create middleware and the catch-all route handler
Options:
npx @botparty/nextjs init --domain example.com # skip domain prompt
npx @botparty/nextjs init --force # re-register and regenerate
npx @botparty/nextjs init --jwks # host /.well-known/jwks.json instead of registering inline key
Manual Install
npm install @botparty/nextjs
Environment Variables
All set automatically by npx @botparty/nextjs init:
BOTPARTY_AUTH_URL=https://id.botparty.club # defaults to this if omitted
BOTPARTY_CLIENT_ID=bp_xxx
BOTPARTY_CLIENT_ASSERTION_KEY=<ES256 PEM private key> # signs client assertions + service JWTs
BOTPARTY_DOMAIN=example.com # your verified domain (optional, defaults to VERCEL_PROJECT_PRODUCTION_URL)
The single BOTPARTY_CLIENT_ASSERTION_KEY does double duty:
- OAuth token exchange: signs
client_assertion JWTs (RFC 7523 private_key_jwt)
- Payment gateway: signs
X-BotParty-Service JWTs
- Session cookies: AES encryption key derived from
SHA-256("bp-session-key:" + key)
Setup (3 files)
1. Route Handler
export { GET, POST } from '@botparty/nextjs/handlers';
Handles /login, /callback, /me, /sign-out, /wallet, /ledger automatically.
2. Middleware
import { botpartyMiddleware, createRouteMatcher } from '@botparty/nextjs/server';
const isPublic = createRouteMatcher(['/api/public(.*)', '/pricing', '/']);
export default botpartyMiddleware((auth, req) => {
if (!isPublic(req)) auth.protect();
});
export const config = { matcher: ['/((?!_next|.*\\..*).*)'] };
3. Provider
import { BotPartyProvider } from '@botparty/nextjs';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html>
<body>
<BotPartyProvider>{children}</BotPartyProvider>
</body>
</html>
);
}
The provider is an async Server Component — it reads the session server-side and hydrates the client with zero waterfall.
Server Auth
Route Handlers & Server Components
import { auth } from '@botparty/nextjs/server';
export async function GET() {
const session = await auth();
if (!session.isAuthenticated) {
return new Response('Unauthorized', { status: 401 });
}
session.userId;
session.email;
session.name;
session.picture;
session.namespaceId;
session.type;
session.hasLinkedUser;
session.getToken();
session.protect();
session.redirectToSignIn();
}
Middleware Auth Object
Inside botpartyMiddleware, the auth callback receives:
interface MiddlewareAuthObject {
isAuthenticated: boolean;
type: 'human' | 'bot' | null;
userId: string | null;
namespaceId: string | null;
email: string | null;
protect(): MiddlewareAuthObject;
redirectToSignIn(): never;
}
Creating Paid Endpoints
Use createPaymentGateway() to charge for API access via the x402 protocol. The gateway handles verification, payment creation, and settlement automatically.
Units: All amounts are integers in USDC atomic units (6 decimals). 1 USDC = 1,000,000 units.
Setup
import { createPaymentGateway } from '@botparty/nextjs/server';
const gateway = createPaymentGateway({ serviceName: 'My API' });
Domain and private key are read from env vars automatically (BOTPARTY_DOMAIN, BOTPARTY_CLIENT_ASSERTION_KEY). On Vercel, domain falls back to VERCEL_PROJECT_PRODUCTION_URL if BOTPARTY_DOMAIN is not set.
You can override any of these in the config object:
const gateway = createPaymentGateway({
domain: 'custom.example.com',
serviceName: 'My API',
privateKey: process.env.MY_CUSTOM_KEY!,
});
Pay-per-call
Charge a flat fee per request:
export async function POST(req: Request) {
const check = await gateway.requirePayment(req, {
amount: 10_000,
description: 'Pay-per-call API request ($0.01)',
});
if (!check.authorized) return check.response;
const result = { message: 'Paid request successful!' };
await gateway.claim(check, {
amount: 10_000,
description: 'Pay-per-call API request',
});
return Response.json(result);
}
Dynamic payment (budget + actual cost)
Request a budget upfront, bill actual cost after processing:
export async function POST(req: Request) {
const check = await gateway.requireBudget(req, {
estimated: 5_000_000,
description: 'AI inference — estimated cost ($5.00)',
});
if (!check.authorized) return check.response;
const actualCost = await doExpensiveWork();
await gateway.claim(check, {
amount: actualCost,
description: `AI inference — actual cost ($${(actualCost / 1_000_000).toFixed(6)})`,
});
return Response.json({ message: 'Done!', charged: actualCost });
}
Payment flow summary
- Caller hits endpoint
requirePayment() checks for an approved payment via the facilitator
- If not approved: returns
402 with PAYMENT-REQUIRED header and a JSON body containing a payTo link to a /humans/{flowId} multi-step approval flow
- Human visits the
payTo link, completes login + top-up + approval
- Caller retries the same request (no special headers needed)
requirePayment() finds the approved payment, returns authorized: true
- After processing,
claim() settles the payment via the facilitator
Calling Other Services
Your service has a domain identity — the ES256 key in BOTPARTY_CLIENT_ASSERTION_KEY that botparty init registered with the IdP. To call another BotParty service, use botpartyFetch, which attaches the right Authorization header. Pick a mode explicitly:
import { botpartyFetch } from '@botparty/nextjs/server';
const res = await botpartyFetch('https://peer.botparty.club/api/v1/thing', {
botpartyAuth: { as: 'domain' },
});
const res2 = await botpartyFetch('https://peer.botparty.club/api/v1/thing', {
botpartyAuth: { as: 'user' },
});
const res3 = await botpartyFetch('https://peer.botparty.club/api/v1/thing', {
botpartyAuth: { as: 'apiKey' },
});
How the peer verifies it: the receiving service's auth() resolves the Authorization: Bearer token — a domain JWT is verified against the issuer's IdP namespace JWKS (no shared secret, no extra hosting), a user access token against the IdP, and a bpk_ key via introspection.
Lower-level helpers are also exported: signDomainToken(opts) returns just the JWT, and botpartyAuthHeaders(mode, targetUrl?) returns just the { Authorization } header for use with non-fetch clients (axios, the AI SDK provider config, etc.).
LLM inference is the exception. llm.botparty.club/v1/* routes straight to LiteLLM, which needs an sk- virtual key — not a domain JWT. Mint one once with npx @botparty/nextjs add-service llm (it authenticates to the management API with your domain identity and writes LLM_API_KEY to .env). See docs/SERVICE-TO-SERVICE.md.
Client Components
All hooks and components from @botparty/react are re-exported:
import {
useAuth, useUser, useWallet, useLedger,
SignedIn, SignedOut, HasLinkedUser,
UserButton, NamespaceBadge,
WalletBalance, TransactionList, TopUpButton, SpendingControls,
} from '@botparty/nextjs';
Example Page
import { SignedIn, SignedOut, UserButton, WalletBalance } from '@botparty/nextjs';
export default function Dashboard() {
return (
<div>
<SignedIn>
<UserButton />
<WalletBalance />
</SignedIn>
<SignedOut>
<a href="/api/botparty/auth/login">Sign in</a>
</SignedOut>
</div>
);
}
Session Strategy
- Fast path: Encrypted cookies (
__botparty_session 15min, __botparty_refresh 30d) encrypted with key derived from BOTPARTY_CLIENT_ASSERTION_KEY
- Bearer tokens: ES256 access tokens verified against
id.botparty.club/.well-known/jwks.json
- Namespace JWTs: Verified against per-namespace JWKS endpoints
- Silent refresh: Middleware auto-refreshes expired session cookies from the refresh token
Demo Project
When you run npx @botparty/nextjs init in an empty directory, it scaffolds a complete demo with:
- Landing page (
/) -- sign in button, feature cards
- Dashboard (
/dashboard) -- protected route showing all SDK components:
<UserButton>, <NamespaceBadge>, <WalletBalance>, <TransactionList>
<TopUpButton>, <SpendingControls>
- API tester panel with buttons to call each sample route
- Terminal commands for testing with
botparty curl
- Sample API routes:
GET /api/bots/open -- accepts any authenticated bot
GET /api/bots/user-required -- requires namespace linked to human account
POST /api/bots/pay-per-call -- $0.10/call with payment authorization
POST /api/bots/dynamic-payment -- $5 authorization, $0.20/call
Exports
@botparty/nextjs | BotPartyProvider, all React hooks + components |
@botparty/nextjs/server | auth(), currentUser(), botpartyMiddleware, createRouteMatcher, session utils, botpartyFetch, botpartyAuthHeaders, signDomainToken |
@botparty/nextjs/handlers | GET, POST catch-all route handlers |