Build onSignFlow.

The app runs on its own public REST API, so everything you do in SignFlow you can do from code: build templates, send documents, follow every signer.

curl https://signflow-api.leonai.io/api/v1/submissions \
  -H "Authorization: $SIGNFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "template_id": "tpl_abc123",
    "name": "NDA — Acme Corp",
    "signers": [
      { "name": "Dana Levi", "email": "dana@acme.example", "role": "signer1" }
    ],
    "fields_data": { "company_name": "Acme Corp" }
  }'

One request, one signing link

  • One header: your API key in Authorization, with no Bearer prefix.

  • Prefill any field of the template with fields_data.

  • Set signing_order for signers in turn, or leave out the email and deliver the link yourself.

The answer:

201 Created
{
  "data": {
    "id": "…",
    "status": "pending",
    "signing_url": "https://signflow.leonai.io/sign/…",
    "expires_at": "…",
    "signers": [ … ]
  }
}

Know the moment it's signed

  • submission.created
  • submission.sent
  • submission.signed
  • submission.completed
  • submission.declined
  • submission.voided
  • submission.expired
  • submission.payment_completed
  • submission.card_saved
  • submission.payment_failed
  • signer.opened
  • signer.viewed
  • signer.signed
  • signer.declined
  • signer.reminder_sent
  • document.generated
  • document.downloaded

Every delivery is signed with your endpoint's secret. Check it before you trust the body.

  • HTTPS only. Private and loopback addresses are refused.

  • Add your own headers per endpoint, stored encrypted, for a firewall rule to match.

  • A failed delivery is retried automatically, and you can resend it from the delivery log or the API.

import crypto from "node:crypto";

// X-LeonAI-Signature: t=<unix seconds>,v1=<base64 HMAC-SHA256>
export function verifyWebhook(rawBody, header, secret) {
  const parts = Object.fromEntries(
    header.split(",").map((p) => [p.slice(0, p.indexOf("=")), p.slice(p.indexOf("=") + 1)]),
  );
  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${parts.t}.${rawBody}`)
    .digest("base64");
  const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
  return (
    fresh &&
    expected.length === parts.v1?.length &&
    crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1))
  );
}

What the app does, the API does

  • Templates
  • Template Fields
  • Submissions
  • Documents
  • Signer Payments
  • Webhooks
  • Files
  • Organizations
  • Members & Invites
  • Roles & Permissions
  • API Tokens
  • Usage & Credits
  • Audit Log
  • SSO
  • Connect

Or connect it without code

  • Make.com

    A native app: send documents and act on every signature from your scenarios.

  • Priority ERP

    SignFlow Connect links your Priority company to your signing flows.

  • Any system with a URL

    Point a webhook at it and receive every event as signed JSON.

Your first request, today