Documentation

Frameworks & Languages

The SDK is TypeScript/JavaScript because it ships the CLI and web widgets. Duct itself is language-agnostic: your backend and agents talk to it over HTTP.

The rule of thumb

Use the SDK when you are building a JavaScript or TypeScript web app. Use REST when you are building in Python, Go, Ruby, Java, PHP, .NET, shell scripts, or an agent runtime.

Supported Integration Styles

Next.js / React
Use @duct-sdk/sdk/next (or /react) for the widget and token helpers. Use @duct-sdk/sdk/server in API routes.
Vite + Express
Use @duct-sdk/sdk/vite for the frontend widget. Use @duct-sdk/sdk/server in the Express backend.
Remix
Use @duct-sdk/sdk/remix for the widget. Use @duct-sdk/sdk/server in loaders and action handlers.
SvelteKit
Use @duct-sdk/sdk/sveltekit. Server hooks use @duct-sdk/sdk/server.
Plain JavaScript
Embed the iframe and implement the postMessage token bridge manually.
Python
Call /v1/shell-token and /v1/shells/:id/invoke with httpx, requests, FastAPI, Django, or any HTTP client.
Go / Ruby / Java / PHP / .NET
Same REST API. You provide token issuance and endpoint auth in your stack.
CLI / scripts
Use curl for token generation, action invocation, smoke tests, or CI checks.

JavaScript REST Example

js
const auth = await fetch('https://auth.ductai.vercel.app/v1/shell-token', {

Python REST Example

python
import os

curl Example

bash
TOKEN=$(curl -s -X POST https://auth.ductai.vercel.app/v1/shell-token \

Vite + Express Guide

Vite serves the frontend; Express (or any Node.js server) handles the backend. They are separate processes with separate environment files. Keep secrets out of Vite.

Environment layout

bash
# /.env  (or /backend/.env) — loaded by Express, never bundled by Vite
DUCT_SECRET_KEY=sk_duct_...
DUCT_SHELL_ID=shell_acme_prod

# /frontend/.env — public vars, safe to expose in the browser bundle
VITE_DUCT_SHELL_ID=shell_acme_prod
VITE_DUCT_SHELL_HOST=https://shell.ductai.vercel.app

Never put DUCT_SECRET_KEY in a VITE_* var

Vite inlines all VITE_* variables into the browser bundle. Your signing secret must live only in the Express process environment, not the Vite build.

Express token route

ts
import express from 'express';

Express auth middleware — Duct delegated token fallback

ts
import { verifyDuctToken } from '@duct-sdk/sdk/server';

Express webhook endpoint (optional)

Webhook payloads are HMAC-SHA256 signed. Verify before trusting the body. Webhooks require raw body access — mount the express.raw() parser on this route, not express.json().

ts
import crypto from 'crypto';

Webhooks are configured in the dashboard

Webhook URLs (deeplink callback, event stream) and the signing secret are not part of duct.config.ts and are not pushed via duct push. Configure them in the Duct dashboard → Shell → Settings → Webhooks. They are optional for the core shell + widget + action flow.

Vite frontend embed

tsx
import { DuctShell } from '@duct-sdk/sdk/vite';

If your language can make HTTPS requests, it can call Duct. The typed SDK is a convenience layer, not a platform requirement.