Webhooks
In this guide, we will look at how to register and consume webhooks to integrate your app with Crater. With webhooks, your app can know when something happens in Crater, such as an invoice is created or an estimate is accepted.
Registering webhooks
To register a new webhook, you need to have a URL in your app that Crater can call. You can configure a new webhook from the Crater dashboard under Settings -> Webhooks. Give your webhook a name, pick the events you want to listen for, and add your URL.
Now, whenever something of interest happens in your app, a webhook is fired off by Crater. In the next section, we'll look at how to consume webhooks.
Consuming webhooks
When your app receives a webhook request from Crater, check the event
attribute to see what event caused it. The first part of the event type will tell you the payload type, e.g., a invoice, estimate, etc.
Example webhook payload
{
"event": "invoice.updated",
"payload": {
"id": "9ab218ee-8e19-4007-aa4d-4c747236ed06"
// ...
}
}
In the example above, a invoice was updated
, and the payload type is a invoice
.
Event types
- Name
business.created
- Type
- Field Type
- Description
Occurs when a new business entity is added to the platform, necessitating the entry of details such as business name, contact information, and address.
- Name
business.updated
- Type
- Field Type
- Description
Occurs when any details of an existing business entity’s profile are modified, which may include changes in contact details, address updates, or alterations to business identification information.
- Name
customer.created
- Type
- Field Type
- Description
Occurs when a new customer entity is added to the business, necessitating the entry of details such as customer name, contact information, and address.
- Name
customer.updated
- Type
- Field Type
- Description
Occurs when any details of an existing customer entity’s profile are modified, which may include changes in customer name, contact information.
- Name
vendor.created
- Type
- Field Type
- Description
Occurs when a new vendor entity is added to the business, necessitating the entry of details such as vendor name, contact information, and address.
- Name
vendor.updated
- Type
- Field Type
- Description
Occurs when any details of an existing vendor entity’s profile are modified, which may include changes in vendor name, contact information.
- Name
estimate.created
- Type
- Field Type
- Description
Occurs upon the creation of a new financial estimate, which outlines the projected costs for products or services proposed to a customer.
- Name
estimate.updated
- Type
- Field Type
- Description
Occurs when changes are made to the details of an existing estimate, potentially involving adjustments to pricing, quantities, or item descriptions.
- Name
estimate.approved
- Type
- Field Type
- Description
Occurs when a client has given formal approval to a financial estimate, indicating readiness to proceed with the proposed terms.
- Name
estimate.converted
- Type
- Field Type
- Description
Occurs when an approved financial estimate is converted into a formal invoice, initiating the billing cycle.
- Name
estimate.rejected
- Type
- Field Type
- Description
Occurs when a client declines a financial estimate, suggesting a need for further negotiation or revision of the proposed terms.
- Name
estimate.sent
- Type
- Field Type
- Description
Occurs when a financial estimate is dispatched to a client, typically indicating the commencement of the approval workflow.
- Name
estimate.status.updated
- Type
- Field Type
- Description
Occurs when there is a change in the lifecycle status of an estimate, tracking its progression through stages such as
DRAFT
,OPEN
,APPROVED
,REJECTED
,CONVERTED
orVOID
.
- Name
invoice.created
- Type
- Field Type
- Description
Occurs when a new invoice is generated, representing a formal billing statement for services rendered or goods delivered.
- Name
invoice.updated
- Type
- Field Type
- Description
Occurs when an existing invoice undergoes modifications, which may include changes to the billed amounts, terms, or itemized charges.
- Name
invoice.approved
- Type
- Field Type
- Description
Occurs when an invoice has been reviewed and endorsed by the authorized customer for payment.
- Name
invoice.paid_status.updated
- Type
- Field Type
- Description
Occurs when there is a change in the payment status of an invoice, which can include updates such as
UNPAID
,PROCESSING
,PARTIALLY_PAID
orPAID
.
- Name
invoice.rejected
- Type
- Field Type
- Description
Occurs when an invoice is formally declined, which may prompt dispute resolution or necessitate issuing a revised invoice.
- Name
invoice.sent
- Type
- Field Type
- Description
Occurs when an invoice is sent out to a customer, marking an official request for the settlement of the billed amount.
- Name
invoice.status.updated
- Type
- Field Type
- Description
Occurs when the status of an invoice is updated, which can reflect transitions to different stages such as
DRAFT
,OPEN
,PAID
, orVOID
.
- Name
payment.created
- Type
- Field Type
- Description
Occurs when an invoice is successfully marked as paid and a new payment receipt is generated.
- Name
payment.sent
- Type
- Field Type
- Description
Occurs when a payment receipt is sent to the customer.
- Name
payment.failed
- Type
- Field Type
- Description
Occurs when a payment made for an invoice gets failed.
- Name
recurring.invoice.created
- Type
- Field Type
- Description
Occurs when a new recurring invoice is generated, A recurring invoice automates the generation of invoices at predefined intervals, reflecting recurring services provided or goods delivered over time.
- Name
recurring.invoice.updated
- Type
- Field Type
- Description
Occurs when an existing recurring invoice undergoes modifications, which may include changes to the billed amounts, terms, or itemized charges.
- Name
recurring.invoice.status.updated
- Type
- Field Type
- Description
Occurs when the status of a recurring invoice status is updated, which can reflect transitions
ACTIVE
,ON_HOLD
orCOMPLETED
.
Example payload
{
"event": "invoice.updated",
"payload": {
"id": "9aae0110-a4d6-4552-99de-4b4d3e3432f8",
"estimate_id": null,
"invoice_number" : "INV-000001",
"invoice_date" : 1017705600,
"due_date" : 1594944000,
"customer_business_id" : "98ed68ce-6964-4c2a-9430-8a849e373c52",
"template_name" : "invoice1",
"items": [
{
"id": "9974c9fc-5dfc-4262-81b8-f42e3275119b",
"name": "Apple Macbook",
"description": "Light and powerful laptop",
"discount_type": null,
"price": 10000,
"quantity": 2,
"unit_name": null,
"discount": 0,
"discount_val": 0,
"tax": 0,
"total": 20000,
"invoice_id": "9aae0110-a4d6-4552-99de-4b4d3e3432f8",
"item_id": null,
"business_id": "995c98ce-cdd9-4ef6-b018-9c696cb07e9d"
}
],
"sequence_number" : 1,
"status" : "DRAFT",
"notes" : "<p>The total amount of the attached invoice INV-000001 is $190.00</p>",
"notes_raw" : "<p>The total amount of the attached invoice {INVOICE_NUMBER} is {TOTAL_AMOUNT}</p>",
"discount" : 5,
"discount_type" : "percentage",
"discount_val" : 1000,
"tax" : 0,
"sub_total" : 20000,
"sent_at" : null,
"viewed_at" : null,
"approved_at" : null,
"overdue_at" : null,
"invoice_pdf_url" : "https://payments.your-domain.com/invoices/pdf/9aae0110-a4d6-4552-99de-4b4d3e3432f8",
"attachments" : [],
"customer" : {},
"tax_per_item_enabled" : false,
"discount_per_item_enabled" : false,
"created_at" : 1687268840,
"billing_address": {},
"shipping_address": {},
"paid_status" : "UNPAID",
"total" : 19000,
"due_amount" : 19000,
"sent_to_oatfi": null,
"vendor_business_id": "995c98ce-cdd9-4ef6-b018-9c696cb07e9d",
"creator_id": "9bdf9dc1-6ca1-4e3c-bc91-84d0f607d6d8",
"scheduled_date": null,
"payee_loan_status" : "DRAFT",
"payor_loan_status" : "DRAFT",
"taxes": [],
"vendor": {},
"allowed_paid_invoice_states": [
"PARTIALLY_PAID",
"PAID"
],
"integrations": [],
"recurring_auto_pay_authorized": false
}
}
Security
To know for sure that a webhook was, in fact, sent by Crater instead of a malicious actor, you can verify the request signature. Each webhook request contains a header named x-crater-signature
, and you can verify this signature by using your secret webhook key. The signature is an HMAC hash of the request payload hashed using your secret key. Here is an example of how to verify the signature in your app:
Verifying a request
const signature = req.headers['x-crater-signature']
const hash = crypto.createHmac('sha256', secret).update(payload).digest('hex')
if (hash === signature) {
// Request is verified
} else {
// Request could not be verified
}
If your generated signature matches the x-crater-signature
header, you can be sure that the request was truly coming from Crater. It's essential to keep your secret webhook key safe — otherwise, you can no longer be sure that a given webhook was sent by Crater. Don't commit your secret webhook key to Git!