TypeScript SDK
The TypeScript SDK provides a type-safe client for integrating with Subnoto’s API. It handles Oak tunnel encryption, HTTP signature authentication, and provides helper functions for common operations.
Installation
Section titled “Installation”npm install @subnoto/api-client# orpnpm add @subnoto/api-client# oryarn add @subnoto/api-clientQuick Start
Section titled “Quick Start”import { SubnotoClient } from "@subnoto/api-client";
const client = new SubnotoClient({ accessKey: process.env.API_ACCESS_KEY, secretKey: process.env.API_SECRET_KEY});
// Use openapi-fetch syntaxconst { data, error } = await client.POST("/public/utils/whoami", { body: {} });console.log("User info:", data);
const { data: workspaces } = await client.POST("/public/workspace/list", { body: {} });console.log("Workspaces:", workspaces);Configuration
Section titled “Configuration”| Option | Type | Required | Description |
|---|---|---|---|
accessKey | string | Yes | API access key |
secretKey | string | Yes | API secret key |
Workspace and workspaceUuid
Section titled “Workspace and workspaceUuid”In most Public API endpoints, workspaceUuid is optional. When omitted, the team’s default workspace is used. This keeps code simple when you use a single workspace. To target a specific workspace, pass workspaceUuid in the request body.
Per-endpoint details are in the OpenAPI specifications. For a pattern that uses an optional workspace from environment variables, see the Subnoto SDK demo (e.g. getClientAndWorkspace() and ...(workspaceUuid && { workspaceUuid }) in request bodies).
Common Use Cases
Section titled “Common Use Cases”List Workspaces
Section titled “List Workspaces”const { data, error } = await client.POST("/public/workspace/list", { body: {} });
if (error) { console.error("Failed to list workspaces:", error);} else { data.workspaces.forEach(workspace => { console.log(`Workspace: ${workspace.name} (${workspace.uuid})`); });}List Envelopes in a Workspace
Section titled “List Envelopes in a Workspace”Omit workspaceUuid to list envelopes in the default workspace, or pass it to scope to a specific workspace.
const { data, error } = await client.POST("/public/envelope/list", { body: { page: 1 }});
if (data) { data.envelopes.forEach(envelope => { console.log(`Envelope: ${envelope.title} - Status: ${envelope.status}`); });}Create an Envelope from Template
Section titled “Create an Envelope from Template”// Create envelope from a pre-configured template// Recipients must include labels that match the template's recipient labels// workspaceUuid is optional (default workspace used when omitted)const { data, error } = await client.POST("/public/envelope/create-from-template", { body: { templateUuid: "your-template-uuid", recipients: [ { type: "manual", label: "customer", firstname: "John", lastname: "Doe" }, { type: "manual", label: "manager", firstname: "Jane", lastname: "Smith" } ] }});
if (data) { console.log(`Created envelope: ${data.envelopeUuid}`);}Send an Envelope
Section titled “Send an Envelope”const { error } = await client.POST("/public/envelope/send", { body: { envelopeUuid: "your-envelope-uuid", customInvitationMessage: "Please review and sign this document." }});
if (!error) { console.log("Envelope sent successfully!");}List Templates
Section titled “List Templates”const { data, error } = await client.POST("/public/template/list", { body: { page: 1 }});
if (data) { data.templates.forEach(template => { console.log(`Template: ${template.title} (${template.uuid})`); });}List Contacts
Section titled “List Contacts”workspaceUuid is optional; omit it to list contacts in the default workspace.
const { data, error } = await client.POST("/public/contact/list", { body: {}});
if (data) { data.contacts.forEach(contact => { console.log(`Contact: ${contact.firstname} ${contact.lastname} (${contact.email})`); });}Full Workflow Examples
Section titled “Full Workflow Examples”Creating an Envelope from a Template
Section titled “Creating an Envelope from a Template”This example uses the default workspace (no workspaceUuid). To target a specific workspace, use ...(workspaceUuid && { workspaceUuid }) in each body when you have a workspaceUuid (e.g. from env or from listing workspaces).
import { SubnotoClient } from "@subnoto/api-client";
async function createAndSendEnvelopeFromTemplate() { const client = new SubnotoClient({ accessKey: process.env.API_ACCESS_KEY, secretKey: process.env.API_SECRET_KEY });
// 1. Get template (default workspace) const { data: templateData } = await client.POST("/public/template/list", { body: { page: 1 } }); const templateUuid = templateData.templates[0].uuid;
// 2. Create envelope from template const { data: envelopeData } = await client.POST("/public/envelope/create-from-template", { body: { templateUuid, recipients: [ { type: "manual", label: "signer", firstname: "John", lastname: "Doe" } ] } });
// 3. Send the envelope await client.POST("/public/envelope/send", { body: { envelopeUuid: envelopeData.envelopeUuid, customInvitationMessage: "Please review and sign this document." } });
console.log(`Envelope ${envelopeData.envelopeUuid} created and sent!`);}
createAndSendEnvelopeFromTemplate().catch(console.error);Creating an Envelope with a Document Upload
Section titled “Creating an Envelope with a Document Upload”Upload documents to create envelopes. Supported file types: PDF (.pdf) and Word documents (.docx, .doc) - Word files are automatically converted to PDF. Maximum file size: 50 MB.
The SDK provides a helper method uploadDocument that simplifies document uploads by handling multipart/form-data automatically. This is the recommended approach. workspaceUuid is optional in uploadDocument and in the envelope endpoints; when omitted, the default workspace is used.
import { SubnotoClient } from "@subnoto/api-client";import { readFileSync } from "fs";
async function createAndSendEnvelopeWithDocument() { const client = new SubnotoClient({ accessKey: process.env.API_ACCESS_KEY, secretKey: process.env.API_SECRET_KEY });
// 1. Upload document and create envelope (default workspace) const pdfBuffer = readFileSync("path/to/document.pdf"); const result = await client.uploadDocument({ fileBuffer: pdfBuffer, envelopeTitle: "My Document" });
const { envelopeUuid, documentUuid } = result;
// 2. Add recipients await client.POST("/public/envelope/add-recipients", { body: { envelopeUuid, recipients: [ { type: "manual", firstname: "John", lastname: "Doe" } ] } });
// 3. Add signature blocks await client.POST("/public/envelope/add-blocks", { body: { envelopeUuid, documentUuid, blocks: [ { type: "signature", page: "1", x: 100, y: 200, } ] } });
// 4. Send the envelope await client.POST("/public/envelope/send", { body: { envelopeUuid, customInvitationMessage: "Please review and sign this document." } });
console.log(`Envelope ${envelopeUuid} created and sent!`);}
createAndSendEnvelopeWithDocument().catch(console.error);Alternative: Manual FormData Approach
Section titled “Alternative: Manual FormData Approach”If you need more control over the upload process, you can use the create-from-file endpoint directly with FormData. Steps 2-4 (add recipients, add blocks, send) remain the same as shown above. workspaceUuid is optional in the form payload; omit it to use the default workspace.
Required dependency:
npm install form-data# orpnpm add form-dataimport { SubnotoClient } from "@subnoto/api-client";import FormData from "form-data";import { createReadStream } from "fs";
// ... (client setup same as above) ...
// 1. Upload document and create envelope using FormDataconst formData = new FormData();formData.append("envelopeTitle", "My Document");formData.append("file", createReadStream("path/to/document.pdf"));
const { data: envelopeData, error: uploadError } = await client.POST("/public/envelope/create-from-file", { body: formData as any, headers: { ...formData.getHeaders() }});
if (uploadError) { throw new Error(`Failed to upload document: ${uploadError}`);}
const { envelopeUuid, documentUuid } = envelopeData;
// Continue with steps 2-4 (add recipients, add blocks, send) as shown in the example aboveAttestation
Section titled “Attestation”The SDK can verify that you are communicating with a genuine Subnoto enclave. After making requests, use client.getAttestationStatus() for a summary and client.getAttestationResults() for detailed attestation results.
API Reference
Section titled “API Reference”The SDK uses openapi-fetch syntax for all API calls. All endpoints are type-safe and match the OpenAPI specification.
For complete API documentation, see the OpenAPI specifications.
Package
Section titled “Package”- NPM: @subnoto/api-client
- License: Apache-2.0