# Agree.com Webhooks API

**Canonical:** https://apis.io/apis/agree-com/agree-com-webhooks-api/  
**Provider:** Agree.com — https://apis.io/providers/agree-com/  
**Base URL:** https://secure.agree.com/api/v1  
**Documentation:** https://secure.agree.com/documentation

Agree.com Webhooks API is one of 6 APIs that [Agree.com](https://apis.io/providers/agree-com/) publishes on the [APIs.io](https://apis.io/) network, described by a machine-readable OpenAPI specification and an AsyncAPI event-driven specification. Tagged areas include Webhook. The published artifact set on APIs.io includes an OpenAPI specification, API documentation, an API reference, a getting-started guide, authentication docs, and an AsyncAPI specification.

Receive real-time notifications when events occur in your Agree account. ## Overview Webhooks push event data to your application as soon as something happens - like when an invoice is paid or a payment fails. This eliminates the need to poll the API for updates and lets you respond to events instantly. **Key concepts:** - You register a URL endpoint that Agree will call when events occur - Each endpoint can subscribe to specific event types - Webhook payloads are signed so you can verify they came from Agree - Failed deliveries are automatically retried with exponential backoff ## Quick Setup ### 1. Create an Endpoint Register a URL to receive webhooks: ```bash curl -X POST https://api.agree.com/api/v1/webhook_endpoints \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "webhook_endpoint": { "url": "https://your-app.com/webhooks/agree", "events": ["invoice.paid", "invoice.failed"] } }' ``` **Response:** ```json { "data": { "id": "550e8400-e29b-41d4-a716-446655440000", "url": "https://your-app.com/webhooks/agree", "events": ["invoice.paid", "invoice.failed"], "active": true, "failure_count": 0, "secret": "whsec_abc123xyz789...", "inserted_at": "2025-01-15T10:30:00Z", "updated_at": "2025-01-15T10:30:00Z" } } ``` **Important:** Save the `secret` - it's only returned once at creation. You'll need it to verify webhook signatures. ### 2. Handle Incoming Webhooks When an event occurs, Agree sends a POST request to your endpoint: ```json { "event": "invoice.paid", "payload": { "id": "4a755746-ba45-4226-a669-aebc7ad3719c", "status": "paid", "amount": {"amount": 15000, "currency": "USD"}, "paid_at": "2025-01-20T14:30:00Z" } } ``` ### 3. Verify the Signature Always verify webhooks came from Agree before processing them. See [Verifying Webhooks](#verifying-webhooks) below. ### 4. Test Your Integration Send a test webhook to verify your endpoint works: ```bash curl -X POST https://api.agree.com/api/v1/webhook_endpoints/550e8400-e29b-41d4-a716-446655440000/test \ -H "Authorization: Bearer YOUR_API_KEY" ``` ## Available Events Subscribe to the events your application needs: | Event | Description | When it fires | |-------|-------------|---------------| | `invoice.created` | Invoice was created | After POST /invoices | | `invoice.sent` | Invoice emailed to customer | When delivery completes | | `invoice.due` | Invoice reached due status | When status becomes `due`: either the scheduled job runs after `sent` (past `due_at`), or the invoice is sent already at/past `due_at` (immediate `due`) | | `invoice.paid` | Payment successful | After payment confirmation | | `invoice.failed` | Payment attempt failed | After payment rejection | | `invoice.canceled` | Invoice was canceled | After DELETE /invoices | | `invoice.refunded` | Invoice payment was refunded | After refund is processed | | `agreement.created` | Agreement was created | After POST /agreements | | `agreement.sent` | Agreement was sent to recipients | When status changes to 'sent' | | `agreement.signed` | Agreement was signed by a recipient | When a recipient signs | | `agreement.executed` | Agreement was fully executed | When all signers have signed | | `webhook.test` | Test event | When you trigger a test | **Tip:** Start with `invoice.paid` and `invoice.failed` - these are the most important for payment integrations. ## Webhook Payload Each webhook request includes: ### Headers | Header | Description | |--------|-------------| | `Content-Type` | `application/json` | | `X-Webhook-Signature` | HMAC-SHA256 signature (hex, lowercase) | | `X-Webhook-Timestamp` | Unix timestamp when sent | ### Body ```json { "event": "invoice.paid", "payload": { // Full invoice object with all fields } } ``` The `payload` contains the complete resource object, so you have all the data you need without making additional API calls. For agreement events (`agreement.created`, `agreement.sent`, `agreement.signed`, `agreement.executed`), the payload includes the `GET /api/v1/agreements/:id` response `data` fields — including flat recipient fields such as `recipients[].email` and `recipients[].name`, and `field_values` (a map of `field_id` to filled plain-text values). Webhooks also include nested `recipients[].user` and `recipients[].contact` objects for backwards compatibility; prefer the flat fields for new integrations. ## Verifying Webhooks **Always verify webhook signatures** before processing. This ensures the request actually came from Agree and wasn't tampered with. ### How Verification Works 1. Get the raw request body (before JSON parsing) 2. Compute HMAC-SHA256 using your endpoint's `secret` as the key 3. Hex-encode the result (lowercase) 4. Compare to the `X-Webhook-Signature` header using constant-time comparison ### Node.js Example ```javascript const crypto = require('crypto'); function verifyWebhookSignature(rawBody, signatureHeader, secret) { const expectedSignature = crypto .createHmac('sha256', secret) .update(rawBody) .digest('hex'); return crypto.timingSafeEqual( Buffer.from(expectedSignature), Buffer.from(signatureHeader) ); } // Express middleware example app.post('/webhooks/agree', express.raw({type: 'application/json'}), (req, res) => { const signature = req.headers['x-webhook-signature']; if (!verifyWebhookSignature(req.body, signature, process.env.AGREE_WEBHOOK_SECRET)) { return res.status(401).send('Invalid signature'); } const event = JSON.parse(req.body); switch (event.event) { case 'invoice.paid': // Handle successful payment break; case 'invoice.failed': // Handle failed payment break; } res.status(200).send('OK'); }); ``` ### Python Example ```python import hmac import hashlib from flask import Flask, request app = Flask(__name__) def verify_webhook_signature(raw_body, signature_header, secret): expected_signature = hmac.new( secret.encode('utf-8'), raw_body, hashlib.sha256 ).hexdigest() return hmac.compare_digest(expected_signature, signature_header) @app.route('/webhooks/agree', methods=['POST']) def handle_webhook(): signature = request.headers.get('X-Webhook-Signature') if not verify_webhook_signature(request.data, signature, AGREE_WEBHOOK_SECRET): return 'Invalid signature', 401 event = request.json if event['event'] == 'invoice.paid': # Handle successful payment pass elif event['event'] == 'invoice.failed': # Handle failed payment pass return 'OK', 200 ``` ## Managing Endpoints ### List All Endpoints ```bash curl https://api.agree.com/api/v1/webhook_endpoints \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### Update an Endpoint Change the subscribed events or URL: ```bash curl -X PUT https://api.agree.com/api/v1/webhook_endpoints/550e8400-e29b-41d4-a716-446655440000 \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "webhook_endpoint": { "events": ["invoice.paid", "invoice.failed", "invoice.created"] } }' ``` ### Disable an Endpoint Set `active` to false to temporarily stop receiving webhooks: ```bash curl -X PUT https://api.agree.com/api/v1/webhook_endpoints/550e8400-e29b-41d4-a716-446655440000 \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "webhook_endpoint": { "active": false } }' ``` ### Delete an Endpoint ```bash curl -X DELETE https://api.agree.com/api/v1/webhook_endpoints/550e8400-e29b-41d4-a716-446655440000 \ -H "Authorization: Bearer YOUR_API_KEY" ``` ## Retry Policy If your endpoint returns a non-2xx status code or times out, Agree automatically retries: | Attempt | Delay | |---------|-------| | 1 | Immediate | | 2 | ~1 minute | | 3 | ~5 minutes | | 4 | ~30 minutes | | 5 | ~2 hours | After 5 failed attempts, the webhook is marked as failed and the endpoint's `failure_count` is incremented. **Tip:** Monitor `failure_count` to detect integration issues. If it keeps increasing, check your endpoint's logs. ## Best Practices 1. **Respond quickly** - Return 200 within 5 seconds, then process asynchronously 2. **Handle duplicates** - Webhooks may occasionally be sent more than once; use idempotency 3. **Verify signatures** - Never skip verification in production 4. **Use HTTPS** - Required in production for security 5. **Log everything** - Store webhook payloads for debugging and auditing ## Fields Reference | Field | Type | Description | |-------|------|-------------| | `id` | UUID | Unique endpoint identifier | | `url` | string | Your webhook URL (HTTPS required in production) | | `events` | array | Event types this endpoint receives | | `active` | boolean | Whether the endpoint is receiving webhooks | | `failure_count` | integer | Consecutive failed deliveries | | `secret` | string | Signing secret (only returned on creation) | | `inserted_at` | datetime | When the endpoint was created | | `updated_at` | datetime | When the endpoint was last modified |

## Operations (7)

| Method | Path | Summary |
|---|---|---|
| GET | `/api/v1/webhooks` | List webhook endpoints |
| POST | `/api/v1/webhooks` | Create webhook endpoint |
| DELETE | `/api/v1/webhooks/{id}` | Delete webhook endpoint |
| GET | `/api/v1/webhooks/{id}` | Get webhook endpoint |
| PATCH | `/api/v1/webhooks/{id}` | Update webhook endpoint |
| PUT | `/api/v1/webhooks/{id}` | Update webhook endpoint |
| POST | `/api/v1/webhooks/test` | Send test webhook |

## Machine-readable artifacts (11)

- **OpenAPI** — https://raw.githubusercontent.com/api-evangelist/agree-com/refs/heads/main/openapi/agree-com-webhooks-api-openapi.yml
- **Documentation** — https://secure.agree.com/documentation
- **APIReference** — https://secure.agree.com/documentation
- **GettingStarted** — https://secure.agree.com/documentation#section/Introduction/Quick-Start
- **Authentication** — https://secure.agree.com/documentation#section/Introduction/Authentication
- **ErrorCatalog** — https://raw.githubusercontent.com/api-evangelist/agree-com/refs/heads/main/errors/agree-com-problem-types.yml
- **DataModel** — https://raw.githubusercontent.com/api-evangelist/agree-com/refs/heads/main/data-model/agree-com-data-model.yml
- **Conventions** — https://raw.githubusercontent.com/api-evangelist/agree-com/refs/heads/main/conventions/agree-com-conventions.yml
- **AsyncAPI** — https://raw.githubusercontent.com/api-evangelist/agree-com/refs/heads/main/asyncapi/agree-com-webhooks-asyncapi.yml
- **Webhooks** — https://raw.githubusercontent.com/api-evangelist/agree-com/refs/heads/main/asyncapi/agree-com-webhooks-asyncapi.yml
- **ToolCrosswalk** — https://raw.githubusercontent.com/api-evangelist/agree-com/refs/heads/main/mcp/agree-com-tool-crosswalk.yml

## Other Agree.com APIs (5)

- [Agree.com Agreements API](https://apis.io/apis/agree-com/agree-com-agreements-api/)
- [Agree.com Contacts API](https://apis.io/apis/agree-com/agree-com-contacts-api/)
- [Agree.com Customers API](https://apis.io/apis/agree-com/agree-com-customers-api/)
- [Agree.com Invoices API](https://apis.io/apis/agree-com/agree-com-invoices-api/)
- [Agree.com Reports API](https://apis.io/apis/agree-com/agree-com-reports-api/)

## Tags

Webhook

---

Profiled by [API Evangelist](https://apievangelist.com) and published on [APIs.io](https://apis.io/apis/agree-com/agree-com-webhooks-api/). The API's provider profile, Kin Score and agent-readiness rating are at https://apis.io/providers/agree-com/.
