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
(orurgent
, orregular
)
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:
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.
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.
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
Urgency | Call Time Limit | Retry Interval | Retry Timeout |
---|---|---|---|
regular | 30 seconds | from 1 second to 4 hours | 48 hours |
urgent | 30 seconds | from 1 second to 5 minutes | 1 hour |
real-time | 10 seconds | 100ms, then 1 second | 5 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.