---
title: TypeScript SDK
description: "The official TypeScript/JavaScript SDK — @syntext/sdk on npm."
---

# TypeScript SDK

Type-safe client for the Syntext API. Works in Node.js (18+), Bun, Deno, and modern browsers.

## Installation

<CodeGroup>
```bash npm
npm install @syntext/sdk
```

```bash bun
bun add @syntext/sdk
```

```bash pnpm
pnpm add @syntext/sdk
```
</CodeGroup>

## Quick Start

```typescript
import { Syntext } from '@syntext/sdk'

const client = new Syntext(process.env.SYNTEXT_API_KEY!)

// Get a project
const project = await client.projects.get('prj_abc123')

// Trigger a build
const build = await client.builds.trigger(project.id, { branch: 'main' })

// Search the docs
const results = await client.search.query(project.id, 'authentication')
```

## Resources

| Resource | Methods |
|----------|---------|
| `client.projects` | `list()`, `get(id)`, `create(data)`, `update(id, data)`, `delete(id)` |
| `client.builds` | `list(projectId, opts?)`, `get(projectId, buildId)`, `trigger(projectId, opts?)`, `cancel(projectId, buildId)` |
| `client.search` | `query(projectId, query, opts?)`, `reindex(projectId)` |
| `client.chat` | `ask(projectId, opts)` — streaming |
| `client.domains` | `add(projectId, domain)`, `verify(projectId, domainId)`, `remove(projectId, domainId)` |
| `client.apiKeys` | `list(projectId)`, `create(projectId, data)`, `rotate(projectId, keyId)`, `revoke(projectId, keyId)` |

## Streaming AI Chat

```typescript
const stream = await client.chat.ask('prj_abc123', {
  question: 'How do I add a custom domain?',
})

for await (const chunk of stream) {
  process.stdout.write(chunk.delta)
}
```

The final chunk carries `citations` (source page paths) and the `sessionId` for follow-up questions.

## Error Handling

```typescript
import {
  SyntextError,
  NotFoundError,
  ValidationError,
  RateLimitError,
  AuthenticationError,
} from '@syntext/sdk'

try {
  await client.builds.trigger('prj_abc123')
} catch (err) {
  if (err instanceof RateLimitError) {
    console.log(`Retry after ${err.retryAfterSeconds}s`)
  } else if (err instanceof SyntextError) {
    console.error(err.code, err.message)
  }
}
```

`429` and `5xx` responses are retried automatically with exponential backoff before an error is thrown.

## Polling a Build to Completion

```typescript
const build = await client.builds.trigger('prj_abc123')

let status = build.status
while (status === 'queued' || status === 'building') {
  await new Promise((r) => setTimeout(r, 5000))
  status = (await client.builds.get('prj_abc123', build.id)).status
}

console.log(status === 'deployed' ? '✓ Live' : `✗ ${status}`)
```
