Agree.com Webhooks API

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

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 #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/agree-com-webhooks-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

agree-com-webhooks-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  description: '# Introduction


    Welcome to the Agree API!'
  title: Agree Webhooks API
  version: 1.0.0
servers:
- url: https://secure.agree.com
  variables: {}
security: []
tags:
- description: Receive real-time notifications when events occur in your Agree account.
  name: Webhooks
paths:
  /api/v1/webhooks:
    get:
      callbacks: {}
      description: Returns all webhook endpoints for the authenticated organization.
      operationId: AgreeWeb.API.V1.WebhookEndpointController.index
      parameters: []
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookEndpointsResponse'
          description: Webhook endpoints list
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Unauthorized'
          description: Unauthorized
      security:
      - bearer: []
      summary: List webhook endpoints
      tags:
      - Webhooks
    post:
      callbacks: {}
      description: 'Creates a new webhook endpoint for the authenticated organization.


        **Important:** The signing `secret` is only returned once in the response when the endpoint is created.

        Store it securely as it cannot be retrieved again.


        Use the secret to verify webhook signatures by computing an HMAC-SHA256 of the request body

        and comparing it to the `X-Agree-Signature` header.'
      operationId: AgreeWeb.API.V1.WebhookEndpointController.create
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookEndpointParams'
        description: Webhook endpoint params
        required: false
      responses:
        '201':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookEndpointCreatedResponse'
          description: Webhook endpoint created
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Unauthorized'
          description: Unauthorized
        '422':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: Validation errors
      security:
      - bearer: []
      summary: Create webhook endpoint
      tags:
      - Webhooks
  /api/v1/webhooks/{id}:
    delete:
      callbacks: {}
      description: Deletes a webhook endpoint by ID.
      operationId: AgreeWeb.API.V1.WebhookEndpointController.delete
      parameters:
      - description: Webhook endpoint ID (UUID)
        in: path
        name: id
        required: true
        schema:
          type: string
      responses:
        '204':
          description: Webhook endpoint deleted
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Unauthorized'
          description: Unauthorized
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFound'
          description: Not found
      security:
      - bearer: []
      summary: Delete webhook endpoint
      tags:
      - Webhooks
    get:
      callbacks: {}
      description: Returns a single webhook endpoint by ID.
      operationId: AgreeWeb.API.V1.WebhookEndpointController.show
      parameters:
      - description: Webhook endpoint ID (UUID)
        in: path
        name: id
        required: true
        schema:
          type: string
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookEndpointResponse'
          description: Webhook endpoint
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Unauthorized'
          description: Unauthorized
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFound'
          description: Not found
      security:
      - bearer: []
      summary: Get webhook endpoint
      tags:
      - Webhooks
    patch:
      callbacks: {}
      description: Updates an existing webhook endpoint.
      operationId: AgreeWeb.API.V1.WebhookEndpointController.update (2)
      parameters:
      - description: Webhook endpoint ID (UUID)
        in: path
        name: id
        required: true
        schema:
          type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookEndpointParams'
        description: Webhook endpoint params
        required: false
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookEndpointResponse'
          description: Webhook endpoint updated
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Unauthorized'
          description: Unauthorized
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFound'
          description: Not found
        '422':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: Validation errors
      security:
      - bearer: []
      summary: Update webhook endpoint
      tags:
      - Webhooks
    put:
      callbacks: {}
      description: Updates an existing webhook endpoint.
      operationId: AgreeWeb.API.V1.WebhookEndpointController.update
      parameters:
      - description: Webhook endpoint ID (UUID)
        in: path
        name: id
        required: true
        schema:
          type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookEndpointParams'
        description: Webhook endpoint params
        required: false
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookEndpointResponse'
          description: Webhook endpoint updated
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Unauthorized'
          description: Unauthorized
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFound'
          description: Not found
        '422':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          description: Validation errors
      security:
      - bearer: []
      summary: Update webhook endpoint
      tags:
      - Webhooks
  /api/v1/webhooks/test:
    post:
      callbacks: {}
      description: 'Sends a test webhook payload to all endpoints subscribed to the `webhook.test` event.


        This is useful for verifying your webhook endpoint is properly configured to receive events.


        The test payload contains:

        ```json

        {

        "test": true,

        "message": "This is a test webhook from Agree",

        "timestamp": "2024-01-15T10:30:00Z"

        }

        ```'
      operationId: AgreeWeb.API.V1.WebhookEndpointController.test
      parameters: []
      responses:
        '202':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookTestResponse'
          description: Test webhooks queued
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Unauthorized'
          description: Unauthorized
        '404':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NotFound'
          description: No endpoints subscribed to webhook.test
      security:
      - bearer: []
      summary: Send test webhook
      tags:
      - Webhooks
