Webhooks
Receive real-time notifications when events occur in your Propper account.
Setting Up Webhooks
- Go to Settings → Webhooks in your dashboard
- Click Add Endpoint
- Enter your endpoint URL
- Select the events you want to receive
- Save and copy your signing secret
Webhook Payload
{
"id": "8f1a6c2e-4b7d-4a91-9c3e-2d5f8b0a7e14",
"type": "agreement.recipient_signed",
"version": 1,
"occurredAt": "2026-01-15T10:30:12.481Z",
"orgId": "3c9d1e77-2a45-4f68-b0c1-9e7a4d2b6f83",
"source": "sign-api",
"data": {
"orgId": "3c9d1e77-2a45-4f68-b0c1-9e7a4d2b6f83",
"agreementId": "b2e4f915-7c8a-4d13-9f60-1a8c5e3b7d92",
"title": "Service Agreement",
"status": "IN_PROGRESS",
"occurredAt": "2026-01-15T10:30:12.481Z",
"recipient": {
"id": "d7c3a018-5f2b-4e96-8a41-6b0d9c2e5f37",
"email": "signer@propper.ai",
"name": "Jordan Lee",
"role": "SIGNER",
"order": 1
}
}
}
Every event shares the envelope fields id, type, version, occurredAt, orgId, source, and data. The data fields depend on the event type; see Sign Webhooks for each agreement event.
Verifying Signatures
All webhooks include a signature header for verification:
X-Propper-Signature: sha256=abc123...
import crypto from 'crypto';
function verifyWebhook(payload: string, signature: string, secret: string): boolean {
const expected = crypto.createHmac('sha256', secret).update(payload).digest('hex');
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(`sha256=${expected}`));
}
Event Types
Sign Events
| Event | Description |
|---|---|
agreement.created | An agreement was created |
agreement.sent | The agreement was sent to its recipients |
agreement.delivered | Every recipient's invitation email was delivered (not sent for every agreement) |
agreement.viewed | A recipient opened the agreement for the first time |
agreement.recipient_signed | A recipient finished signing |
agreement.completed | Every recipient finished and the signed document is ready |
agreement.declined | A recipient declined to sign |
agreement.voided | The agreement was voided |
agreement.recalled | The sender recalled the agreement for editing, returning it to draft |
agreement.expired | The agreement expired before it was completed |
Click Events
| Event | Description |
|---|---|
click.acceptance.completed | An acceptance is recorded and its evidence is complete |
click.evidence.created | The evidence record for an acceptance is created |
click.evidence.signed | The evidence record is signed |
click.evidence.failed | Evidence could not be produced; the acceptance itself is still recorded |
Retry Policy
Failed webhook deliveries are retried with exponential backoff:
- 1st retry: 1 minute
- 2nd retry: 5 minutes
- 3rd retry: 30 minutes
- 4th retry: 2 hours
- 5th retry: 24 hours
After 5 failed attempts, the endpoint is disabled and you'll be notified.