Webhooks

Cabinetry.Online has a number of webhook triggers where external URLs can be called on certain actions.

Current Webhooks

Order Submission

This acts as an additional check / validation step when submitting a job.

  1. Customer clicks "Submit Job" and acknowledges that they want to submit the job
  2. The webhook is called
  3. The webhook response is evaluated:
    • If it's successful:
      1. The job is marked as submitted and all emails and other updates are performed
      2. Any messages returned are shown to the customer and saved on the job
      3. An external ID, if present, is set on the job
    • If it fails:
      1. The job is not submitted and remains in the processing status
      2. Any errors returned are shown the customer

This can be used to implement:

Pricing

This is a replacement for Cabinetry.Online's built-in pricing for manufacturers who have complicated pricing requirements or who already have systems in place to calculate pricing, tax, discounts, etc. on a job.

  1. Customer saves a product, closes the Doors and Panels tool or opens a job containing products
  2. The webhook is called
  3. The webhook's response is evaluated:
    • If it's successful:
      1. The pricing is saved on the job
      2. The sidebar cart shows the pricing returned
    • If it fails:
      1. Any errors returned are shown to the customer
      2. The previous pricing is shown to the customer

Webhook Configuration

Common Options

Field Example Description
Enable webhook On / Off Whether the webhook is enabled
Authentication Type Bearer Token Type of authentication used by the webhook. See below
Export Details Format JSON Format to use for the job export in the payload

Bearer Token Authentication

Field Example Description
Bearer Token some-bearer-token Token to pass in the Authorization header when calling the webhook

Auth0 Authentication

This uses the Client Credentials Flow to generate a token for the webhook request. This will be cached for the validity period returned by Auth0.

Field Example Description
Tenant Domain example.au.auth0.com Auth0 tenant domain name
Client ID Client ID
Client Secret Client secret
Audience Audience

The Client ID, Client Secret and Audience should be copied from Auth0's configuration.

Webhook Requests

Upon being triggered, the webhook will send a JSON payload and any authentication headers to the URL specified.

All webhooks use the same request structure.

Example request:

POST https://example.com/webhook
Authorization: Bearer some-bearer-token

