Get more events through the API

Webhooks made in the app only cover document statuses. Through the API, your system can also hear about new contacts, form submissions, payments, comments and more.

Before you start

You need a working connection: an OAuth client and an access token for it. To try things out first, test credentials work for everything on this page. You also need an https address in your system that can receive the data.

What you can subscribe to

Each event needs a permission, called a scope. If you chose scopes for your OAuth client, make sure it includes the one listed here.

contactCreated
A contact is added. Needs webhooks:contact_created.
contactUpdated, contactRemoved
A contact is changed or removed. Needs webhooks:contact_changes.
formSubmitted
A recipient submits a form in a document. Needs webhooks:form_submission.
documentPaymentEvent
A payment is received, fails or is refunded. Filter with status: received, failed or refunded. Needs webhooks:document_payments.
documentCommentEvent
A comment is added, resolved or reopened. Filter with status: created, resolved or reopened. Needs webhooks:document_comments.
documentCreated
A document is created. Needs webhooks:document_created.
recipientFirstViewed, recipientSigned
A recipient opens a document for the first time, or signs it. Needs webhooks:recipient_activity.
documentDeliveryStatusChanged
A scheduled or sent email changes state, such as sent or failed. You can filter with status. Needs webhooks:document_delivery.
productChanged
A product is created, updated, activated or deactivated. You can filter with status. Needs webhooks:product_changes.
documentStatusChange
A document reaches the status you name in status, which is required. Needs webhooks:document_status.
  1. Subscribe

    Send the address that should receive the events to Subscribe webhook, with the event name in the path:

    Subscribe to new contacts
    curl -X POST "https://app.quote.cloud/api/v1/triggers/contactCreated/subscribe?client_id=YOUR_CLIENT_ID" \
      -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"hookUrl": "https://yourapp.example.com/webhooks/contacts"}'
    Reply
    {
      "data": { "status": "success", "message": "Webhook created" }
    }

    To only hear about some changes, add status to the address. This one only sends payments that went through:

    Subscribe to received payments
    curl -X POST "https://app.quote.cloud/api/v1/triggers/documentPaymentEvent/subscribe?client_id=YOUR_CLIENT_ID&status=received" \
      -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"hookUrl": "https://yourapp.example.com/webhooks/payments"}'
  2. Check it’s there

    The subscription appears in the webhook list under Manage Integrations on the API dashboard, and each delivery appears in the Events table, the same as a webhook made in the app.

  3. Handle what arrives

    QuoteCloud sends a POST with a JSON body. Every body has an id, which also arrives in the X-QuoteCloud-Event-Id header and stays the same if a delivery is sent again, and an event that says what happened. Reply with a 2xx within 15 seconds.

What gets sent

New contact

This came from a real delivery on a test account.

contactCreated
{
  "id": "contact_created:v178q04f8gaam9vxarqwvgea898hfv9g",
  "event": "contact_created",
  "contactId": "v178q04f8gaam9vxarqwvgea898hfv9g",
  "email": "jamie.lee@example.com",
  "firstName": "Jamie",
  "lastName": "Lee",
  "fullName": "Jamie Lee",
  "phone": null,
  "mobile": null,
  "jobTitle": "Travel manager",
  "address": null,
  "createdAt": "2026-11-02T11:05:48.645Z"
}

Form submission

The body only says which form was submitted. To get the answers, pass submissionId to the form submission endpoint.

formSubmitted
{
  "id": "form_submission:n58c2v7x4k1q9w3e",
  "event": "form_submission",
  "submissionId": "n58c2v7x4k1q9w3e",
  "documentId": "k57c9m2x8e4t1r6w",
  "recipientId": "p24h8j6l1m9b3d7f",
  "submittedAt": "2026-11-02T04:15:00.000Z",
  "valueCount": 6
}

Payment

Amounts are in the smallest unit of the currency, so 125000 in AUD is $1,250.00. failureCode and failureMessage are only filled in when a payment fails.

documentPaymentEvent
{
  "id": "document_payment_event:evt_3Q1example",
  "event": "document_payment_event",
  "paymentEvent": "received",
  "transactionId": "t81r4e6w2q9y5u3i",
  "transactionRef": "TX-1042",
  "documentId": "k57c9m2x8e4t1r6w",
  "documentRef": "1042",
  "documentTitle": "Japan in spring",
  "documentStatus": "paid",
  "recipientId": "p24h8j6l1m9b3d7f",
  "providerPaymentRef": "pi_3Q1example",
  "amountMinor": 125000,
  "refundTotalMinor": 0,
  "currency": "AUD",
  "status": "succeeded",
  "payerEmail": "jamie.lee@example.com",
  "failureCode": null,
  "failureMessage": null,
  "occurredAt": "2026-11-02T04:15:00.000Z"
}

Comment

commentEvent says whether the comment was created, resolved or reopened.

documentCommentEvent
{
  "id": "document_comment_event:c63v9b2n5m8k1j4h:created:1793592900000",
  "event": "document_comment_event",
  "commentEvent": "created",
  "commentId": "c63v9b2n5m8k1j4h",
  "commentRef": "17",
  "documentId": "k57c9m2x8e4t1r6w",
  "documentRef": "1042",
  "documentTitle": "Japan in spring",
  "documentStatus": "opened",
  "body": "Can we add a night in Kyoto?",
  "status": "open",
  "authorId": "p24h8j6l1m9b3d7f",
  "authorName": "Jamie Lee",
  "authorEmail": "jamie.lee@example.com",
  "createdAt": "2026-11-02T04:15:00.000Z",
  "updatedAt": "2026-11-02T04:15:00.000Z",
  "resolvedAt": null
}

The IDs and values in the last three are made up. Every field is described under Subscribe webhook.

Stop an event

Call Unsubscribe webhook with the same event, address and status you subscribed with:

Unsubscribe
curl -X DELETE "https://app.quote.cloud/api/v1/triggers/contactCreated/unsubscribe?client_id=YOUR_CLIENT_ID" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"hookUrl": "https://yourapp.example.com/webhooks/contacts"}'

Subscribing the same address again turns it back on. Deliveries that fail follow the same rules as any other webhook, so a 4xx reply switches it off. Here’s how to fix that.