Platform
ScaiWave ScaiGrid ScaiCore ScaiBot ScaiDrive ScaiKey Modellen Tools & Services
Oplossingen
Organisaties Ontwikkelaars Internet Service Providers Managed Service Providers AI-in-a-Box
Kenniscentrum
Ondersteuning Documentation Blog Downloads
Bedrijf
Over ons Onderzoek Vacatures Investeren Contact
Inloggen

SDKs

ScaiScribe ships three official client SDKs. All cover the same surface — document creation, editing, ingestion, plus an admin sub-client for operator surfaces.

Python#

Installpip install scaiscribe

Requires — Python 3.10+

python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
from scaiscribe import Client, ScaiKeyAuth

auth = ScaiKeyAuth(client_id="...", client_secret="...")

# Sync
with Client("https://scaiscribe.scailabs.ai", auth=auth) as scribe:
    doc = scribe.create_document(format="docx", theme="office")
    scribe.add_element(doc.doc_id, {"type": "heading", "level": 1, "text": "Hi"})
    result = scribe.finalize(doc.doc_id, formats=["docx", "pdf"])

# Async — same surface, AsyncClient
from scaiscribe import AsyncClient
async with AsyncClient("https://scaiscribe.scailabs.ai", auth=auth) as scribe:
    doc = await scribe.create_document(format="docx")
    await scribe.add_element(doc.doc_id, {"type": "paragraph", "markdown": "Hi from async."})
    result = await scribe.finalize(doc.doc_id)

The Python SDK ships with Client (sync, httpx.Client-backed) and AsyncClient (async, httpx.AsyncClient-backed). Same methods on both; pick whichever fits your runtime.

TypeScript#

Installnpm install @scaiscribe/sdk

Requires — Node 20+ or any modern browser

ts
1
2
3
4
5
6
7
8
9
import { Client, ScaiKeyAuth } from "@scaiscribe/sdk";

const scribe = new Client("https://scaiscribe.scailabs.ai", {
  auth: new ScaiKeyAuth({ clientId: "...", clientSecret: "..." }),
});

const doc = await scribe.createDocument({ format: "docx", theme: "office" });
await scribe.addElement(doc.doc_id, { type: "heading", level: 1, text: "Hi" });
const result = await scribe.finalize(doc.doc_id, { formats: ["docx", "pdf"] });

The TS SDK is fetch-based and async-only (idiomatic for the JS runtime). Browser usage works the same way; just ensure CORS is permitted from your origin (set up by your ScaiScribe operator).

.NET#

Installdotnet add package ScaiLabs.ScaiScribe

Requires — .NET 8.0+

csharp
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
using ScaiLabs.ScaiScribe;

using var auth = new ScaiKeyAuth(clientId: "...", clientSecret: "...");
using var scribe = new ScaiScribeClient("https://scaiscribe.scailabs.ai", auth);

var doc = await scribe.CreateDocumentAsync(new CreateDocumentInput
{
    Format = "docx",
    Theme = "office",
});
await scribe.AddElementAsync(doc.DocId, new Dictionary<string, object>
{
    ["type"] = "heading", ["level"] = 1, ["text"] = "Hi",
});
var result = await scribe.FinalizeAsync(doc.DocId, new FinalizeInput
{
    Formats = new[] { "docx", "pdf" },
});

HttpClient-based, async-only, idiomatic naming. Implements IDisposable for both the auth and the client.

Shared design#

The three SDKs are deliberately aligned:

  • Same conceptual surface: Client (with optional AsyncClient in Python), DocumentEnvelope, JobEnvelope, RenderArtefact, PatchOp, plus an admin sub-namespace.
  • Same auth model: ScaiKeyAuth (client_credentials against ScaiKey, transparent refresh) is the default. BearerAuth(token) for pre-minted tokens.
  • Same error mapping: every spec §6.6 error envelope maps to a typed exception with .code, .message, .details, .request_id carried through.
  • Same sync-wrap semantics: long ops (finalize, ingest_document, preview) default sync=true; pass sync=false to get a JobEnvelope back and poll yourself.

Operations covered#