{
  "export": {
    "JobNumber": 348167,
    "JobName": "Test Job",
    "Status": "Processing",
    "Description": "",
    "CustomerName": "Test Account",
    "Manufacturer Name": "Example",
    "InvoiceTo": "Test Account",
    "OrderDate": "26th Feb 2024 at 6:31pm",
    "ExpectedDeliveryDate": "-",
    "DispatchMethod": "Default Address",
    "ContactNumber": "0412123123",
    "CustomerId": 27465,
    "JobRooms": [
        {
            "RoomNumber": 1,
            "RoomName": "Room 1",
            "RoomDescription": "",
            "CompanyLabel": "Test Account 0412123123",
            "InteriorMaterial": "Polytec SolidMatt MRMDF 16.5 Canterbury Grey",
            "ExteriorMaterial": "Polytec SolidMatt MRMDF 16.5 Canterbury Grey",
            "InteriorEdging": "Polytec SolidMatt 1 Mountain Pepper",
            "ExteriorEdging": "Polytec SolidMatt 1 Mountain Pepper",
            "DoorDwrProductName": "Flat Panel",
            "HingeSeries": "None",
            "DrawerSystem": "Blum Metabox",
            "ToeKickHeight": "0",
            "JobCabinets": [
                {
                    "RoomProductNo": "1-1.00",
                    "Type": "Door",
                    "ProcessName": "DoorQFP",
                    "ProductDescription": "Door",
                    "Quantity": "1",
                    "ProductHeight": "900",
                    "ProductWidth": "550",
                    "ExteriorMaterialType": "Melamine",
                    "ExteriorMaterial": "Polytec SolidMatt MRMDF 16.5 Canterbury Grey",
                    "ExteriorEdging": "Polytec SolidMatt 1 Mountain Pepper",
                    "InteriorMaterialType": "Non Supply",
                    "DoorDwrEdgingLeft": "Yes",
                    "DoorDwrEdgingRight": "Yes",
                    "DoorDwrEdgingTop": "Yes",
                    "DoorDwrEdgingBottom": "Yes",
                    "ExcludeHardware": "Yes",
                    "SpecificHingeHeights": "None",
                    "DoorHangType": "Single",
                    "DoorHang": "None",
                    "HingeSeries": "None",
                    "DoorDwrProductName": "Flat Panel"
                },
                {
                    "RoomProductNo": "1-2.00",
                    "Type": "Drawer Face",
                    "ProcessName": "DrawerQFP",
                    "ProductDescription": "Drawer Pack",
                    "Quantity": "1",
                    "ProductHeight": "900",
                    "ProductWidth": "550",
                    "DrawerDetail": "298.66;298.66;298.66;",
                    "ExteriorMaterialType": "Melamine",
                    "ExteriorMaterial": "Polytec SolidMatt MRMDF 16.5 Canterbury Grey",
                    "ExteriorEdging": "Polytec SolidMatt 1 Mountain Pepper",
                    "InteriorMaterialType": "Non Supply",
                    "DoorDwrEdgingLeft": "Yes",
                    "DoorDwrEdgingRight": "Yes",
                    "DoorDwrEdgingTop": "Yes",
                    "DoorDwrEdgingBottom": "Yes",
                    "EdgeJoiningBorder": "Yes",
                    "ExcludeHardware": "Yes",
                    "DrawerAmount": "3",
                    "DoorDwrProductName": "Flat Panel",
                    "DrawerFaceType": "Individual Faces",
                    "ClearanceBetweenDrawers": "2"
                },
                {
                    "RoomProductNo": "1-3.00",
                    "Type": "Manual Panel",
                    "ProcessName": "PanelQFP",
                    "ProductDescription": "Flat Panel",
                    "Quantity": "1",
                    "ProductLength": "900",
                    "ProductWidth": "550",
                    "ExteriorMaterialType": "Melamine",
                    "ExteriorMaterial": "Polytec SolidMatt MRMDF 16.5 Canterbury Grey",
                    "ExteriorEdging": "Polytec SolidMatt 1 Mountain Pepper",
                    "InteriorMaterialType": "Non Supply",
                    "ExteriorEdgeFront": "Yes",
                    "ExteriorEdgeBack": "Yes",
                    "ExteriorEdgeLeft": "Yes",
                    "ExteriorEdgeRight": "Yes",
                    "ExcludeHardware": "Yes"
                }
            ],
            "RawJobBenchtops": []
        }
    ],
    "JobSundries": [],
    "jobBenchtops": []
  },
  "job": {
    "id": 338167,
    "customerId": 27465,
    "status": 0,
    "name": "Test Job",
    "description": "",
    "dispatchMethod": 2,
    "address": "1 Fake Street",
    "suburb": "Example Suburb",
    "state": "Victoria",
    "postcode": "3220",
    "variationCost": 0,
    "freightCost": 50,
    "dateEntered": "2024-02-26T18:31:56+00:00",
    "dateUpdated": "2024-02-26T18:32:49+00:00",
    "dateSubmitted": "0000-00-00T00:00:00+00:00",
    "dateAccepted": "0000-00-00T00:00:00+00:00",
    "dateDelivery": "0000-00-00T00:00:00+00:00",
    "datePaid": "0000-00-00T00:00:00+00:00",
    "accepted": 0,
    "customerName": "Test Account",
    "manufacturerName": "Example",
    "variationsConfirmed": 0,
    "taxRate": 10,
    "currencyAbbreviation": "AUD",
    "currencyType": "$",
    "cost": 332.96,
    "roomCount": "1",
    "productCount": 3,
  },
  "customer": {
    "id": 27465,
    "manufacturer_id": 103,
    "name": "Test Account",
    "email": "example@cabinetsbycomputer.com",
    "phone": "0412123123",
    "mobile": "",
    "cc_email": "",
    "price_adjustment": 0,
    "minimum_charge_amount": 0,
    "minimum_freight_amount": 50,
    "contact_address": {
      "street": [
        "1 Fake Street"
      ],
      "suburb": "Example Suburb",
      "state": "Victoria",
      "state_code": "VIC",
      "postcode": "1232",
      "country": "Australia",
      "country_code": "AU"
    },
    "delivery_address": {
      "street": [
        "1 Fake Street"
      ],
      "suburb": "Example Suburb",
      "state": "Victoria",
      "state_code": "VIC",
      "postcode": "3220",
      "country": "Australia",
      "country_code": "AU"
    },
    "customer_labels": [],
    "settings": {
      "is_beta": true,
      "is_premium": false,
      "is_assembly_enabled": false,
      "is_suspended": false
    }
  },
  "success": 1
}

