Skip to content

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

Terminal window
npm install @subnoto/api-client
# or
pnpm add @subnoto/api-client
# or
yarn add @subnoto/api-client

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 syntax
const { 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

OptionTypeRequiredDescription
accessKeystringYesAPI access key
secretKeystringYesAPI secret key

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

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

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

// 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

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

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

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

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

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,
recipientEmail: "[email protected]"
}
]
}
});
// 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

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:

Terminal window
npm install form-data
# or
pnpm add form-data
import { 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 FormData
const 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 above

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

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