Paddock20

Developers

Send agreements and follow them from your own app. Create a key under Settings, then call the API at /api/sign/v1.

Authentication

Send your key as a Bearer token. A key belongs to one company and can only see that company's agreements.

Authorization: Bearer p20s_xxxxxxxxxxxx.yyyyyyyyyyyyyyyyyyyyyyyy

Send an agreement

POST /api/sign/v1/envelopes
{
  "title": "Authorization letter",
  "pdf_base64": "<the PDF, base64>",
  "signers": [
    { "role": "client", "name": "Pat Owner", "email": "pat@example.com" },
    { "role": "countersign", "name": "Gavin Brooks", "email": "gavin@paddock20.com" }
  ],
  "client_ref": "your-record-id",      // optional: how your system knows this client
  "message": "Please sign by Friday"   // optional
}
→ 201 { "id": "...", "number": "P2-1001" }

The agreement is created as a draft. Place the signature fields on the agreement page, then send it, or call POST /envelopes/{id}/send. Up to 10 signers and 15 MB per PDF.

Other calls

Webhooks

Add an https address under Settings and choose the events: sent, viewed, signed, completed, declined, voided, expired. Each delivery is signed with your webhook's secret in a Sign-Signature header. Check it, and reject anything older than five minutes.

import { createHmac, timingSafeEqual } from "node:crypto";

function verify(secret, rawBody, header) {
  const m = /^t=(\d+),v1=([0-9a-f]{64})$/.exec(header ?? "");
  if (!m || Math.abs(Date.now() / 1000 - Number(m[1])) > 300) return false;
  const want = createHmac("sha256", secret).update(m[1] + "." + rawBody).digest("hex");
  return timingSafeEqual(Buffer.from(want), Buffer.from(m[2]));
}

Connect Pole Keeper

Create an API key named Pole Keeper and a webhook for envelope.completed pointing at your Pole Keeper address. When it fires, read the client reference from the event, fetch the signed PDF with GET /envelopes/{id}/files/signed, and attach it to that client's record. Send agreements from Pole Keeper the same way, with the client's record id in client_ref.