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.

Terminal window
npm install @subnoto/api-client
# or
pnpm add @subnoto/api-client
# or
yarn add @subnoto/api-client
import { SubnotoClient } from "@subnoto/api-client";
const client = new SubnotoClient({
apiBaseUrl: "https://enclave.subnoto.com",
accessKey: process.env.API_ACCESS_KEY,
secretKey: process.env.API_SECRET_KEY,
unattested: false
});
// 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);
OptionTypeRequiredDescription
apiBaseUrlstringYesAPI base URL
accessKeystringYesAPI access key
secretKeystringYesAPI secret key
unattestedbooleanNoUse unattested mode (default: false)
attesterKeyBufferNoPublic key for attestation
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})`);
});
}
const { data, error } = await client.POST("/public/envelope/list", {
body: {
workspaceUuid: "your-workspace-uuid",
page: 1
}
});
if (data) {
data.envelopes.forEach(envelope => {
console.log(`Envelope: ${envelope.title} - Status: ${envelope.status}`);
});
}
// Create envelope from a pre-configured template
// Recipients must include labels that match the template's recipient labels
const { data, error } = await client.POST("/public/envelope/create-from-template", {
body: {
workspaceUuid: "your-workspace-uuid",
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}`);
}
const { error } = await client.POST("/public/envelope/send", {
body: {
workspaceUuid: "your-workspace-uuid",
envelopeUuid: "your-envelope-uuid",
customInvitationMessage: "Please review and sign this document."
}
});
if (!error) {
console.log("Envelope sent successfully!");
}
const { data, error } = await client.POST("/public/template/list", {
body: { page: 1 }
});
if (data) {
data.templates.forEach(template => {
console.log(`Template: ${template.name} (${template.uuid})`);
});
}
const { data, error } = await client.POST("/public/contact/list", {
body: { workspaceUuid: "your-workspace-uuid" }
});
if (data) {
data.contacts.forEach(contact => {
console.log(`Contact: ${contact.firstname} ${contact.lastname} (${contact.email})`);
});
}
import { SubnotoClient } from "@subnoto/api-client";
async function createAndSendEnvelopeFromTemplate() {
const client = new SubnotoClient({
apiBaseUrl: "https://enclave.subnoto.com",
accessKey: process.env.API_ACCESS_KEY,
secretKey: process.env.API_SECRET_KEY
});
// 1. Get workspace
const { data: workspaceData } = await client.POST("/public/workspace/list", { body: {} });
const workspaceUuid = workspaceData.workspaces[0].uuid;
// 2. Get template
const { data: templateData } = await client.POST("/public/template/list", {
body: { page: 1 }
});
const templateUuid = templateData.templates[0].uuid;
// 3. Create envelope from template
const { data: envelopeData } = await client.POST("/public/envelope/create-from-template", {
body: {
workspaceUuid,
templateUuid,
recipients: [
{
type: "manual",
label: "signer",
firstname: "John",
lastname: "Doe"
}
]
}
});
// 4. Send the envelope
await client.POST("/public/envelope/send", {
body: {
workspaceUuid,
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.

import { SubnotoClient } from "@subnoto/api-client";
import { readFileSync } from "fs";
async function createAndSendEnvelopeWithDocument() {
const client = new SubnotoClient({
apiBaseUrl: "https://enclave.subnoto.com",
accessKey: process.env.API_ACCESS_KEY,
secretKey: process.env.API_SECRET_KEY
});
// 1. Get workspace
const { data: workspaceData } = await client.POST("/public/workspace/list", { body: {} });
const workspaceUuid = workspaceData.workspaces[0].uuid;
// 2. Upload document and create envelope using the helper method
const pdfBuffer = readFileSync("path/to/document.pdf");
const result = await client.uploadDocument({
workspaceUuid,
fileBuffer: pdfBuffer,
envelopeTitle: "My Document"
});
const { envelopeUuid, documentUuid } = result;
// 3. Add recipients
await client.POST("/public/envelope/add-recipients", {
body: {
workspaceUuid,
envelopeUuid,
recipients: [
{
type: "manual",
firstname: "John",
lastname: "Doe"
}
]
}
});
// 4. Add signature blocks
await client.POST("/public/envelope/add-blocks", {
body: {
workspaceUuid,
envelopeUuid,
documentUuid,
blocks: [
{
type: "signature",
page: "1",
x: 100,
y: 200,
recipientEmail: "[email protected]"
}
]
}
});
// 5. Send the envelope
await client.POST("/public/envelope/send", {
body: {
workspaceUuid,
envelopeUuid,
customInvitationMessage: "Please review and sign this document."
}
});
console.log(`Envelope ${envelopeUuid} created and sent!`);
}
createAndSendEnvelopeWithDocument().catch(console.error);

If you need more control over the upload process, you can use the create-from-file endpoint directly with FormData. Steps 3-5 (add recipients, add blocks, send) remain the same as shown above.

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";
// ... (steps 1 and client setup same as above) ...
// 2. Upload document and create envelope using FormData
const formData = new FormData();
formData.append("workspaceUuid", workspaceUuid);
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 3-5 as shown in the example above

The SDK supports attestation verification to ensure you’re communicating with a genuine Subnoto enclave:

const client = new SubnotoClient({
apiBaseUrl: "https://enclave.subnoto.com",
accessKey: process.env.API_ACCESS_KEY,
secretKey: process.env.API_SECRET_KEY,
attesterKey: Buffer.from(process.env.ATTESTATION_PUBLIC_KEYS, "base64"),
unattested: false // Enable attestation (default)
});
// After making a request, check attestation status
const attestationStatus = client.getAttestationStatus();
console.log("Attestation status:", attestationStatus);
const attestationResults = client.getAttestationResults();
console.log("Attestation results:", attestationResults);

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.