Skip to content
You're offline. Some features may be unavailable.
QPortal is live. Deploy QR-powered AI instantly.

SDKs

TypeScript / JS SDK

The official 3QPR JavaScript/TypeScript client. Works in Node.js 18+ and modern browsers.

Installation

npm install @3qpr/sdk
# or
yarn add @3qpr/sdk
# or
pnpm add @3qpr/sdk

Initialize

client.tstypescript
import { ThreeQPR } from "@3qpr/sdk";

const client = new ThreeQPR({
  apiKey: process.env.THREEQPR_API_KEY!,
});

Create a QPR Code

const code = await client.qprCodes.create({
  name: "Event Networking Badge",
  prompt:
    "You are a professional networking assistant at TechConf 2026. " +
    "Help attendees connect with each other, find sessions, and exchange contact info.",
  template: "events",
  welcomeMessage: "Hi! Tap to exchange info or find what's on next.",
});

console.log(code.scanUrl);      // https://3qpr.com/s/ev8n2q
console.log(code.qrImageUrl);   // https://api.3qpr.com/qr/ev8n2q.png

List QPR Codes

const { codes, total } = await client.qprCodes.list({ limit: 20 });
codes.forEach((c) => console.log(`${c.name}: ${c.scansTotal} scans`));

Fetch analytics

const analytics = await client.analytics.get({
  qprCodeId: "qpr_01HXYZ789ABC",
  period: "7d",
});
console.log(`${analytics.totalScans} scans in the last 7 days`);

Webhooks — Next.js App Router

app/api/webhooks/3qpr/route.tstypescript
import { NextRequest, NextResponse } from "next/server";
import { verifyWebhookSignature, ThreeQPRWebhookEvent } from "@3qpr/sdk";

const WEBHOOK_SECRET = process.env.THREEQPR_WEBHOOK_SECRET!;

export async function POST(req: NextRequest) {
  const body = await req.arrayBuffer();
  const signature = req.headers.get("x-3qpr-signature") ?? "";

  let event: ThreeQPRWebhookEvent;
  try {
    event = verifyWebhookSignature(Buffer.from(body), signature, WEBHOOK_SECRET);
  } catch {
    return NextResponse.json({ error: "Invalid signature" }, { status: 400 });
  }

  switch (event.event) {
    case "scan.created":
      console.log("New scan:", event.data.shortId);
      break;
    case "conversation.completed":
      console.log("Conversation ended, turns:", event.data.turnCount);
      break;
  }

  return NextResponse.json({ received: true });
}

Error handling

import { ThreeQPRError, RateLimitError, AuthError } from "@3qpr/sdk";

try {
  const code = await client.qprCodes.create({ name: "Test", prompt: "..." });
} catch (err) {
  if (err instanceof AuthError) {
    console.error("Invalid API key");
  } else if (err instanceof RateLimitError) {
    console.error(`Rate limited. Retry in ${err.retryAfter}s`);
  } else if (err instanceof ThreeQPRError) {
    console.error(`API error ${err.statusCode}: ${err.message}`);
  }
}