sign.ytDocs

SDKs

TypeScript SDK

@signyt/sdk is a dependency-free, fetch-based client with types generated from the OpenAPI spec. It runs on Node 18+ and other runtimes with fetch, FormData and Web Crypto. Keep API keys on the server.

Install#

npm install @signyt/sdk

Create a client#

import { Signyt } from "@signyt/sdk";

const client = new Signyt({
  apiKey: process.env.SIGNYT_API_KEY!,
  // baseUrl: "https://api.sign.yt/v1",
  // maxRetries: 2, retryBackoffMs: 500, timeoutMs: 30_000, fetch: customFetch,
});
// or simply: new Signyt(process.env.SIGNYT_API_KEY!)
OptionDefaultDescription
apiKeyrequiredAn sk_live_... key.
baseUrlhttps://api.sign.yt/v1API base URL.
maxRetries2Retries for GET/PUT/DELETE on 429, 5xx and network errors.
retryBackoffMs500Base backoff (exponential, jittered; Retry-After wins, capped at 60 s).
timeoutMs30000Per-attempt timeout.
fetchglobalThis.fetchCustom fetch implementation.

Resources#

MethodEndpoint
documents.list({ limit, offset })GET /documents
documents.get(id)GET /documents/{id}
documents.create({ pdf, title, recipients, signingOrder, verificationType, metadata, expiresAt, allowDelegation, teamId, folderId, filename })POST /documents; pdf is a Blob, Uint8Array (including Node Buffer) or ArrayBuffer
documents.setFields(id, fields)PUT /documents/{id}/fields
documents.detectFields(id)POST /documents/{id}/detect-fields
documents.updateRecipient(id, recipientId, { email, name, phone })PATCH /documents/{id}/recipients/{recipientId}
documents.resend(id, recipientId)POST .../recipients/{recipientId}/resend
documents.send(id), documents.remind(id)POST /documents/{id}/send, /remind
documents.cancel(id, reason, copyAsDraft?)POST /documents/{id}/cancel
documents.delete(id), documents.restore(id)DELETE /documents/{id}, POST /documents/{id}/restore
documents.downloadSignedPdf(id), documents.downloadOriginalPdf(id)Resolve to Uint8Array
documents.audit(id)GET /documents/{id}/audit
templates.list(), templates.create({ pdf, name, description, category }), templates.use(id, { title, recipients }), templates.delete(id)/templates
webhooks.list(), webhooks.create({ url, events }), webhooks.update(id, { url, events, active }), webhooks.delete(id)/webhooks

Exported types include DocumentDetail, DocumentSummary, RecipientInput, FieldInput, TemplateRead, WebhookRead, WebhookCreated and the status enums. For endpoints without a method (flows, public links, deliveries, signing links, evidence, cursor pagination) use fetch directly; the guides have examples.

End-to-end example#

import { readFile, writeFile } from "node:fs/promises";
import { Signyt } from "@signyt/sdk";

const client = new Signyt(process.env.SIGNYT_API_KEY!);

const doc = await client.documents.create({
  pdf: await readFile("contract.pdf"),
  filename: "contract.pdf",
  title: "Service agreement",
  recipients: [{ email: "[email protected]", name: "Anna Nowak" }],
  verificationType: "EMAIL_OTP",
  metadata: { crm_deal_id: "D-1042" },
});
await client.documents.setFields(doc.id, [
  { type: "SIGNATURE", page: 1, position_x: 15, position_y: 80, width: 25, height: 8, recipient_id: doc.recipients[0].id },
]);
await client.documents.send(doc.id);

// later, after document.completed:
const done = await client.documents.get(doc.id);
if (done.status === "COMPLETED") await writeFile("contract-signed.pdf", await client.documents.downloadSignedPdf(doc.id));

Errors#

Failed requests reject with a subclass of SignytError carrying status, code, message, extra and requestId: BadRequestError (400, 413, 422), AuthenticationError (401), PaymentRequiredError (402), PermissionDeniedError (403), NotFoundError (404), ConflictError (409), RateLimitError (429, with retryAfter), ServerError (5xx) and APIConnectionError (network or timeout).

import { ConflictError, Signyt, SignytError } from "@signyt/sdk";

const client = new Signyt(process.env.SIGNYT_API_KEY!);
try {
  await client.documents.remind(process.env.DOC_ID!);
} catch (e) {
  if (e instanceof ConflictError && e.code === "document_not_pending") console.log("nothing to remind");
  else if (e instanceof SignytError) console.error(e.status, e.code, e.message, e.requestId);
  else throw e;
}

Verify webhooks#

import { createServer } from "node:http";
import { constructWebhookEvent, SignatureVerificationError } from "@signyt/sdk";

createServer(async (req, res) => {
  const chunks: Buffer[] = [];
  for await (const c of req) chunks.push(c as Buffer);
  const raw = new Uint8Array(Buffer.concat(chunks));
  try {
    const event = await constructWebhookEvent(
      raw,
      req.headers as Record<string, string>,
      process.env.SIGNYT_WEBHOOK_SECRET!,
    );
    console.log(event.event, event.data);
    res.writeHead(204).end();
  } catch (e) {
    res.writeHead(e instanceof SignatureVerificationError ? 400 : 500).end();
  }
}).listen(3000);

constructWebhookEvent checks the HMAC (constant time, via Web Crypto) and a 5-minute timestamp window (tolerance in seconds), then returns { event, timestamp, data }. verifyWebhookSignature(payload, header, secret, timestamp) is the lower-level check. See Webhooks.