SDKs & toolsTypeScript SDK

TypeScript SDK

⚠️
Preview — this feature is being built; the design below is the spec.

@syntic/sdk is the official JavaScript and TypeScript library for the Syntic API. It runs on Node.js, Deno, Bun, Cloudflare Workers, Vercel Edge and other runtimes with a standard fetch, and gives you full type definitions, retries with back-off, streaming helpers, automatic pagination, a tool-loop runner and access to every Syntic endpoint, including agents, sessions and the Admin API.

Today there is no official package. Use an OpenAI-compatible client with Syntic’s base URL, as shown in OpenAI-compatible clients. That keeps working after the SDK ships.

Install

npm install @syntic/sdk
# or: pnpm add @syntic/sdk / yarn add @syntic/sdk / bun add @syntic/sdk
# Deno: import Syntic from 'npm:@syntic/sdk'
RequirementValue
Node.js18 or newer
TypeScript4.9 or newer (optional)
Module formatsES modules and CommonJS
DependenciesNone at runtime

Create a client

import Syntic from '@syntic/sdk'
 
const client = new Syntic() // reads SYNTIC_API_KEY where process.env exists
OptionDefaultNotes
apiKeyprocess.env.SYNTIC_API_KEYRequired in runtimes without process.env.
baseURLprocess.env.SYNTIC_BASE_URL ?? 'https://app.syntic.ai/v1'
versionThe version the release was built forSent as syntic-version.
betas[]Sent as syntic-beta. Methods that need a flag add it automatically.
maxRetries2Retries rate_limit, overloaded, api_error and network errors, honouring retry-after.
timeout600_000 msPer request.
fetchglobalThis.fetchSupply your own for proxies or tests.
dangerouslyAllowBrowserfalseThe client refuses to run in a browser unless set, because a key in a page is readable by anyone. See Calling from a browser.

A first request

import Syntic from '@syntic/sdk'
 
const client = new Syntic()
 
const reply = await client.chat.completions.create({
  model: 'Amara S1.2',
  messages: [{ role: 'user', content: 'Give me three names for a bakery.' }],
  max_tokens: 200,
})
console.log(reply.choices[0].message.content)
console.log(reply.usage.total_tokens, reply.request_id)

Streaming

const stream = client.chat.completions.stream({
  model: 'Amara S1.2',
  messages: [{ role: 'user', content: 'Write a haiku about rain.' }],
})
 
for await (const text of stream.textDeltas()) process.stdout.write(text)
 
const final = await stream.finalCompletion() // message, joined tool calls, usage

Cancel with stream.abort() or an AbortSignal passed as { signal } in the second argument. To forward a stream from your server to a browser, stream.toReadableStream() returns a web ReadableStream of server-sent events.

Tool loop

import Syntic, { defineTool } from '@syntic/sdk'
import { z } from 'zod'
 
const client = new Syntic()
 
const getOrder = defineTool({
  name: 'get_order',
  description: 'Look up an order by its id.',
  parameters: z.object({ order_id: z.string() }),
  run: async ({ order_id }) => ({ order_id, status: 'shipped', carrier: 'DHL' }),
})
 
const result = await client.tools.run({
  model: 'Amara S1.2',
  messages: [{ role: 'user', content: 'Where is order 88123?' }],
  tools: [getOrder],
  maxRounds: 8,
})
console.log(result.finalMessage.content)

parameters accepts a Zod schema or a plain JSON Schema object. Arguments are validated before run is called; invalid arguments are returned to the model as an error result.

Errors

API errors are thrown as subclasses of Syntic.APIStatusError, named after the envelope type: InvalidRequestError, AuthenticationError, PermissionDeniedError, NotFoundError, QuotaExhaustedError, RateLimitError, OverloadedError and InternalServerError. Network failures throw APIConnectionError or APITimeoutError. Each API error has status, type, code, message, param, details and requestId.

try {
  await client.chat.completions.create({ model: 'Amara S1.2', messages: [] })
} catch (err) {
  if (err instanceof Syntic.QuotaExhaustedError) {
    console.log('Allowance resets at', err.details?.resets_at)
  } else if (err instanceof Syntic.APIStatusError) {
    console.log(err.code, err.param, err.requestId)
  } else throw err
}

Pagination

for await (const agent of client.agents.list({ limit: 50 })) {
  console.log(agent.id, agent.name)
}

Files, batches, agents and admin

import fs from 'node:fs'
import Syntic, { SynticAdmin } from '@syntic/sdk'
 
const client = new Syntic()
 
const file = await client.files.upload({ file: fs.createReadStream('contract.pdf'), purpose: 'document' })
 
const session = await client.sessions.create({
  agent_id: 'agt_01JC4R8W6Q2N9X3T5V7Y',
  input: [{ type: 'user.message', content: 'Refund order 88123' }],
})
for await (const event of client.sessions.stream(session.id)) {
  if (event.type === 'message.completed') console.log(event.content)
}
 
const admin = new SynticAdmin() // reads SYNTIC_ADMIN_KEY
const org = await admin.organization.retrieve()
console.log(org.plan.name)

Raw responses and headers

const { data, response } = await client.chat.completions
  .create({ model: 'Amara Quick', messages: [{ role: 'user', content: 'ping' }] })
  .withResponse()
console.log(response.headers.get('x-syntic-request-id'), response.headers.get('x-syntic-billing-source'))

Build notes for the platform team

  • Same generator and helper set as the Python SDK; release both together.
  • Zero runtime dependencies; Zod is an optional peer dependency used only by defineTool.
  • Test every release on Node 18, 20 and 22, Deno, Bun and an edge runtime in CI.
  • Publish to npm with provenance from CI under the @syntic scope.
Was this page helpful?