Sign Webhooks
Receive real-time notifications when signing events occur instead of polling the API.
Why Use Webhooks?
| Approach | Pros | Cons |
|---|---|---|
| Polling | Simple to implement | Wastes API calls, delayed updates |
| Webhooks | Real-time, efficient | Requires public endpoint |
Webhooks eliminate polling, reduce API usage, and provide instant updates.
Setup
1. Configure Webhook Endpoint
In the Propper Dashboard:
- Go to Settings → Webhooks
- Click Add Endpoint
- Enter your webhook URL (must be HTTPS)
- Select events to subscribe to
- Copy the webhook secret for signature verification
2. Create Your Handler
Your endpoint must:
- Accept POST requests
- Respond with 2xx status within 30 seconds
- Verify the webhook signature
- Handle events idempotently
Event Types
| Event | When it fires | data.status |
|---|---|---|
agreement.created | An agreement is created through the API, in the dashboard, or from a template. Creating an envelope with status: "sent" sends agreement.created and then agreement.sent. | CREATED |
agreement.sent | The agreement is sent to its recipients. | SENT |
agreement.delivered | Every recipient's invitation email is confirmed delivered while the agreement is still SENT. Sent at most once per agreement (see the note below). | DELIVERED |
agreement.viewed | A recipient opens the agreement for the first time. Sent once per recipient. | Unchanged |
agreement.recipient_signed | A recipient finishes signing. Sent once per signer. | Unchanged (usually IN_PROGRESS) |
agreement.completed | Every recipient has finished their part and the signed document is ready to download. | COMPLETED |
agreement.declined | A recipient declines to sign. This ends the agreement for every recipient. | DECLINED |
agreement.voided | The agreement is voided (cancelled). | VOIDED |
agreement.recalled | The sender recalls a sent agreement for editing before anyone has signed. It returns to draft and can be edited and sent again. | CREATED |
agreement.expired | The agreement passes its expiration date before it is completed. | EXPIRED |
Not every agreement sends agreement.delivered
It waits until every recipient's invitation email is confirmed delivered, and is skipped once signing has started. With sequential routing, later recipients are not invited until earlier ones sign, so the event is not sent. Track progress with agreement.viewed and agreement.recipient_signed rather than waiting for agreement.delivered.
Propper Click sends click.* events (click.acceptance.completed, click.evidence.created, click.evidence.signed, click.evidence.failed) to the same endpoints. See Verifying webhook signatures for those.