BFF Pattern
Torque business API keys (sk_live_…) authorize READ and DECIDE. They must never ship in browser bundles. The standard integrator pattern is a backend-for-frontend (BFF): your server holds the key and exposes same-origin routes your UI calls.
Architecture
/api/torque/** or similar)TORQUE_API_KEY via torque-nodeSmart wallet JWTs are different: they belong to the signed-in end user and are required for EXECUTE (POST /execute/**). Do not mix JWT and business key on the same public route without explicit auth on your BFF.
When You Need a BFF
| Surface | Credential | BFF? |
|---|---|---|
| Intelligence feed, views, datasets, markets | sk_live_… | Required for browser UI |
| Assistant chat | sk_live_… | Required for browser UI |
| Actions — merchant channel | sk_live_… + Business ID | Required — use torque-checkout on server |
| Actions — on_chain | Smart wallet JWT | Only if user session exists; no partner JWT mint API |
| Capabilities / OpenAPI probe | None | Optional direct call from server |
Environment
TORQUE_API_KEY=sk_live_…
TORQUE_BASE_URL=https://app.torque.fi/api/v1 # optionalimport { createTorqueFromEnv } from 'torque-node'
export async function getTorque() {
return createTorqueFromEnv()
}Next.js Route Handlers
Canonical READ examples. Legacy alias paths still work if you have not upgraded SDK yet.
import { createTorqueFromEnv } from 'torque-node'
import { NextRequest, NextResponse } from 'next/server'
export async function GET(req: NextRequest) {
const { searchParams } = req.nextUrl
const torque = createTorqueFromEnv()
const feed = await torque.read.intelligence.getFeed({
walletAddress: searchParams.get('walletAddress') ?? undefined,
chainId: Number(searchParams.get('chainId') ?? 8453),
includeBrief: searchParams.get('includeBrief') === '1' ? 1 : undefined,
})
return NextResponse.json(feed)
}import { createTorqueFromEnv } from 'torque-node'
import { NextRequest, NextResponse } from 'next/server'
export async function GET(
req: NextRequest,
{ params }: { params: Promise<{ id: string }> },
) {
const { id } = await params
const days = req.nextUrl.searchParams.get('days')
const torque = createTorqueFromEnv()
const data = await torque.read.intelligence.getDataset(id, days ? { days: Number(days) } : undefined)
return NextResponse.json(data)
}import { createTorqueFromEnv } from 'torque-node'
import { NextRequest, NextResponse } from 'next/server'
export async function POST(req: NextRequest) {
const body = await req.json()
const torque = createTorqueFromEnv()
const reply = await torque.decide.assistant.chat(body)
return NextResponse.json(reply)
}Pair With @torquefi/react
Default hook routes match the examples above. Override paths if your BFF lives elsewhere.
'use client'
import { useIntelligenceFeed } from '@torquefi/react/intelligence'
export function FeedPanel({ walletAddress }: { walletAddress: string }) {
const { items, isLoading } = useIntelligenceFeed({
walletAddress,
chainId: 8453,
includeBrief: 1,
// bffUrl: '/api/torque/intelligence/feed', // default
})
// ...
}Full hook reference: React SDK. There are no React hooks for Platform Data or markets yet — add BFF routes and call them from your client with SWR or React Query.
Non-Next.js Servers
Same idea on Express, Fastify, or any backend: one handler per Torque surface, instantiate createTorqueFromEnv() per request or as a singleton, return JSON to your frontend. CORS is only needed if the browser calls Torque directly — with a BFF, the browser stays same-origin.
See Also
- Authentication
- Entitlements — Pro tier for dataset routes
- Errors & Rate Limits — propagate Torque errors from your BFF