Node SDK
A typed client for Node.js 20.19 or later, with no runtime dependencies, that follows the OpenAPI file call for call.
Status. The SignWren API is opening in stages and may not be on your account yet. If Settings shows an API keys section, you can make sandbox keys now; live keys come with the Pro and Business plans. SignWren is an electronic signature app for small businesses; it is not a law firm and does not give legal advice.
How do I install the Node SDK?
It isn't on npm yet, so it comes as a package file: email hello@signwren.com for signwren-sdk-0.1.0.tgz and install that file. The npm name, @signwren/sdk, and the licence it will be published under are still to be decided.
cd ~/your-project
npm install ./signwren-sdk-0.1.0.tgzThe package works with import and with require, ships its own TypeScript types, and has no runtime dependencies.
How do I create a client?
Pass your API key; everything else has a sensible default.
import { SignWren } from '@signwren/sdk'; // or: const { SignWren } = require('@signwren/sdk')
const sw = new SignWren({
apiKey: process.env.SIGNWREN_API_KEY ?? '', // sw_test_... or sw_live_...
appInfo: 'my-crm/2.1', // shown in the audit trail's user agent
});The resources mirror the API: sw.documents, sw.envelopes (with .recipients and .fields), sw.templates and sw.webhookEndpoints (with .deliveries). Every operation in the reference has a method, and the SDK's tests fail if one is missing. The quick start walks through a whole envelope.
What does the SDK handle for me?
- Idempotency keys. Every
POSTgets a random key, reused on each retry of that call, so a retry never does the work twice. Pass your own to stay safe across restarts. - Retries. 429, 500, 502, 503, 504 and network errors are retried twice by default with exponential backoff and jitter, waiting for
Retry-Afterwhen the API sends one. - Typed errors. One class per kind of failure, each with the API's
code,message,param,detailsandrequestId. - Pagination.
iterate()walks every page for you. - Download checks. PDFs are checked against the SHA-256 the API sends with them.
- Webhook checks.
webhooks.constructEvent()verifies the signature header in constant time; see webhooks. - Key safety. The key is never printed by
JSON.stringify, and plainhttp://is refused except for localhost.
How do I handle errors?
Catch the error classes you care about and branch on code for the details.
import { ConflictError, InvalidRequestError, NotFoundError, RateLimitError } from '@signwren/sdk';
try {
await sw.envelopes.send(envelopeId);
} catch (err) {
if (err instanceof InvalidRequestError && err.code === 'WARNING_UNACKNOWLEDGED') {
// err.details.categories lists what to show the sender before acknowledging
} else if (err instanceof ConflictError) {
// already sent, or not a draft
} else if (err instanceof NotFoundError) {
// wrong id, or the key is in the other environment
} else {
throw err; // err.requestId is in SignWren's logs
}
}How do I read every page of a list?
Use iterate(), which asks for the next page only when your loop reaches it.
for await (const envelope of sw.envelopes.iterate({ status: 'sent', limit: 100 })) {
console.log(envelope.id, envelope.status_label);
}Which options can I change?
All options are on the constructor, and per-call options take an idempotency key, an abort signal, a timeout and a retry count.
const sw = new SignWren({
apiKey: process.env.SIGNWREN_API_KEY ?? '',
baseUrl: 'https://app.signwren.com/api/v1', // the default
maxRetries: 2, // after the first try
timeoutMs: 30_000, // per try; uploads default to 120 s
maxRetryDelayMs: 60_000, // a longer Retry-After is thrown, not waited for
onResponse: (r) => log.debug(r.operationId, r.status, r.requestId),
});
await sw.envelopes.create(body, { idempotencyKey: `crm-${deal.id}-lease` });How do I test code that uses the SDK?
Point it at the mock server from @signwren/sdk/testing, which answers from the OpenAPI file, or at the sandbox with a sw_test_ key. The sandbox page shows both.
Is there a Python SDK?
Yes. The Python SDK has the same methods, retries, errors and webhook checks, with Python names, and like this package it isn't published yet.
Last checked against the API spec on .