Method (Python / TS casing in parens) Endpoint
create_document / createDocument POST /v1/documents
get_document / getDocument GET /v1/documents/{id}
delete_document / deleteDocument DELETE /v1/documents/{id}
close_document / closeDocument POST /v1/documents/{id}/close
patch_document / add_element PATCH /v1/documents/{id}
finalize POST /v1/documents/{id}/finalize
preview POST /v1/documents/{id}/preview
from_template / fromTemplate POST /v1/documents/from_template
ingest_document / ingestDocument POST /v1/documents/ingest
get_job / getJob GET /v1/jobs/{id}
upload_asset / list_assets POST/GET /v1/assets
upload_font / list_fonts / delete_font POST/GET/DELETE /v1/fonts
upload_template / list_templates POST/GET /v1/templates
health GET /v1/health
admin.* (12 endpoints) /v1/admin/*

Admin sub-client#

For operator surfaces (roles, users, partner/tenant inspection, job result inspection, quota rollups), each SDK exposes an admin sub-client:

python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# Python
scribe.admin.health()
scribe.admin.list_jobs(status="failed", limit=20)
scribe.admin.grant_role("usr_alice", role="superadmin")

# Quota rollups
scribe.admin.partner_quota_rollup("prt_acme", axis="renders_per_day")
scribe.admin.tenant_user_quota_rollup("tnt_acme", axis="renders_per_day")

# Webhook secret rotation (superadmin only)
rot = scribe.admin.rotate_webhook_secret()
print(rot.new_secret)   # install on ScaiKey side + update .env immediately
ts
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// TypeScript
await scribe.admin.health();
await scribe.admin.listJobs({ status: "failed", limit: 20 });
await scribe.admin.grantRole("usr_alice", { role: "superadmin" });

await scribe.admin.partnerQuotaRollup("prt_acme", { axis: "renders_per_day" });
await scribe.admin.tenantUserQuotaRollup("tnt_acme");

const rot = await scribe.admin.rotateWebhookSecret();
console.log(rot.new_secret);
csharp
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// .NET
await scribe.Admin.GetHealthAsync();
await scribe.Admin.ListJobsAsync(status: "failed", limit: 20);
await scribe.Admin.GrantRoleAsync("usr_alice", new GrantRoleInput { Role = "superadmin" });

await scribe.Admin.PartnerQuotaRollupAsync("prt_acme", axis: "renders_per_day");
await scribe.Admin.TenantUserQuotaRollupAsync("tnt_acme");

var rot = await scribe.Admin.RotateWebhookSecretAsync();
Console.WriteLine(rot.NewSecret);

You need a token with admin-level scope to use these. Browser-based admin sign-in goes through the admin UI instead.

Admin endpoint coverage#

Endpoint Python TS .NET
GET /v1/admin/config admin.config() admin.config() Admin.GetConfigAsync()
GET /v1/admin/me admin.me() admin.me() Admin.GetMeAsync()
GET /v1/admin/health admin.health() admin.health() Admin.GetHealthAsync()
GET /v1/admin/jobs admin.list_jobs() admin.listJobs() Admin.ListJobsAsync()
GET /v1/admin/jobs/{id} admin.get_job() admin.getJob() Admin.GetJobAsync()
GET /v1/admin/users admin.list_users() admin.listUsers() Admin.ListUsersAsync()
GET /v1/admin/users/{id}/roles admin.list_user_roles() admin.listUserRoles() Admin.ListUserRolesAsync()
POST /v1/admin/users/{id}/roles admin.grant_role() admin.grantRole() Admin.GrantRoleAsync()
DELETE /v1/admin/users/{id}/roles/{rid} admin.revoke_role() admin.revokeRole() Admin.RevokeRoleAsync()
GET /v1/admin/tenants admin.list_tenants() admin.listTenants() Admin.ListTenantsAsync()
GET /v1/admin/partners admin.list_partners() admin.listPartners() Admin.ListPartnersAsync()
POST /v1/admin/scaikey/rotate-webhook-secret admin.rotate_webhook_secret() admin.rotateWebhookSecret() Admin.RotateWebhookSecretAsync()
GET /v1/admin/quotas/partner/{id} admin.partner_quota_rollup() admin.partnerQuotaRollup() Admin.PartnerQuotaRollupAsync()
GET /v1/admin/quotas/tenant/{id}/users admin.tenant_user_quota_rollup() admin.tenantUserQuotaRollup() Admin.TenantUserQuotaRollupAsync()

Generated spec types#

Python and TypeScript SDKs ship types generated from the published JSON Schema. Import directly when you're building a document spec programmatically:

python
1
2
# Python (in scaiscribe._generated.spec, re-exported)
from scaiscribe.spec import ScaiscribeDocumentSpecification
ts
1
2
// TypeScript
import type { ScaiscribeDocumentSpecification } from "@scaiscribe/sdk/spec";

The .NET SDK uses hand-written wire-level types; a future release will add an NSwag codegen target.

Versioning#

All three SDKs follow semver. We pin to the spec's schema_version (currently 0.1):

  • 0.1.x SDKs target schema_version: "0.1"
  • Breaking changes to the spec bump the major; SDKs follow.
  • Within a major, additive backend changes (new optional fields, new endpoints) are minor bumps.
Updated 2026-07-03 13:00:09 View source (.md) rev 16