Node SDK
API reference for @temps-sdk/node-sdk. This package provides a typed API client for the entire Temps platform and a Sentry-compatible error tracking client for server-side Node.js applications.
Installation
npm install @temps-sdk/node-sdk
Requirements: Node.js 18+ or Bun. TypeScript 5+ (peer dependency).
API client
The API client provides typed access to every Temps API endpoint.
import { TempsClient } from '@temps-sdk/node-sdk';
const temps = new TempsClient({
baseUrl: 'https://your-instance.temps.dev',
apiKey: 'your-api-key',
});
// List projects
const { data: projects } = await temps.projects.list();
// Trigger a deployment
await temps.deployments.deploy({
path: { project_id: 1 },
body: { branch: 'main' },
});
// Rollback
await temps.deployments.rollback({
path: { project_id: 1, deployment_id: 5 },
});
Constructor options
- Name
baseUrl- Type
- string
- Description
Your Temps instance URL (e.g.
https://your-instance.temps.dev). Required.
- Name
apiKey- Type
- string
- Description
API key for authentication. Required.
Raw client access
For advanced use cases or endpoints not covered by namespaces:
const client = temps.rawClient;
Client namespaces
The client organizes all platform operations into 24 typed namespaces:
| Namespace | Description |
|---|---|
temps.apiKeys | API key CRUD, activate/deactivate |
temps.analytics | Visitors, sessions, events, enrichment, stats |
temps.auditLogs | Audit log retrieval |
temps.authentication | Login, logout, magic links, MFA, password reset |
temps.backups | Backup schedules, S3 sources, run/restore |
temps.crons | Cron jobs and execution history |
temps.deployments | Deploy, cancel, pause, resume, rollback, teardown, logs |
temps.dns | DNS providers, managed domains, zone listing |
temps.domains | SSL/TLS domains, ACME provisioning |
temps.email | Email providers, domains, send, stats |
temps.externalServices | PostgreSQL, Redis, S3 lifecycle, env vars |
temps.files | File retrieval by ID |
temps.funnels | Funnel CRUD, metrics, previews |
temps.git | GitHub/GitLab providers, repo connections, sync |
temps.loadBalancer | Route management |
temps.monitoring | Monitors, incidents, uptime, status buckets |
temps.notifications | Preferences, providers (email, Slack, webhook) |
temps.performance | Web Vitals metrics |
temps.platform | Instance info, IPs, geolocation, presets |
temps.projects | Full project lifecycle: environments, domains, env vars, containers, analytics, errors, session replay, webhooks |
temps.proxyLogs | Proxy log queries |
temps.repositories | Synced repos, branches, tags, presets |
temps.sessionReplay | Session init, events, deletion |
temps.settings | Platform settings |
temps.users | User CRUD, MFA, roles |
All request/response types are auto-generated from the OpenAPI spec:
import type {
ProjectResponse,
DeploymentResponse,
CreateProjectRequest,
} from '@temps-sdk/node-sdk';
Error tracking
A Sentry-compatible error tracking client. Initialize it once at application startup.
import { ErrorTracking } from '@temps-sdk/node-sdk';
ErrorTracking.init({
dsn: 'https://public-key@your-instance.temps.dev/1',
environment: 'production',
release: '1.0.0',
});
The DSN follows the Sentry format: https://<public-key>@<host>/<project-id>. Find it in your project's Error Tracking > DSN & Setup tab.
ErrorTracking.init options
- Name
dsn- Type
- string
- Description
The Data Source Name. Required.
- Name
environment- Type
- string
- Description
Environment name (e.g.
production,staging).
- Name
release- Type
- string
- Description
Your application version.
- Name
serverName- Type
- string
- Description
Server identifier for distinguishing instances.
- Name
sampleRate- Type
- number
- Description
Error sampling rate (0.0 to 1.0).
- Name
tracesSampleRate- Type
- number
- Description
Performance trace sampling rate (0.0 to 1.0).
- Name
ignoreErrors- Type
- (string | RegExp)[]
- Description
Errors matching these patterns are silently dropped.
- Name
beforeSend- Type
- (event) => event | null
- Description
Modify or drop events before sending. Return
nullto drop.
- Name
maxBreadcrumbs- Type
- number
- Description
Maximum breadcrumbs to retain.
- Name
attachStacktrace- Type
- boolean
- Description
Attach stack traces to message events.
- Name
debug- Type
- boolean
- Description
Log events to console instead of sending. Useful for development.
- Name
integrations- Type
- Integration[]
- Description
Custom integrations (each must implement
setupOnce()).
Capturing errors
// Capture an exception
try {
riskyOperation();
} catch (error) {
const eventId = ErrorTracking.captureException(error);
}
// Capture with extra context
ErrorTracking.captureException(error, {
tags: { subsystem: 'payments' },
extra: { orderId: '12345', amount: 99.99 },
level: 'fatal',
});
// Capture a message
ErrorTracking.captureMessage('Disk usage above 90%', 'warning');
// Capture a raw event
ErrorTracking.captureEvent({
message: 'Custom event',
level: 'info',
tags: { source: 'cron' },
});
Global handlers
The SDK automatically captures unhandled errors:
| Handler | Level | Behavior |
|---|---|---|
process.on('uncaughtException') | fatal | Captured, then process.exit(1) |
process.on('unhandledRejection') | error | Captured, process continues |
Both are tagged with handled: false.
Context and scope
Enrich error reports with user information, tags, and structured data.
// Set the current user (attached to all subsequent events)
ErrorTracking.setUser({
id: '123',
email: 'alice@example.com',
username: 'alice',
ip_address: '{{auto}}',
});
// Set global tags
ErrorTracking.setTag('region', 'eu-west-1');
ErrorTracking.setTags({ service: 'api', version: '2.0' });
// Set extra data
ErrorTracking.setExtra('requestId', 'abc-123');
ErrorTracking.setExtras({ query: 'SELECT ...', duration: 150 });
// Set structured context
ErrorTracking.setContext('order', {
id: 'order-456',
total: 99.99,
items: 3,
});
// Clear user on logout
ErrorTracking.setUser(null);
Scoped context
// Permanent scope modification
ErrorTracking.configureScope((scope) => {
scope.setTag('transaction', 'checkout');
scope.setUser({ id: '123' });
});
// Temporary scope (discarded after callback)
ErrorTracking.withScope((scope) => {
scope.setTag('component', 'payment-form');
ErrorTracking.captureMessage('Payment processed');
});
Breadcrumbs
Leave a trail of events leading up to an error.
ErrorTracking.addBreadcrumb({
category: 'auth',
message: 'User logged in',
level: 'info',
data: { method: 'oauth' },
});
ErrorTracking.addBreadcrumb({
category: 'http',
message: 'GET /api/users',
level: 'info',
type: 'http',
data: { status: 200, duration: 45 },
});
// Clear all breadcrumbs
ErrorTracking.clearBreadcrumbs();
Breadcrumb properties
- Name
category- Type
- string
- Description
Grouping category (e.g.
auth,http,db).
- Name
message- Type
- string
- Description
Human-readable description.
- Name
type- Type
- string
- Description
One of:
default,http,navigation,console.
- Name
level- Type
- string
- Description
One of:
debug,info,warning,error,critical.
- Name
data- Type
- Record<string, any>
- Description
Arbitrary structured data.
Performance monitoring
Track transactions and spans to measure latency.
const transaction = ErrorTracking.startTransaction({
name: 'POST /api/checkout',
op: 'http.server',
});
const dbSpan = transaction.startChild({
op: 'db.query',
description: 'SELECT * FROM orders WHERE id = ?',
});
// ... query ...
dbSpan.finish();
transaction.setMeasurement('order_total', 99.99, 'usd');
transaction.setStatus('ok');
transaction.finish();
Spans capture startTimestamp, endTimestamp, op, description, status, tags, and data. Spans can be nested.
User feedback
Collect feedback after an error:
const eventId = ErrorTracking.captureException(error);
ErrorTracking.captureUserFeedback({
event_id: eventId,
name: 'Alice',
email: 'alice@example.com',
comments: 'The checkout button did nothing.',
});
Lifecycle
// Flush pending events (waits up to 2s by default)
await ErrorTracking.flush(2000);
// Close the client (disables further capturing + flushes)
await ErrorTracking.close(2000);
Enriching visitors
Attach backend context — user identity, subscription tier, custom tags — to a visitor record after they authenticate. This links the anonymous pre-login session to the known user.
Getting the visitor ID from the frontend
import { useAnalytics } from '@temps-sdk/react-analytics';
function UserProfile({ user }) {
const analytics = useAnalytics();
useEffect(() => {
const visitorId = analytics.getVisitorId();
if (visitorId && user) {
fetch('/api/enrich-visitor', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ visitorId, userId: user.id, email: user.email }),
});
}
}, [user, analytics]);
}
The visitor ID can be a GUID string ("550e8400-...") or a numeric ID.
Enriching from the backend
import { TempsClient } from '@temps-sdk/node-sdk';
const client = new TempsClient({
baseUrl: process.env.TEMPS_API_URL,
apiKey: process.env.TEMPS_API_KEY,
});
await client.analytics.enrichVisitor({
path: { visitor_id: visitorId },
query: { project_id: Number(process.env.TEMPS_PROJECT_ID) },
body: {
custom_data: {
userId: user.id,
email: user.email,
subscriptionTier: user.subscription?.tier ?? 'free',
signupDate: user.createdAt.toISOString(),
},
},
});
// Returns: { success: true, visitor_id: string, message: string }
Next.js API route example
// app/api/enrich-visitor/route.ts
import { TempsClient } from '@temps-sdk/node-sdk';
const client = new TempsClient({
baseUrl: process.env.TEMPS_API_URL!,
apiKey: process.env.TEMPS_API_KEY!,
});
export async function POST(req: Request) {
const { visitorId, userId, email } = await req.json();
const user = await db.users.findUnique({ where: { id: userId } });
await client.analytics.enrichVisitor({
path: { visitor_id: visitorId },
query: { project_id: Number(process.env.TEMPS_PROJECT_ID) },
body: {
custom_data: {
userId: user.id,
email: user.email,
subscriptionTier: user.subscription?.tier ?? 'free',
},
},
});
return Response.json({ success: true });
}
Querying enriched visitors
// By GUID
const visitor = await client.analytics.getVisitorByGuid({
path: { visitor_id: '550e8400-e29b-41d4-a716-446655440000' },
query: { project_id: 1 },
});
// By numeric ID
const visitor = await client.analytics.getVisitorById({
path: { id: 123 },
query: { project_id: 1 },
});
console.log(visitor.custom_data);
// { userId: '123', email: 'user@example.com', subscriptionTier: 'pro' }
Call flush() or close() before process exit to ensure all events are sent.
Feature flags
Read feature flags created in the Temps console from any service you deploy on Temps. TEMPS_API_URL and TEMPS_API_TOKEN are injected into every deployment and the token pins the project (and usually the environment), so flags.init() needs no configuration on Temps itself.
import { flags } from '@temps-sdk/node-sdk';
await flags.init();
if (flags.get('checkout.v2', { key: user.id }, false)) {
// ...
}
get() is synchronous and does zero network I/O per call: the whole environment's flag set is loaded into memory once and kept fresh by a background poll, so a per-check HTTP round trip never sits in a request handler's hot path. The third argument is the fallback — returned whenever the flag is unknown, the snapshot hasn't loaded yet, or the control plane is unreachable. flags.ready and flags.lastError are exposed so an unreachable flag service is a visible condition, not a silent one.
Locally, without TEMPS_API_URL/TEMPS_API_TOKEN set, every read returns its fallback — this is expected, not a degraded state.
Flag refresh interval
The background poll that keeps the in-memory flag snapshot fresh runs every 30 seconds by default. A flag flipped in the console reaches an already-running process on its next poll — up to 30s later, not instantly. This is deliberate: it keeps reads free of network I/O, at the cost of that window.
Override it either way:
import { FlagsClient } from '@temps-sdk/node-sdk';
const flags = new FlagsClient({ refreshIntervalMs: 5_000 });
await flags.init();
TEMPS_FLAGS_REFRESH_INTERVAL_MS is the one to reach for on a Temps deployment — set it as an environment variable on the project/environment and the default flags singleton picks it up with no redeploy of application code. A non-numeric or negative value is ignored (falls back to 30s) and logged via console.warn, rather than silently accepted.
Unchanged flags cost a 304 Not Modified, not a payload, so tightening this interval is cheap even at a low value. Setting it to 0 disables the background poll entirely — reads keep serving whatever snapshot was loaded at init().