components:
  schemas:
    WebhookEndpointCreatedResponse:
      description: Response containing a newly created webhook endpoint with signing secret
      properties:
        data:
          $ref: '#/components/schemas/WebhookEndpointWithSecret'
      required:
      - data
      title: WebhookEndpointCreatedResponse
      type: object
    WebhookTestResponse:
      description: Response after triggering test webhooks
      example:
        data:
          failed: 0
          job_ids:
          - 123
          - 124
          message: Test webhooks have been queued and will be sent shortly
          successful: 2
          total: 2
      properties:
        data:
          properties:
            failed:
              description: Number of failed queue attempts
              type: integer
            job_ids:
              description: IDs of queued webhook delivery jobs
              items:
                type: integer
              type: array
            message:
              description: Status message
              type: string
            successful:
              description: Number of successfully queued webhooks
              type: integer
            total:
              description: Total number of endpoints that received test
              type: integer
          type: object
      required:
      - data
      title: WebhookTestResponse
      type: object
    WebhookEndpoint:
      description: A webhook endpoint configuration
      example:
        active: true
        events:
        - invoice.created
        - invoice.paid
        failure_count: 0
        id: 550e8400-e29b-41d4-a716-446655440000
        inserted_at: '2024-01-15T10:30:00Z'
        updated_at: '2024-01-15T10:30:00Z'
        url: https://example.com/webhooks
      properties:
        active:
          description: Whether the endpoint is active
          type: boolean
        events:
          description: List of event types this endpoint is subscribed to
          items:
            type: string
          type: array
        failure_count:
          description: Number of consecutive delivery failures
          type: integer
        id:
          description: Unique webhook endpoint identifier
          format: uuid
          type: string
        inserted_at:
          description: When the endpoint was created
          format: date-time
          type: string
        updated_at:
          description: When the endpoint was last updated
          format: date-time
          type: string
        url:
          description: URL where webhook events will be sent
          format: uri
          type: string
      required:
      - id
      - url
      - events
      - active
      title: WebhookEndpoint
      type: object
    Unauthorized:
      description: Authentication required or invalid credentials
      example:
        error: Invalid or missing API key
      properties:
        error:
          description: Error message
          type: string
      title: Unauthorized
      type: object
    Error:
      description: Error response with field-specific error messages
      example:
        errors:
          amount:
          - can't be blank
          recurring_options:
          - is invalid
      properties:
        errors:
          additionalProperties:
            items:
              type: string
            type: array
          description: Map of field names to arrays of error messages
          type: object
      title: Error
      type: object
    WebhookEndpointWithSecret:
      description: Webhook endpoint with signing secret (only returned on creation)
      properties:
        active:
          description: Whether the endpoint is active
          type: boolean
        events:
          description: List of event types this endpoint is subscribed to
          items:
            type: string
          type: array
        failure_count:
          description: Number of consecutive delivery failures
          type: integer
        id:
          description: Unique webhook endpoint identifier
          format: uuid
          type: string
        inserted_at:
          description: When the endpoint was created
          format: date-time
          type: string
        secret:
          description: Signing secret for verifying webhook payloads. Only returned once on creation.
          type: string
        updated_at:
          description: When the endpoint was last updated
          format: date-time
          type: string
        url:
          description: URL where webhook events will be sent
          format: uri
          type: string
      required:
      - id
      - url
      - events
      - active
      - secret
      title: WebhookEndpointWithSecret
      type: object
    WebhookEndpointsResponse:
      description: Response containing a list of webhook endpoints
      properties:
        data:
          description: List of webhook endpoints
          items:
            $ref: '#/components/schemas/WebhookEndpoint'
          type: array
      required:
      - data
      title: WebhookEndpointsResponse
      type: object
    WebhookEndpointResponse:
      description: Response containing a single webhook endpoint
      properties:
        data:
          $ref: '#/components/schemas/WebhookEndpoint'
      required:
      - data
      title: WebhookEndpointResponse
      type: object
    WebhookEndpointParams:
      description: Parameters for creating or updating a webhook endpoint
      example:
        webhook_endpoint:
          events:
          - invoice.created
          - invoice.paid
          - invoice.failed
          url: https://example.com/webhooks
      properties:
        webhook_endpoint:
          properties:
            active:
              description: Whether the endpoint should be active
              type: boolean
            events:
              description: List of event types to subscribe to
              items:
                type: string
              type: array
            url:
              description: URL where webhook events will be sent
              format: uri
              type: string
          required:
          - url
          - events
          type: object
      required:
      - webhook_endpoint
      title: WebhookEndpointParams
      type: object
    NotFound:
      description: Resource not found error
      example:
        error: Not found
      properties:
        error:
          description: Error message
          type: string
      title: NotFound
      type: object
  securitySchemes:
    bearer:
      description: API key authentication via Bearer token
      scheme: bearer
      type: http