Receive real-time HTTP notifications when signing events occur in your Agreements.ai account. Automate your workflows by integrating with your existing systems.
All webhook payloads follow this structure:
{
"event": "signing.completed",
"timestamp": "2026-02-10T12:00:00Z",
"data": {
"documentId": "abc123",
"documentTitle": "Employment Agreement",
"signers": [
{
"name": "John Doe",
"email": "john@example.com",
"status": "signed",
"signedAt": "2026-02-10T12:00:00Z"
}
],
"completedAt": "2026-02-10T12:00:00Z"
}
}| Event | Description |
|---|---|
| signing.sent | Triggered when a document is sent for signing. |
| signing.completed | Triggered when all signers have completed signing. |
| signing.voided | Triggered when the sender voids a signing request. |
| signing.declined | Triggered when a signer declines to sign. |
| signing.opened | Triggered when a signer opens the signing link. |
| signing.reminder_sent | Triggered when a reminder email is sent to a signer. |
Every webhook request includes an X-Agreements-Signature header containing an HMAC-SHA256 hex digest of the request body, signed with your secret key. Always verify this signature to ensure the request is authentic.
const crypto = require('crypto');
function verifyWebhook(body, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(body)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// Express.js example
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-agreements-signature'];
if (!verifyWebhook(req.body, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(req.body);
// Handle event...
res.status(200).send('OK');
});import hmac
import hashlib
def verify_webhook(body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode(),
body,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)
# Flask example
@app.route('/webhook', methods=['POST'])
def webhook():
signature = request.headers.get('X-Agreements-Signature')
if not verify_webhook(request.data, signature, WEBHOOK_SECRET):
return 'Invalid signature', 401
event = request.json
# Handle event...
return 'OK', 200Programmatically create and manage signing envelopes. Authenticate with an API key from Settings → API Keys.
Include your API key in the Authorization header:
Authorization: Bearer sk_your_api_key_here/api/v1/envelopes— Create & send envelope{
"documentId": "abc123",
"signers": [
{ "id": "signer-1", "label": "Tenant", "name": "John Doe", "email": "john@example.com" },
{ "id": "signer-2", "label": "Any Approver", "name": "Jane", "email": "jane@example.com",
"group": "approvers", "groupLabel": "Any Approver" }
],
"fields": [
{ "id": "field-1", "type": "signature", "signerId": "signer-1", "label": "Tenant Signature" }
],
"options": {
"signingOrder": "parallel",
"message": "Please sign this lease",
"expiresAt": "2026-03-01T00:00:00Z"
}
}/api/v1/envelopes— List envelopesQuery params: ?status=pending&limit=20
/api/v1/envelopes/:id— Get envelope details/api/v1/envelopes/:id— Void envelopecurl -X POST https://www.agreements.ai/api/v1/envelopes \
-H "Authorization: Bearer sk_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"documentId": "abc123",
"signers": [{ "id": "s1", "label": "Client", "name": "John", "email": "john@example.com" }],
"fields": [{ "id": "f1", "type": "signature", "signerId": "s1", "label": "Signature" }]
}'Streamline your legal workflow with AI-powered contract analysis and creation. Upload, analyze, and create contracts in minutes.