API v1 — Stable

Developer API

Send documents for e-signature, embed signing UIs, and automate workflows. The easiest way to add legally binding signatures to your app.

Getting Started

1

Create an account

Sign up free at signforge.io/register

2

Generate an API key

Go to Dashboard → Developers and create a live or test key.

3

Make your first request

Send a document for signing with a single API call:

bash
curl -X POST https://signforge.io/api/v1/quick-sign \
  -H "X-API-Key: sf_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "NDA Agreement",
    "pdf_base64": "<base64-encoded-pdf>",
    "signer_email": "jane@example.com",
    "signer_name": "Jane Doe"
  }'

Authentication

All V1 API endpoints authenticate via the X-API-Key header.

Live keys

Prefix: sf_live_

Create real envelopes, send emails, consume quota.

Test keys

Prefix: sf_test_

Sandbox mode — watermarked PDFs, no emails sent, no quota consumed.

Endpoints Reference

Envelopes

POST/api/v1/envelopesCreate envelope
POST/api/v1/envelopes/{id}/sendSend for signing
GET/api/v1/envelopes/{id}Get status
GET/api/v1/envelopesList envelopes
GET/api/v1/envelopes/{id}/documents/{kind}Download PDF
POST/api/v1/envelopes/{id}/voidVoid envelope
DELETE/api/v1/envelopes/{id}Delete
POST/api/v1/quick-signOne-call sign
POST/api/v1/envelopes/{id}/embed-urlGet embed URL

Webhooks

POST/api/v1/webhooksRegister
GET/api/v1/webhooksList
DELETE/api/v1/webhooks/{id}Delete
GET/api/v1/webhooks/{id}/deliveriesDelivery log

Quick Sign

The fastest way to get a document signed. One call creates the envelope, uploads the PDF, adds the signer, and sends the signing email.

python
import requests, base64

with open("contract.pdf", "rb") as f:
    pdf_b64 = base64.b64encode(f.read()).decode()

response = requests.post(
    "https://signforge.io/api/v1/quick-sign",
    headers={"X-API-Key": "sf_live_YOUR_KEY"},
    json={
        "title": "Service Agreement",
        "pdf_base64": pdf_b64,
        "signer_email": "client@company.com",
        "signer_name": "Alex Chen",
    },
)

data = response.json()
print(f"Envelope: {data['envelope_id']}")
print(f"Status: {data['status']}")

Webhooks

Get real-time notifications when envelopes change state. All webhook payloads are signed with HMAC-SHA256.

Events

envelope.sent

Envelope sent for signing

envelope.viewed

Recipient opened document

envelope.signed

Recipient completed signing

envelope.completed

All recipients signed

envelope.voided

Sender voided the envelope

envelope.expired

Envelope reached expiry

Payload Format

json
{
  "event": "envelope.completed",
  "envelope_id": "550e8400-e29b-41d4-a716-446655440000",
  "timestamp": "2026-03-25T12:00:00Z",
  "data": {
    "title": "Service Agreement",
    "status": "completed",
    "recipients": [
      {
        "email": "signer@example.com",
        "name": "Jane Doe",
        "status": "signed",
        "signed_at": "2026-03-25T11:59:00Z"
      }
    ],
    "download_urls": {
      "signed": "/api/v1/envelopes/{id}/documents/signed",
      "certificate": "/api/v1/envelopes/{id}/documents/certificate"
    }
  }
}

HMAC Verification

javascript
const crypto = require("crypto");

function verifyWebhook(body, signature, secret) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(body)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature)
  );
}

// In your Express handler:
app.post("/webhook", (req, res) => {
  const sig = req.headers["x-webhook-signature"];
  if (!verifyWebhook(req.rawBody, sig, WEBHOOK_SECRET)) {
    return res.status(401).send("Invalid signature");
  }
  const event = req.body;
  console.log("Event:", event.event, event.envelope_id);
  res.sendStatus(200);
});

Rate Limits & Quotas

PlanAPI Envelopes / MonthRate Limit
Free560 req/min
Pro10060 req/min
Business50060 req/min
EnterpriseUnlimitedCustom

Test/sandbox keys are exempt from monthly quotas but still subject to rate limits.

Error Codes

CodeMeaning
400Invalid request — check the request body
401Missing or invalid API key
403Account suspended or feature not available
404Resource not found
422Validation error — details in response
429Rate limit or quota exceeded
500Internal server error

Embed Widget

Embed signing UIs in your app with an iframe and JS SDK.

MCP Server

Use SignForge from Claude Desktop and AI agents.

Code Examples

Integration samples for n8n, Retool, cURL, and more.