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 |
| A Node.js app or browser tool | The TypeScript SDK |
| A .NET service | The .NET SDK |
| An AI agent (Claude, GPT, etc.) | The MCP tool surface |
| Anything else, or want raw control | The REST 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:
1 2 3 4 5 6 7 | |
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:
1 2 3 4 5 6 7 8 | |
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).