npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@signedsh/sdk

v0.1.0

Published

Official TypeScript/JavaScript SDK for Signed — the e-signature API that generates the document for you.

Readme

Signed — TypeScript / JavaScript SDK

npm license

The official SDK for Signed — the e-signature API that generates the document for you. Generate a PDF from a template or HTML, send it for signature, collect a legally binding e-signature with a court-grade audit trail, get a webhook when it's done, and store the sealed PDF. One API, one bill, ~$0.10 per envelope. The developer-first alternative to DocuSign.

  • Zero dependencies. Built on the platform fetch — works on Node 18+, Bun, Deno, Cloudflare Workers, and the edge.
  • Fully typed. Every request and response is described in TypeScript.
  • Safe by default. Automatic idempotency keys, retries with jitter, and a typed error for every failure mode.
  • Webhook verification included. Standard Webhooks HMAC verification, no extra package.

Install

npm install @signedsh/sdk

Quickstart

import { Signed } from "@signedsh/sdk";

const signed = new Signed("sk_live_..."); // or set SIGNED_API_KEY

const envelope = await signed.envelopes.create({
  document: {
    template_id: "tmpl_employment",
    data: { employee: "Jane Doe", salary: "$120,000" },
  },
  signers: [{ name: "Jane Doe", email: "[email protected]", role: "employee", order: 1 }],
  fields: [{ type: "signature", signer: "employee", anchor: "{{sig_employee}}" }],
  options: { expires_in_days: 14 },
  webhook_url: "https://acme.com/hooks/signed",
});

console.log(envelope.envelope_id, envelope.status, envelope.webhook_secret); // env_8fa2 "sent" whsec_...

We generate the PDF, email Jane a signing link, and fire envelope.completed to your webhook when she's done. Store webhook_secret to verify events for this envelope. One call.

Configuration

const signed = new Signed({
  apiKey: process.env.SIGNED_API_KEY, // default: process.env.SIGNED_API_KEY
  baseUrl: "https://api.signed.sh/v1", // override for self-hosted
  maxRetries: 2,                        // retry 429 / 5xx / network errors
  timeout: 30_000,                      // per-request timeout (ms)
});

Every method takes the same per-call options as a final argument:

await signed.envelopes.create(params, {
  idempotencyKey: "order_8842",  // a key is auto-generated if you omit this
  timeout: 10_000,
  maxRetries: 5,
  signal: AbortSignal.timeout(5_000),
});

Resources

Envelopes

const ref = await signed.envelopes.create({ document, signers, fields, metadata: { order_id: "8842" } });
const envelope = await signed.envelopes.retrieve(ref.envelope_id);
await signed.envelopes.update(ref.envelope_id, { metadata: { archived: true } });
await signed.envelopes.void(ref.envelope_id);

// Auto-paginating iterator over every envelope (newest first):
for await (const env of signed.envelopes.list({ status: "completed" })) {
  console.log(env.envelope_id, env.metadata);
}

// Poll until terminal, with a timeout:
const sealed = await signed.envelopes.waitUntilCompleted(ref.envelope_id, { timeoutMs: 600_000 });
sealed.signed_document_url; // sealed (PAdES) PDF
sealed.certificate_url;     // certificate of completion

Signing links

A single reusable link — no API call per signature (like a Stripe Payment Link).

const link = await signed.signingLinks.create({
  name: "Mutual NDA",
  document: { template_id: "tmpl_nda" },
  fields: [{ type: "signature", signer: "counterparty" }],
  options: { max_uses: 100, expires_in_days: 30 },
});

console.log(link.url); // share anywhere — whoever opens it signs

Documents

Render a template or HTML to a PDF without sending it for signature.

const { url } = await signed.documents.render({
  html: "<h1>Invoice #1024</h1>",
  options: { format: "A4" },
});

Errors

Every failure throws a typed subclass of SignedError.

import { Signed, RateLimitError, InvalidRequestError, SignedError } from "@signedsh/sdk";

try {
  await signed.envelopes.create(params);
} catch (err) {
  if (err instanceof RateLimitError) {
    // already retried maxRetries times; back off further
  } else if (err instanceof InvalidRequestError) {
    console.error(err.message, err.type, err.requestId, err.docsUrl);
  } else if (err instanceof SignedError) {
    console.error(`Signed API error ${err.status}:`, err.message);
  }
}

| Class | When | | --- | --- | | InvalidRequestError | 400 / 422 — malformed request or validation failure | | AuthenticationError | 401 — missing or invalid API key | | QuotaExceededError | 402 — quota exhausted (prompt an upgrade) | | PermissionError | 403 — not allowed (e.g. test key on a live resource) | | NotFoundError | 404 — no such resource | | ConflictError | 409 — conflicting state (e.g. voiding a completed envelope) | | RateLimitError | 429 — rate limited (auto-retried) | | ServerError | 5xx — our side (auto-retried) | | APIConnectionError | network failure, timeout, or abort |

Every SignedError carries .status, .type, .requestId, .docsUrl, and .raw.

Verifying webhooks

Verify the raw request body before trusting an event (Standard Webhooks).

import { Webhook, WebhookVerificationError } from "@signedsh/sdk";

const wh = new Webhook(process.env.SIGNED_WEBHOOK_SECRET!); // whsec_...

// Express / Node — make sure you pass the RAW body, not a parsed object.
app.post("/hooks/signed", express.raw({ type: "application/json" }), (req, res) => {
  try {
    const event = wh.verify(req.body, req.headers);
    if (event.type === "envelope.completed") {
      // event.data.envelope_id, ...
    }
    res.sendStatus(200);
  } catch (err) {
    if (err instanceof WebhookVerificationError) return res.sendStatus(400);
    throw err;
  }
});

Idempotency & retries

  • Writes are idempotent. Every POST sends an Idempotency-Key; one is generated for you, or pass your own via { idempotencyKey }. Retrying a key returns the original result and never double-charges.
  • Automatic retries. 429, 5xx, and network errors are retried up to maxRetries with exponential backoff + full jitter, honoring Retry-After.

Links

  • Docs: https://docs.signed.sh
  • API reference: https://docs.signed.sh/api-reference
  • SDKs & AI/LLM access: https://docs.signed.sh/sdks
  • OpenAPI spec: https://github.com/trysolodev/signed.sh/blob/main/openapi.yaml

Built on open source

Signed's platform stands on great open source — Gotenberg (document generation) and optional self-hosted DocuSeal for advanced/PDF ceremonies — with our own SES signing page, PAdES sealing, certificate of completion, and hash-chained audit trail layered on top. This SDK is an independent HTTP client and bundles none of their code.

License

MIT © Signed