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.
webhooks:contact_created.webhooks:contact_changes.webhooks:form_submission.webhooks:document_payments.webhooks:document_comments.webhooks:document_created.webhooks:recipient_activity.webhooks:document_delivery.webhooks:product_changes.webhooks:document_status.Subscribe
Send the address that should receive the events to Subscribe webhook, with the event name in the path:
Subscribe to new contactscurl -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
statusto the address. This one only sends payments that went through:Subscribe to received paymentscurl -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"}'
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.
Handle what arrives
QuoteCloud sends a
POSTwith a JSON body. Every body has anid, which also arrives in theX-QuoteCloud-Event-Idheader and stays the same if a delivery is sent again, and aneventthat says what happened. Reply with a2xxwithin 15 seconds.
What gets sent
New contact
This came from a real delivery on a test account.
{
"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.
{
"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.
{
"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.
{
"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:
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.