We are in active development, so your feedback is critical to us. Please reach out if you run into any issues or have a feature you would like to see implemented.

Understanding Hooks

A Hook acts as a proxy for webhooks between you and your customers. You primarily interact with your hook by sending HTTP POST requests to the Hook URL. The first thing to decide when creating a hook is which direction the traffic will flow.

Inbound vs. Outbound

We handle both sending (outbound) and receiving (inbound) webhooks, as each have different challenges.

Inbound

Inbound hooks are designed to provide a buffer between your users and your backend. Inbound webhooks typically come from many sources and are relayed to one endpoint. Because of this, you must specify a Target URL in the Hook settings.

When Hook Relay gets cozy with you and your inbound webhooks, we ensure that your servers are never overloaded. If you have any connection problems or downtime, you can rest easy knowing you will get your webhooks after coming back online.

Outbound

You won't have to deal with slow consumers taking up outgoing connections when you delegate your outgoing webhooks to Hook Relay. Outbound webhooks are usually sent to multiple consumers, so you must provide the Target URL in the request header.

Go ahead and send us all the webhook requests you can. We will respond right away and make sure the payload gets delivered to your users. You can even use our API to provide receipts of your webhook deliveries.

Webhook Requests

Each hook has a single Hook URL that looks something like this:

You will POST directly to the Hook URL for outbound webhooks or hand it to your customers for inbound webhooks.

When we receive a POST, we create a delivery and queue up the request to be sent to the Target URL. We respond immediately with a JSON payload containing the delivery ID:

{
  "id": "01EC8Z3JAQ0W2ZAQGG2S3XNMWJ"
}

You can use this ID to track webhook by looking up the status of your delivery.

Deliveries

Deliveries are a container for webhook "requests." We create a delivery for each POST received by a Hook. A delivery keeps track of the inbound request, the target's response, and any retry history. You can visit the delivery page for any request to see detailed information about each request and response.

Streams

Streams let you segment your hook deliveries. To include a stream value, append an identifier as an optional path to your Hook URL, for example:

/hooks/r3j8kxgen2gzqhgdwom45v7q/f8b4798bff3a3fe82464fa32/customer1

We will keep track of customer1's deliveries and provide you with extra tools for tracking and filtering.

Retries

If we have any issues relaying your target request, we will keep retrying (with exponential falloff). If we can not reach the target within your account's retry limit, we mark the delivery as "failed" and stop trying.

NOTE: A successful response must have a 200 level status code. Receiving any other response code (or a connection error) will result in a retry.

You can cancel a retrying delivery at any point. You may also retry a canceled delivery at any point as well.

Target URL

The Target URL is where we will relay requests. If you are receiving inbound webhook requests, it might make sense to provide a default target URL. You can do this in your hook's settings:

If you want to vary the Target URL (say, for outgoing webhooks), the target can be specified as the value for the "HR_TARGET_URL" header in the hook request.

NOTE: Even if your hook has a default Target URL, a target specified in the header will always take precedence.

Report URL

If you provide us with a Report URL in your hook settings, we will send you updates (in the form of a webhook) for every delivery attempt. You will recieve a POST request with a body containing the same contents as a typical Delivery API lookup response but with the responses data stripped.

Pausing & Disabling

Pausing will still accept requests, but it will not relay them to the Target URL. This can be useful if your endpoint is down, yet you still want to accept webhook requests.

You can flag your hook as disabled if you want to ignore all requests into your hook.

Both Disabling and Pausing can be achieved via hook settings.

Account Management

Access is granted via an account. We provision a default account when you first sign-up. You can add (or remove) an account at any time, but you must always have at least one account. Subscriptions and payment info are also associated with an account.

Switching Accounts

While viewing your data, you are always within the context of a current account. If you want to view hooks for another account, then you must switch accounts. We provivde a quick account switcher in the main menu. You can also switch accounts via the accounts area.

Regions

