---
audience: developers
summary: SDKs, REST endpoints, and MCP tools. Authoritative surface for every operation.
title: Reference
path: reference
status: published
---


# Reference

The full ScaiScribe surface. Three peers; pick whichever fits your runtime.

| If you're building… | Use |
|---|---|
| A Python service or script | The [Python SDK](/docs/scaiscribe/reference/sdks) |
| A Node.js app or browser tool | The [TypeScript SDK](/docs/scaiscribe/reference/sdks) |
| A .NET service | The [.NET SDK](/docs/scaiscribe/reference/sdks) |
| An AI agent (Claude, GPT, etc.) | The [MCP tool surface](/docs/scaiscribe/reference/api) |
| Anything else, or want raw control | The [REST API](/docs/scaiscribe/reference/api) |

All three transports route through the same service layer and respect the same auth scopes — the choice is ergonomics, not capability.

## Authentication

Every surface uses ScaiKey-issued bearer tokens. The recommended path is OAuth `client_credentials` against your tenant's ScaiKey deployment:

```
POST https://scaikey.scailabs.ai/api/v1/platform/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials
&client_id=<your client_id>
&client_secret=<your client_secret>
&scope=api:read api:write
```

The SDKs handle this for you transparently when you pass `ScaiKeyAuth(client_id, client_secret)`. Tokens are cached in-process and refreshed ~30 seconds before expiry.

## Error envelope

Every error response is shaped per spec §6.6:

```json
{
  "error": {
    "code": "QUOTA_EXCEEDED",
    "message": "Tenant render quota exhausted",
    "details": { "limit": 1000, "current": 1000 },
    "request_id": "req_01ABC..."
  }
}
```

SDKs map these to typed exceptions:

| Status + code | Python | TypeScript | .NET |
|---|---|---|---|
| 401 | `AuthError` | `AuthError` | `AuthException` |
| 403 + `QUOTA_EXCEEDED` | `QuotaError` | `QuotaError` | `QuotaException` |
| 403 (other) | `ForbiddenError` | `ForbiddenError` | `ForbiddenException` |
| 404 | `NotFoundError` | `NotFoundError` | `NotFoundException` |
| 409 | `ConflictError` | `ConflictError` | `ConflictException` |
| 429 | `RateLimitError` | `RateLimitError` | `RateLimitException` |
| 400 / 422 | `BadRequestError` | `BadRequestError` | `BadRequestException` |
| 5xx | `ServerError` | `ServerError` | `ServerException` |

Every typed exception carries `.code`, `.message`, `.details`, `.request_id` (or `.RequestId` in .NET) so backend logs are correlatable.

## Sync wrapping (long ops)

Three operations are long-running: `finalize`, `ingest_document`, `preview`. The SDKs default to `sync=True` — the backend blocks until the job completes within the per-operation timeout (spec §3.4) and returns the final result inline.

| Operation | Default sync timeout |
|---|---|
| `finalize` | 15s |
| `ingest_document` | 30s |
| `preview` | 8s |

Pass `sync=False` to get a `JobEnvelope` back and poll `get_job(job_id)` yourself. The async pattern is also what you want for jobs you know will exceed the sync timeout (e.g. ingesting a 200-page DOCX).

## Sub-sections

- **[SDKs](/docs/scaiscribe/reference/sdks)** — install, surface, examples for Python / TypeScript / .NET.
- **[API](/docs/scaiscribe/reference/api)** — full REST endpoint list + MCP tool catalogue.
- **[Templates](/docs/scaiscribe/reference/templates)** — complete docx-templates grammar: every command, every quirk, every limitation.