Request Payload Structure:

This payload consists of three components:

{
    "export": {...},
    "job": {...},
    "customer": {...}
}

Each component in the payload is the exact data returned by one of the other API endpoints present in the Cabinetry.Online API.

Component Source
export Job Download
job Job Listing
customer Customer Management

The data in each top-level component is identical to the data that would be returned by running an API request for each of those types of data for the job the webhook was triggered for and the customer who owns that job.

Note that depending on the size of the job, this object may be quite large.

Export

This is the data returned by the job download API in the format selected in the webhook settings.

If the "JSON" format is selected, the JSON job export is embedded in the outer object returned like in the example above. If any other option is returned, this is a string containing the export.

Job

This is the job data as returned from the job listing API.

Note that the columns documented in the job listing API are stable and other values may come and go depending on operational requirements.

Customer

This is the customer details as returned from the customer management API.

Webhook Responses

Each type of webhook has different response requirements based on their parituclar purpose.

However all responses will follow the same overall requirements:

Failure Responses

Any response that has either a non-200 HTTP status or a success key that isn't truthy will be assumed to be failed.

Field Example Requried Description
success false No Whether the request succeded, ignored if the HTTP status is not 200
errors ["No widgets", "User blocked"] No Message or array of messages describing why the request failed. Will be shown to customers

If the errors field isn't present in a response, a generic "something went wrong" message will be shown to the customer.

Absolute Minimum Error Response:

Example Error Response:

{
    "success": false,
    "errors": [
        "No Widgets",
        "User Blocked",
    ]
}

Successful Order Submission Responses

Fields:

Field Example Required Description
success true No Whether the request succeeded, must be truthy
message ["Order #123456", "Please contact support for delivery"] No Message(s) to store on the job and display to the customer, can be a string or array of strings
id MEL-123456 No External ID to store on the job

Absolute Minimum Successful Response:

Example Successful Response:

{
    "success": true,
    "message": "Order #123456",
    "id": "JPS-990495"
}

Successful Pricing Responses

Fields:

Field Example Required Description
cost 1234.56 Yes Total cost, including tax, of the job
success true No Whether the request succeeded, must be truthy
message ["10% first order discount applied", "Freight is for North Melbourne 3051"] No Message(s) to store on the job and display to the customer, can be a string or array of strings
breakdown [{"name": "Tax", "cost": 123.46}] No Cost breakdown and any other cost lines to show to the customer

The breakdown field is a tree structure containing a detailed breakdown of the pricing of the job.

Field Type Required Description
name string Yes Name of the line item
cost number No Cost of the line item
collapse boolean No Whether the child nodes of this one should be collapsed
items Array of breakdown objects No Child items

E.g.

[
  {"name": "Subtotal", "cost": 123.45},
  {"name": "Discounts", "collapse": true, "items": [
    {"name": "Free freight", "cost": -100},
    {"name": "10% coupon", "cost": -12.34}
  ]}
]

Would be displayed as this:

with the two discounts hidden by default.

Note:

Absolute Minimum Successful Response:

{
    "cost": 1234.56
}

Example Successful Response:

{
    "success": true,
    "cost": 1234.56,
    "message": "10% first order discount applied",
    "breakdown": [
        {
            "name": "Discounts",
            "items": [
                {
                    "cost": 123.46,
                    "name": "10% First Order Discount"
                }
            ]
        }, {
            "cost": 101.01,
            "name": "Tax",
        }
    ]
}