When you create an account, you have the option to specify a region. Your data will be stored in the selected region. A region closer to your location will also benefit from lower latency for requests. You cannot change a region after Account creation.

Users

If you are an owner or have the admin role for an account, you can invite users to your account. You can update and remove any invited users to your account via the account details:

Billing & Pricing

View the billing settings for your current account via the "Billing" main menu option. If you want to see billing info for another account, you must switch to that account.

Pricing is based on the amount of recorded "deliveries". A typical request will consume 2 deliveries. Both the incoming request and outgoing attempt counts as a delivery. If you have a delivery that requires retries, each retry will also count as a "delivery".

Rest API

Authentication

We use (Bearer) token-based authentication for all our API routes. You can provision an API token within our "API tokens" area. Access this section via the menu dropdown. Once you give your new token a name, it will be presented to you:

You can revoke or reprovision a new token at any time. As you can see in the screenshot, just include the token in the Authorization header and data away!

Pagination

For any endpoints that require pagination, you can request more results by passing an item id as a cursor. Cursors should always be passed as query parameters. We accept cursors for results up to an id (?ending_before=abc123), and beginning at an id (?starting_after=abc123.)

Accounts

Operations around accounts you are a member of.

Get an Account

get /accounts/{account_id}

Example response

{
  "id": "75r4e01zq24z0hwd6yxjpgvo",
  "links": {
    "hooks": "/api/v1/accounts/zprgwxnvm9eozhk2178j304k/hooks",
    "self": "/api/v1/accounts/zprgwxnvm9eozhk2178j304k"
  },
  "name": "My Account"
}

List all Accounts

get /accounts

Example response

{
  "data": [
    {
      "id": "75r4e01zq24z0hwd6yxjpgvo",
      "links": {
        "hooks": "/api/v1/accounts/zprgwxnvm9eozhk2178j304k/hooks",
        "self": "/api/v1/accounts/zprgwxnvm9eozhk2178j304k"
      },
      "name": "My Account"
    },
    "..."
  ],
  "has_more": true
}

Deliveries

Look up a delivery when you want to show the status of a webhook to a customer.

Get a Delivery

get /accounts/{account_id}/hooks/{hook_id}/deliveries/{delivery_id}

Example response

{
  "attempts": 1,
  "completed_at": "2020-12-02T15:37:42Z",
  "failure_reason": "Could not connect",
  "id": "2a360b1d10fff55b91498e45",
  "last_attempted_at": "2020-12-02T15:37:42Z",
  "report_url": "http://example.com/aeiou",
  "request": {
    "body": "body",
    "headers": { "Content-Type": "application/json" },
    "jmespath_error": "jmespath_error",
    "target_url": "http://example.com/aeiou"
  },
  "responses": [
    {
      "body": "body",
      "code": 0,
      "created_at": "2000-01-23T04:56:07.000+00:00",
      "error": "error",
      "headers": { "Content-Type": "application/json" }
    },
    "..."
  ],
  "status": "success"
}

List Deliveries

get /accounts/{account_id}/hooks/{hook_id}/deliveries

Query Params

ending_before
Return results up to this ID
starting_after
Begin results starting from this ID
limit
Constrain count of results.

Example response

{
  "data": [
    {
      "attempts": 1,
      "completed_at": "2020-12-02T15:37:42Z",
      "failure_reason": "Could not connect",
      "id": "2a360b1d10fff55b91498e45",
      "last_attempted_at": "2020-12-02T15:37:42Z",
      "report_url": "http://example.com/aeiou",
      "request": {
        "body": "body",
        "headers": { "Content-Type": "application/json" },
        "jmespath_error": "jmespath_error",
        "target_url": "http://example.com/aeiou"
      },
      "responses": [
        {
          "body": "body",
          "code": 0,
          "created_at": "2000-01-23T04:56:07.000+00:00",
          "error": "error",
          "headers": { "Content-Type": "application/json" }
        },
        {
          "body": "body",
          "code": 0,
          "created_at": "2000-01-23T04:56:07.000+00:00",
          "error": "error",
          "headers": { "Content-Type": "application/json" }
        }
      ],
      "status": "success"
    },
    "..."
  ],
  "has_more": true
}

