Agreement Developer API
Integrate e-signatures, AI-generated agreements, and document workflows into your application with our REST API and JavaScript SDK.
🔑 Get an API Key
Sign in, go to Admin → API Keys, and create a key. It starts with agr_.
📦 Install the SDK
Copy agreement-sdk.js into your project or load it from a <script> tag.
🚀 Make a Request
Pass your API key in the X-API-Key header on every request to /api/*.
Authentication
The API supports two authentication methods. API keys are recommended for server-to-server integrations. JWT bearer tokens are used by the web app and can also be used for short-lived access.
API Key (recommended)
Create API keys from Admin → API Keys. Include the key in every request header:
curl https://yourdomain.com/api/agreements \
-H "X-API-Key: agr_your_api_key_here"
Bearer Token (JWT)
Obtain a token via POST /api/auth/login, then pass it as a Bearer token:
curl https://yourdomain.com/api/agreements \
-H "Authorization: Bearer eyJhbGciOiJ..."
POST /api/auth/refresh with your refresh token to get a new pair without re-authenticating.Rate Limits
All API routes are limited to 200 requests per 15 minutes per IP address. Authentication routes have a stricter limit of 15 requests per 15 minutes.
Rate limit headers are included in every response:
| Header | Description |
|---|---|
| RateLimit-Limit | Maximum requests in the window |
| RateLimit-Remaining | Requests remaining in the current window |
| RateLimit-Reset | Unix timestamp when the window resets |
Errors
All errors return a JSON body with success: false and an error message.
{
"success": false,
"error": "Agreement not found"
}
| Status | Meaning |
|---|---|
| 400 | Validation error — check your request body |
| 401 | Missing or invalid credentials |
| 403 | Insufficient permissions for this resource |
| 404 | Resource not found |
| 429 | Rate limit exceeded |
| 500 | Internal server error |
JavaScript / Node.js SDK
The SDK wraps the full REST API in a clean, promise-based interface. It works in both the browser and Node.js.
Installation
<script src="/js/agreement-sdk.js"></script>
curl -O https://yourdomain.com/js/agreement-sdk.js
Quick Start
const client = new AgreementSDK({ apiKey: 'agr_your_key' });
// Create a draft agreement
const { agreement } = await client.agreements.create({
title: 'Contractor NDA — Acme Corp',
content: '<h1>Non-Disclosure Agreement</h1><p>...</p>',
signingOrder: 'parallel',
});
// Add signers
await client.agreements.addRecipient(agreement.id, {
name: 'Jane Smith',
email: 'jane@example.com',
role: 'signer',
});
// Send for signatures
await client.agreements.send(agreement.id);
console.log('Agreement sent!', agreement.id);
AI Generation
const { content } = await client.ai.generate({
prompt: 'NDA between Acme Corp and a freelance developer, 2-year term, California law',
category: 'nda',
});
// Create the agreement with the generated content
const { agreement } = await client.agreements.create({
title: 'AI-Generated NDA',
content,
});
From Template
// List templates
const { data: templates } = await client.templates.list({ category: 'nda' });
// Create a draft from the first matching template
const { agreement } = await client.templates.useAsAgreement(templates[0].id);
Download signed PDF
// In Node.js
const url = client.agreements.downloadUrl(agreement.id);
const resp = await fetch(url, { headers: { 'X-API-Key': 'agr_your_key' } });
const buffer = await resp.arrayBuffer();
require('fs').writeFileSync('signed.pdf', Buffer.from(buffer));
Python
No official Python package yet — use requests directly against the REST API.
import requests
API_KEY = "agr_your_key"
BASE = "https://yourdomain.com/api"
HEADERS = {"X-API-Key": API_KEY, "Content-Type": "application/json"}
# Create agreement
agreement = requests.post(f"{BASE}/agreements", json={
"title": "Contractor NDA",
"content": "<h1>NDA</h1><p>...</p>",
}, headers=HEADERS).json()["agreement"]
# Add recipient
requests.post(f"{BASE}/agreements/{agreement['id']}/recipients", json={
"name": "Jane Smith",
"email": "jane@example.com",
"role": "signer",
}, headers=HEADERS)
# Send
requests.post(f"{BASE}/agreements/{agreement['id']}/send", headers=HEADERS)
print("Sent:", agreement["id"])
Agreements
| Parameter | Type | Description |
|---|---|---|
| page | integer | Page number (default: 1) |
| limit | integer | Results per page (default: 20) |
| status | string | Filter: draft · pending · completed · voided · expired |
| search | string | Search by title |
| Field | Type | Description |
|---|---|---|
| title* | string | Agreement title |
| content | string | HTML body. Use <!-- PAGEBREAK --> to split pages |
| signingOrder | string | parallel (default) or sequential |
| expirationDate | date | ISO 8601 date (YYYY-MM-DD) |
| reminderDays | integer | Days between auto-reminders (1, 3, or 7) |
| message | string | Message included in the signing email |
Transitions the agreement from draft → pending and dispatches signing emails to all recipients. Requires at least one signer recipient to be added first.
Returns the PDF binary. Available for both authenticated users (JWT/API key) and recipients via ?token= query parameter.
Recipients
| Field | Type | Description |
|---|---|---|
| name* | string | Full name |
| email* | string | Email address |
| role | string | signer · approver · cc · viewer |
| signingOrder | integer | Position in sequential signing order |
Signature Fields
Replace all signature/form fields on the agreement. Accepts an array of field objects:
| Field | Type | Description |
|---|---|---|
| fieldId* | string | Unique ID for this field |
| type* | string | signature · initials · date · text · checkbox · company · title · email · phone · dropdown · radio |
| recipientId* | uuid | Assigned recipient |
| x, y | number | Position in pixels (relative to page) |
| width, height | number | Size in pixels |
| pageNumber | integer | Page the field appears on (1-indexed) |
| required | boolean | Whether the field must be filled |
Templates
| Parameter | Type | Description |
|---|---|---|
| category | string | Filter by category (nda, employment, service, …) |
| search | string | Search by name |
Creates a new draft agreement pre-populated with the template's content and field layout. Returns the new agreement object.
AI
All AI endpoints require authentication. Results are also logged to your AI history for billing and audit purposes.
| Field | Type | Description |
|---|---|---|
| prompt* | string | Plain-English description of what you need |
| category | string | nda · employment · contractor · service · saas · real_estate · partnership · purchase · privacy · terms |
| agreementId | uuid | Attach the result to an existing agreement |
Returns content (HTML string), tokensUsed, and model.
Analyzes HTML agreement content and returns annotated HTML with <span class="risk-high">, risk-medium, and risk-low annotations.
| Field | Type | Description |
|---|---|---|
| content* | string | HTML or plain text of the agreement |
Webhooks
Agreement delivers webhook events to your HTTPS endpoint via POST. Each request is signed with HMAC-SHA256 for verification.
Signature verification
const crypto = require('crypto');
function verifyWebhook(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// Express example
app.post('/webhooks/agreement', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.headers['x-agreement-sig'];
if (!verifyWebhook(req.body, sig, process.env.WEBHOOK_SECRET)) {
return res.status(401).end();
}
const event = JSON.parse(req.body);
console.log('Event:', event.event, event.agreementId);
res.status(200).end();
});
Request headers
| Header | Description |
|---|---|
| X-Agreement-Event | Event type (e.g. agreement.completed) |
| X-Agreement-Sig | HMAC-SHA256 hex signature of the raw JSON body |
| X-Agreement-ID | Agreement UUID |
| Content-Type | application/json |
Events
Payload structure
{
"event": "agreement.completed",
"agreementId": "a1b2c3d4-...",
"timestamp": "2025-05-20T14:32:00Z",
"data": {
"id": "a1b2c3d4-...",
"title": "Contractor NDA",
"status": "completed",
"completedAt": "2025-05-20T14:32:00Z",
"recipients": [
{ "name": "Jane Smith", "email": "jane@example.com", "status": "signed" }
]
}
}
| Field | Type | Description |
|---|---|---|
| name* | string | Descriptive name |
| url* | string | Your HTTPS endpoint URL |
| events* | string[] | Array of event types to subscribe to |