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
    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
    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
    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
    Description

    Occurs when any details of an existing customer entity’s profile are modified, which may include changes in customer name, contact information.

  • Name
    estimate.created
    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
    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
    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
    Description

    Occurs when an approved financial estimate is converted into a formal invoice, initiating the billing cycle.

  • Name
    estimate.rejected
    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
    Description

    Occurs when a financial estimate is dispatched to a client, typically indicating the commencement of the approval workflow.

  • Name
    estimate.status.updated
    Type
    Description

    Occurs when there is a change in the lifecycle status of an estimate, tracking its progression through stages such as 'DRAFT', 'SENT', 'APPROVED', 'REJECTED', or 'CONVERTED'.

  • Name
    invoice.created
    Type
    Description

    Occurs when a new invoice is generated, representing a formal billing statement for services rendered or goods delivered.

  • Name
    invoice.updated
    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
    Description

    Occurs when an invoice has been reviewed and endorsed by the authorized customer for payment.

  • Name
    invoice.paid_status.updated
    Type
    Description

    Occurs when there is a change in the payment status of an invoice, which can include updates such as 'PAID' or 'UNPAID'.

  • Name
    invoice.rejected
    Type
    Description

    Occurs when an invoice is formally declined, which may prompt dispute resolution or necessitate issuing a revised invoice.

  • Name
    invoice.sent
    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
    Description

    Occurs when the status of an invoice is updated, which can reflect transitions to different stages such as 'DRAFT', 'SENT', 'VIEWED', 'APPROVED', 'REJECTED' or 'COMPLETED'.

  • Name
    payment.created
    Type
    Description

    Occurs when an invoice is successfully marked as paid and a new payment receipt is generated.

  • Name
    payment.sent
    Type
    Description

    Occurs when a payment receipt is sent to the customer.

  • Name
    payment.failed
    Type
    Description

    Occurs when a payment made for an invoice gets failed.

Example payload

{
  "event": "invoice.updated",
  "payload": {
    "id": "995c6a61-4cc8-446c-860b-a73365c6f1a4",
    "invoice_date": 1676350800,
    "created_at": 1686222008,
    "due_date": 1678942800,
    "invoice_number": "INV-00000001",
    "status": "DRAFT",
    "paid_status": "UNPAID",
    "reject_reason": null,
    "notes": null,
    "discount_type": "percentage",
    "discount": 5,
    "discount_val": 2000,
    "sub_total": 40000,
    "tax": 0,
    "total": 38000,
    "due_amount": 38000,
    "sent_at": null,
    "viewed_at": null,
    "overdue_at": null,
    "template_name": "invoice1",
    "sequence_number": 1,
    "customer_id": "995c668a-487f-43c6-a1da-6dda2e886dd8",
    "invoice_pdf_url": "https://payments.your-domain.com/invoices/pdf/995c6a61-4cc8-446c-860b-a73365c6f1a4",
    "attachments": [],
    "approval_type": "FULL_APPROVAL",
    "invoice_type": "outgoing",
    "payee_loan_status": "DRAFT",
    "payor_loan_status": "DRAFT",
    "tax_per_item_enabled": false,
    "discount_per_item_enabled": false,
    "customer": {}
  }
}

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!