Official TypeScript SDK for the Motifuse API.
DocForge · Reconova · Spectrace
Release status:
1.0.0-beta.2is published publicly on npm. The official GitHub release workflow is authorized as an npm Trusted Publisher and uses short-lived OIDC credentials for subsequent releases.
Install the current public beta:
npm install @motifuse/sdkUse npm install @motifuse/sdk@beta when you want to follow the prerelease channel explicitly.
The package targets Node.js 20 or newer and uses native fetch. It is ESM-first and has zero
runtime dependencies.
import { Motifuse } from "@motifuse/sdk";
const motifuse = new Motifuse({
apiKey: process.env.MOTIFUSE_API_KEY!,
});
const projects = await motifuse.spectrace.projects.list({ limit: 20 });
console.log(projects.data);Motifuse API keys are server-side secrets. Never put them in browser JavaScript, mobile bundles, public repositories, logs, or analytics. The SDK refuses construction in a browser environment.
const generation = await motifuse.docforge.generations.create(
{
template_id: "tpl_example",
rows: [{ customer_name: "Example Industries" }],
output_format: "pdf",
},
{ idempotencyKey: "invoice-batch-2026-08-24" },
);
const completed = await motifuse.jobs.wait(generation);
const download = await motifuse.docforge.generations.download(completed.id);const file = await motifuse.reconova.files.upload(
{ filename: "quality.csv", size: bytes.byteLength, content_type: "text/csv" },
{ body: bytes, idempotencyKey: "quality-upload-2026-08-24" },
);
const profile = file.job ? await motifuse.jobs.wait(file.job) : undefined;
const cleaned = await motifuse.reconova.operations.clean({ source_asset_id: file.id });const project = await motifuse.spectrace.projects.create({
name: "Supplier contract review",
});
const comparison = await motifuse.spectrace.comparisons.create(project.id, {
baseline_version_id: "stv_baseline_example",
revised_version_id: "stv_revised_example",
});
if (comparison.job) await motifuse.jobs.wait(comparison.job);
for await (const finding of motifuse.spectrace.findings.listAll({
comparisonId: comparison.id,
limit: 50,
})) {
console.log(finding.id, finding.primary_change_type);
}Reconova and Spectrace use direct signed uploads. Their files.upload helpers perform the real
three-step flow: request authorization, upload bytes directly to the short-lived destination, and
complete the file. Document bytes never pass through the SDK or Motifuse application server as an
extra proxy hop. Pass a Blob, Uint8Array, ArrayBuffer, or compatible streaming BodyInit.
Use product-specific retrieve methods or the shared helper:
const job = await motifuse.jobs.retrieve("spectrace", "spj_example");
const completed = await motifuse.jobs.wait(job, {
waitTimeout: 10 * 60_000,
signal: abortController.signal,
});Polling backs off to a bounded interval and stops on succeeded, failed, or cancelled.
MotifuseJobError exposes the job ID, terminal status, and safe processing code.
Every list keeps normal page access. listAll returns an async iterator and requests one bounded
page at a time; it never accumulates an unbounded collection in memory.
import { MotifuseError, getResponseMetadata } from "@motifuse/sdk";
try {
const project = await motifuse.spectrace.projects.retrieve("spj_example");
console.log(getResponseMetadata(project)?.requestId);
} catch (error) {
if (error instanceof MotifuseError) {
console.error(error.code, error.status, error.requestId, error.retryAfter);
}
}MotifuseError preserves RFC 9457 problem type, API code, status, request ID, details, and
Retry-After. Successful object responses can be inspected with getResponseMetadata for request
and rate-limit information without changing normal resource shapes.
The SDK retries network failures, 408, 429, and selected 5xx responses with exponential
backoff, jitter, and Retry-After. GET/HEAD requests are safe to retry. Mutations are retried only
when they carry Idempotency-Key.
SDK methods for API-declared idempotent operations generate one key per logical call. Supply your
own stable key when a process restart must repeat the same operation. Motifuse retains keys for 24
hours, replays equivalent requests, and returns 409 idempotency_conflict if the method, path, or
body changes.
Verify the exact, unmodified raw request body before parsing it:
const rawBody = await request.text();
const event = motifuse.webhooks.verify({
payload: rawBody,
signature: request.headers.get("motifuse-signature")!,
secret: process.env.MOTIFUSE_WEBHOOK_SECRET!,
});Verification uses HMAC-SHA256 over timestamp + "." + raw_body, constant-time comparison, and a
five-minute default tolerance. The returned WebhookEvent type is generated from the actual event
catalog in Motifuse OpenAPI.
new Motifuse({
apiKey: process.env.MOTIFUSE_API_KEY!,
timeout: 30_000,
maxRetries: 2,
baseUrl: "https://motifuse.com/api/v1",
fetch: globalThis.fetch,
headers: { "X-Integration-Name": "billing-worker" },
});Custom base URLs must use HTTPS, except localhost for testing. Per-request options support timeout,
AbortSignal, safe additional headers, and explicit idempotency keys. The SDK sends
motifuse-typescript/<version> client identification and no personal telemetry.
openapi/motifuse.openapi.json is a snapshot of the canonical public contract. Generated models
live in src/generated and must never be edited manually.
npm run openapi:generate
npm run openapi:check
npm run openapi:upstreamCI fails if generated declarations drift from the committed contract. A scheduled upstream check
also compares the snapshot with https://motifuse.com/openapi.json.
- Tested examples
- Developer documentation
- Interactive API reference
- OpenAPI JSON
- OpenAPI YAML
- API changelog
- SDK changelog
The SDK is a convenience layer over the canonical REST API. Developers may use REST, OpenAPI, or the SDK independently.
See CONTRIBUTING.md. Report vulnerabilities privately as described in SECURITY.md; never include keys or customer documents in a public issue.
Licensed under the MIT License.