JavaScript SDK
Use PromptRails from JavaScript or TypeScript apps with typed clients for agents, prompts, traces, and scores.
Best for
Engineers building against the API, SDKs, CLI, MCP, or local tooling
The official JavaScript/TypeScript SDK for PromptRails provides a fully typed client for interacting with the PromptRails API from Node.js, Deno, or browser environments.
Use the JavaScript SDK when a web app, Node service, serverless function, or frontend-adjacent workflow needs to call PromptRails directly. You do not need it to try an agent inside the product; Studio, chat, triggers, and Agent UI deployments can run without SDK code.
For production applications, create a scoped API key, keep it server-side when possible, and inspect the resulting execution trace before exposing the workflow to users.
Installation
npm install @promptrails/sdkOr with other package managers:
yarn add @promptrails/sdk
pnpm add @promptrails/sdkSupports both ESM and CommonJS module formats.
Current release: v0.7.0 — the standalone @promptrails/sdk/tracing
entry point for sending spans to PromptRails from any code, with LangChain,
OpenAI, Anthropic, Google GenAI, and OpenTelemetry integrations. See the
changelog.
Technical detailsClient setup and resource reference
Client Initialization
import { PromptRails } from '@promptrails/sdk'
const client = new PromptRails({
apiKey: 'your-api-key',
baseUrl: 'https://api.promptrails.ai', // default
timeout: 30000, // milliseconds, default
maxRetries: 3, // default
})Configuration
| Parameter | Type | Default | Description |
|---|---|---|---|
apiKey | string | Required | PromptRails API key |
baseUrl | string | https://api.promptrails.ai | API base URL |
timeout | number | 30000 | Request timeout in milliseconds |
maxRetries | number | 3 | Maximum retry attempts |
Available Resources
| Resource | Property | Description |
|---|---|---|
| Agents | client.agents | Agent CRUD, versioning, execution |
| Prompts | client.prompts | Prompt CRUD, versioning, execution |
| Executions | client.executions | Execution listing and details |
| Credentials | client.credentials | Credential management |
| Data Sources | client.dataSources | Data source CRUD, versioning, execution |
| Chat | client.chat | Send messages to chat sessions |
| Sessions | client.sessions | Chat session management |
| Memories | client.memories | Agent memory CRUD and search |
| Traces | client.traces | Trace listing and filtering |
| Costs | client.costs | Cost analysis and summaries |
| MCP Tools | client.mcpTools | MCP tool management |
| MCP Templates | client.mcpTemplates | MCP template browsing |
| Guardrails | client.guardrails | Guardrail configuration |
| Approvals | client.approvals | Approval request management |
| Scores | client.scores | Scoring and evaluation |
| Templates | client.templates | Flow templates |
| Dashboard | client.dashboard | Agent UI deployments |
| Sessions | client.sessions | Session management |
| A2A | client.a2a | Agent-to-Agent protocol |
| LLM Models | client.llmModels | Available LLM models |
| Agent Triggers | client.agentTriggers | Agent trigger management (generic webhook, Slack, Telegram, Teams, WhatsApp, schedule) |
Common Operations
Execute an Agent
const result = await client.agents.execute('agent-id', {
input: { message: 'Hello, world!' },
metadata: { source: 'api' },
})
console.log(result.data.output)
console.log(`Cost: $${result.data.cost.toFixed(6)}`)Technical detailsMore JavaScript SDK operations
List Agents
const agents = await client.agents.list({ page: 1, limit: 20 })
for (const agent of agents.data) {
console.log(`${agent.name} (${agent.type})`)
}Create a Prompt
const prompt = await client.prompts.create({
name: 'Summarizer',
description: 'Summarizes text',
})
const version = await client.prompts.createVersion(prompt.data.id, {
systemPrompt: 'You are a concise summarizer.',
userPrompt: 'Summarize: {{ text }}',
temperature: 0.5,
message: 'Initial version',
})Chat
const session = await client.chat.createSession({
agentId: 'agent-id',
})
const response = await client.chat.sendMessage(session.id, {
content: 'What is PromptRails?',
})
console.log(response.content)Stream a Chat Turn
sendMessageStream posts a user message and yields typed
Server-Sent Events on the same HTTP connection — useful for showing the
agent's reasoning, tool calls, and token-by-token deltas in the UI.
const session = await client.chat.createSession({ agentId: 'agent-id' })
const controller = new AbortController()
for await (const event of client.chat.sendMessageStream(
session.id,
{ content: 'What is PromptRails?' },
{ signal: controller.signal },
)) {
switch (event.type) {
case 'execution':
console.log('execution_id:', event.executionId)
break
case 'thinking':
console.log('[thinking]', event.content)
break
case 'tool_start':
console.log('[tool_start]', event.name)
break
case 'tool_end':
console.log('[tool_end]', event.name, event.summary)
break
case 'content':
process.stdout.write(event.content)
break
case 'done':
console.log('\n[done]', event.tokenUsage)
break
case 'error':
console.error('[error]', event.message)
break
}
}Cancel an in-flight stream with controller.abort(). All event shapes are
exported via the StreamEvent discriminated union:
import type { StreamEvent } from '@promptrails/sdk'Stream an Existing Execution
When an execution was started outside a chat (e.g. client.agents.execute),
subscribe to its live event stream with client.executions.stream:
for await (const event of client.executions.stream(executionId)) {
if (event.type === 'content') process.stdout.write(event.content)
if (event.type === 'done') break
}Search Memories
const results = await client.memories.search({
agentId: 'agent-id',
query: 'refund policy',
limit: 5,
})Create a Score
await client.scores.create({
traceId: 'trace-id',
name: 'quality',
dataType: 'numeric',
value: 4.5,
source: 'manual',
})Approve an Execution
await client.approvals.decide('approval-id', {
decision: 'approved',
reason: 'Looks good',
})Technical detailsJavaScript SDK advanced details
Typed Agent Config
createVersion takes a typed AgentConfig — a discriminated union by
agent type. The SDK injects the type discriminator automatically, so
renames in the backend schema (e.g. prompt_version_id → prompt_id)
surface as TypeScript errors instead of silent runtime failures.
import {
SimpleAgentConfig,
ChainAgentConfig,
MultiAgentConfig,
WorkflowAgentConfig,
CompositeAgentConfig,
PromptLink,
} from '@promptrails/sdk'
// Simple agent — one prompt per execution
const simple: SimpleAgentConfig = {
type: 'simple',
prompt_id: 'prompt-id',
approval_required: false,
}
// Chain agent — prompts run sequentially, output of step N feeds step N+1
const chain: ChainAgentConfig = {
type: 'chain',
prompt_ids: [
{ prompt_id: 'p1', role: 'step1', sort_order: 0 },
{ prompt_id: 'p2', role: 'step2', sort_order: 1 },
],
}
await client.agents.createVersion('agent-id', {
version: '1.0.0',
config: simple,
set_current: true,
})Available variants: SimpleAgentConfig, ChainAgentConfig,
MultiAgentConfig, WorkflowAgentConfig, CompositeAgentConfig. Chain
and multi-agent configs use PromptLink[]; workflow uses WorkflowNode[];
composite uses CompositeStep[]. See
Agent Versioning for the per-type field
reference.
Tracing
The @promptrails/sdk/tracing entry point sends spans to PromptRails from any code, without managing your prompts or agents on the platform. It is independent of the API client and only needs an API key with the traces:write scope.
import { Tracer } from '@promptrails/sdk/tracing'
const tracer = new Tracer({ apiKey: 'pr_...' })
await tracer.span('agent-run', { kind: 'agent' }, async (root) => {
root.setInput({ q: 'weather?' })
await tracer.span('llm-call', { kind: 'llm' }, async (llm) => {
llm.setModel('gpt-4o').setUsage(120, 30)
})
})
await tracer.flush()Framework integrations
Subpath imports auto-instrument popular frameworks:
// LangChain
import { PromptRailsCallbackHandler } from '@promptrails/sdk/tracing/integrations/langchain'
await chain.invoke(inputs, { callbacks: [new PromptRailsCallbackHandler(tracer)] })
// OpenAI
import { traceOpenAI } from '@promptrails/sdk/tracing/integrations/openai'
const client = traceOpenAI(new OpenAI(), tracer)
// Anthropic
import { traceAnthropic } from '@promptrails/sdk/tracing/integrations/anthropic'
const anthropic = traceAnthropic(new Anthropic(), tracer)
// Google GenAI
import { traceGoogle } from '@promptrails/sdk/tracing/integrations/google'
const google = traceGoogle(new GoogleGenAI({ apiKey: '...' }), tracer)See the Tracing guide for span kinds, batching, and the OpenTelemetry bridge.
SDK Version
import { VERSION } from '@promptrails/sdk'
console.log(VERSION) // "0.7.0"The SDK also sends User-Agent: promptrails-js/<version> on every
request (except in browsers, where fetch ignores the header).
TypeScript Types
The SDK includes full TypeScript type definitions. All request and response types are exported:
import type {
Agent,
Prompt,
Execution,
Trace,
Score,
Credential,
ChatSession,
} from '@promptrails/sdk'Error Handling
The SDK throws typed errors for different HTTP status codes:
import {
PromptRailsError,
ValidationError,
UnauthorizedError,
ForbiddenError,
NotFoundError,
RateLimitError,
ServerError,
} from '@promptrails/sdk'
try {
const result = await client.agents.execute('invalid-id', { input: {} })
} catch (error) {
if (error instanceof NotFoundError) {
console.log(`Agent not found: ${error.message}`)
} else if (error instanceof ValidationError) {
console.log(`Invalid input: ${error.message}`)
console.log(`Details:`, error.details)
} else if (error instanceof RateLimitError) {
console.log(`Rate limited: ${error.message}`)
} else if (error instanceof UnauthorizedError) {
console.log(`Invalid API key: ${error.message}`)
} else if (error instanceof ForbiddenError) {
console.log(`Insufficient permissions: ${error.message}`)
} else if (error instanceof ServerError) {
console.log(`Server error (${error.statusCode}): ${error.message}`)
} else if (error instanceof PromptRailsError) {
console.log(`Unexpected error: ${error.message}`)
}
}Error Classes
| Exception | HTTP Status | Description |
|---|---|---|
ValidationError | 400 | Invalid request parameters |
UnauthorizedError | 401 | Invalid or missing API key |
ForbiddenError | 403 | Insufficient permissions |
NotFoundError | 404 | Resource not found |
RateLimitError | 429 | Rate limit exceeded |
ServerError | 5xx | Server-side error |
PromptRailsError | Any | Base class for all errors |
All error instances include:
message-- Error descriptionstatusCode-- HTTP status codecode-- Optional error codedetails-- Optional additional details object
ESM and CJS Support
The SDK ships with both ESM and CommonJS builds:
// ESM
import { PromptRails } from '@promptrails/sdk'
// CommonJS
const { PromptRails } = require('@promptrails/sdk')Pagination
// Page-based pagination
const page1 = await client.agents.list({ page: 1, limit: 20 })
const page2 = await client.agents.list({ page: 2, limit: 20 })Related Topics
- Examples -- Ready-to-run code examples
- Quickstart -- Getting started guide
- Python SDK -- Python alternative
- Go SDK -- Go alternative
- API Keys and Scopes -- API key management
- REST API Reference -- Underlying REST API