Hooks

Fully manage your hooks via API.

Create a Hook

post /accounts/{account_id}/hooks

Example response

{
  "id": "2a360b1d10fff55b91498e45",
  "links": {
    "account": "/api/v1/accounts/75r4e01zq24z0hwd6yxjpgvo",
    "deliveries": "/api/v1/accounts/75r4e01zq24z0hwd6yxjpgvo/hooks/2a360b1d10fff55b91498e45/deliveries",
    "self": "/api/v1/accounts/75r4e01zq24z0hwd6yxjpgvo/hooks/4e7b6cc56fab423204025385"
  },
  "name": "My Hook",
  "report_url": "https://3ab577f377a4.ngrok.io/no_content"
}

Delete a Hook

delete /accounts/{account_id}/hooks/{hook_id}

Get a Hook

get /accounts/{account_id}/hooks/{hook_id}

Example response

{
  "id": "2a360b1d10fff55b91498e45",
  "links": {
    "account": "/api/v1/accounts/75r4e01zq24z0hwd6yxjpgvo",
    "deliveries": "/api/v1/accounts/75r4e01zq24z0hwd6yxjpgvo/hooks/2a360b1d10fff55b91498e45/deliveries",
    "self": "/api/v1/accounts/75r4e01zq24z0hwd6yxjpgvo/hooks/4e7b6cc56fab423204025385"
  },
  "name": "My Hook",
  "report_url": "https://3ab577f377a4.ngrok.io/no_content"
}

List all Hooks

get /accounts/{account_id}/hooks

Query Params

ending_before
Return results up to this ID
starting_after
Begin results starting from this ID
limit
Constrain count of results.

Example response

{
  "data": [
    {
      "id": "2a360b1d10fff55b91498e45",
      "links": {
        "account": "/api/v1/accounts/75r4e01zq24z0hwd6yxjpgvo",
        "deliveries": "/api/v1/accounts/75r4e01zq24z0hwd6yxjpgvo/hooks/2a360b1d10fff55b91498e45/deliveries",
        "self": "/api/v1/accounts/75r4e01zq24z0hwd6yxjpgvo/hooks/4e7b6cc56fab423204025385"
      },
      "name": "My Hook",
      "report_url": "https://3ab577f377a4.ngrok.io/no_content"
    },
    "..."
  ],
  "has_more": true
}

Update a Hook

put /accounts/{account_id}/hooks/{hook_id}

Example response

{
  "id": "2a360b1d10fff55b91498e45",
  "links": {
    "account": "/api/v1/accounts/75r4e01zq24z0hwd6yxjpgvo",
    "deliveries": "/api/v1/accounts/75r4e01zq24z0hwd6yxjpgvo/hooks/2a360b1d10fff55b91498e45/deliveries",
    "self": "/api/v1/accounts/75r4e01zq24z0hwd6yxjpgvo/hooks/4e7b6cc56fab423204025385"
  },
  "name": "My Hook",
  "report_url": "https://3ab577f377a4.ngrok.io/no_content"
}

User

Info about the currently logged in User.

Show User

get /me

Example response

{
  "accounts": [
    {
      "id": "75r4e01zq24z0hwd6yxjpgvo",
      "links": {
        "hooks": "/api/v1/accounts/zprgwxnvm9eozhk2178j304k/hooks",
        "self": "/api/v1/accounts/zprgwxnvm9eozhk2178j304k"
      },
      "name": "My Account"
    },
    "..."
  ],
  "id": "2a360b1d10fff55b91498e45",
  "name": "Bobby Tables"
}
© 2020-2021 Honeybadger Industries, LLC