Hooks API

Hooks API

Hooks allow you to extend the functionality of Bubblehouse with your own code.

Using the API settings page, you should specify a hook URL (we'll be calling a single URL for all hooks, replacing :name with an actual hook name).

At the very least, you need to implement Hello1 hook. We'll call it every time you save the API settings page, and it returns the list of other hooks that you want to subscribe to.

Hook requests

A hook request is a POST to the URL you have provided, with :name in the URL replaced with the actual hook name like Hello1.

Request headers:

  • Content-Type: application/json
  • Accepts: application/json
  • X-Request-ID: <uuid>
  • X-BH-Urgency: real-time (or urgent, or regular)

Request body is the input JSON object for the hook.

The response must be 200 OK, we also accept 201, 202 or 204. The response body must be a valid output JSON object. We don't care about the Content-Type or other headers you set.

If your hook returns 4xx or 5xx, we will retry it several times before marking it as failed. We can reprocess failed hooks upon request.

We recommend that you use a web server that supports HTTP 2 to speed up high-volume hook processing.

We may send unexpected Hello hooks

Your code MUST be prepared to receive calls of unexpected hooks, at least in the Hello family, and MUST return a 404 error code for those.

We won't actually be sending random hooks, but if we ever introduce Hello2, we think we will try it first before invoking Hello1.

Real-time, urgent and regular calls

There are 3 levels of urgency that hook calls may have:

  1. Real-time calls need to be processed immediately, and we cannot proceed until we get output from them.

    We do not have public real-time hooks at the moment, although:

    • Hello1 call when invoked from API settings page is considered real-time,
    • there's a handful of private hooks that are real-time, particularly when dealing with custom promo objects;
    • there are certain configurations where CreateDiscount hook is also invoked in real-time mode.
  2. Urgent hooks need to be processed as soon as possible, but the user flow continues while waiting on these.

    An example is redeeming points; the customer is waiting for their discount code to be available, but we pre-generate the code string, and we expect the CreateDiscount hook to complete while the customer is copying the code into your checkout page.

  3. Regular hooks are simply notified about events at Bubblehouse, and can take their time to complete.

If you're putting hooks into a job queue, we recommend that you run real-time hooks right away without queueing, and arrange for urgent hooks to take priority.

You can detect urgency level by checking X-BH-Urgency. Please be sure to follow the HTTP standard and use case-insensitive comparisons when looking for an HTTP header.

Time Limits & Retry

UrgencyCall Time LimitRetry IntervalRetry Timeout
regular30 secondsfrom 1 second to 4 hours48 hours
urgent30 secondsfrom 1 second to 5 minutes1 hour
real-time10 seconds100ms, then 1 second5 times

After a retry timeout, hooks are marked as failed, and can be reprocessed upon request.

Authentication

We allow you to configure a value for an Authorization: <whatever> header. This allows you to present a bearer token, basic credentials, or something else of your choice.

The webhook URL must use HTTPS. We recommend ngrok for local testing. We do not further sign webhooks Amazon-style, which would be pretty pointless; HTTPS and token authentication is enough for normal API calls, and thus must also be enough for webhooks.

Examples

Here's a very simple example of a Hooks API server using Express.js:

const express = require('express')
const app = express()
const port = 4000

app.use(express.json())

app.post('/Hello1', (req, res) => {
  res.json({ magic: req.body.magic, hooks: ['CreateDiscount4'] })
})

app.post('/CreateDiscount4', (req, res) => {
  console.log(`TODO: create discount code ${req.body.code} as ${JSON.stringify(req.body, null, 2)}`)
  res.json({ ok: true })
})

app.listen(port, () => {
  console.log(`Hook server listening on port ${port}`)
})

Note that Express automatically handles 404 errors for us. Please ensure that your endpoint returns 404 errors for unknown hooks just as well.

Previous
RecordCustomTrigger1