Manage Webhooks

In this example we take you through how to create, update and query webhooks.

What you’ll learn

In this article you’ll learn:

  • Why you may want to automate the creation of webhooks
  • Primary webhook related entities
  • How to use the Operator API to create and update webhooks
  • How to query webhooks, webhook events and webhook event responses

Use-case for automation

Once you have set up and created webhooks, they will typically not change that much. That is not to say that they won’t change over time, but the typical cadence of those changes may not warrant building an automated solution.

So why automate?

The primary reason you may want to automate webhook management will be in relation to testing webhook configurations in environments that “reset”, that is to say where configurations are erased to give you a clean slate on which to begin a new series of testing. In this scenario recreating webhooks again (and again) could be an arduous and error prone task. This is a good use-case for automation.

What can you automate

You can automate the following in relation to webhooks:

  • Create a new webhook (webhookCreate mutation)
  • Update an existing webhook (webhookCreate mutation)
  • Query webhooks (webhooks query)
  • Query webhooks events (webhookEvents query)
  • Query webhook responses(via the WebhookEventResponse)

Examples of these queries and mutations can be found in this article as well as the Operator API collections for Postman and Insomnia.

Webhook Entities

Before launching into using the API to create webhooks, it’s probably worth reviewing the primary webhook entities as we’ll be manipulating these to various extents with the API. The model is shown below:

Webhook Entities

Webhook

This is the entity that represents the webhook “registration”. It holds information such as:

  • What object do we want to receive webhook events for (e.g. Invoice, Shipment etc.)
  • The URL endpoint where events are to be sent
  • Which “events” are we interested in (e.g. Create, Update, Destroy etc.)
  • Whether the webhook is enabled
  • Whether we want to enable deduplication

Webhook Event

Represents a triggered event for a given webhook. It holds information such as:

Webhook Event Response

Represents the response back from the destination endpoint. If the webhook is retrying due to failure responses, there may be multiple webhook event responses as part of that retry cycle. Webhook Event Responses contain information such as:

  • The HTTP status of the response
  • Body payload of the response

Creating webhooks

We can use the webhookCreate mutation to create webhooks (the webhook entity), an example of which is shown below.

NOTE: A full list of the attributes you can pass to webhookCreate are listed here.

mutation webhookCreate($input: WebhookCreateMutationInput!) {
 webhookCreate(input: $input) {
  errors {
   field
   messages
  }
  status
  webhook {
   id
  }
 }
}

The JSON variable set we can pass is:

{
  "input": {
    "attributes": {
      "enabled": true,
      "type": "INVOICE",
      "eventName": "UPDATE",
      "url": "https://example.com/your_post_endpoint",
      "headers": "{ \"environment\": \"Sandbox\" }",
      "queryString": "query($id: ID!){node(id: $id){... on Invoice{__typename id statusFlags createdAt}}}",
      "allowSkip": true
    }
  }
}

This would return the following response:

{
  "data": {
    "webhookCreate": {
      "errors": null,
      "status": 200,
      "webhook": {
        "id": "V2ViaG9vay0x"
      }
    }
  }
}

Create Webhook

Updating webhooks

Updating webhooks is similar to the creation process, with the following exceptions:

  • We use the webhookUpdate mutation
  • We need to pass an id of an existing webhook

An example of calling this mutation is shown below where we disable the webhook.

NOTE: A full list of the attributes you can pass to webhookUpdate are listed here.

mutation WebhookUpdate($input: WebhookUpdateMutationInput!) {
 webhookUpdate(input: $input) {
  errors {
   field
   messages
  }
  status
  webhook {
   id
  }
 }
}

The JSON variable set we can pass is:

{
  "input": {
    "webhookId": "V2ViaG9vay0x",
    "attributes": {
      "enabled": false
    }
  }
}
{
  "data": {
    "webhookUpdate": {
      "errors": null,
      "status": 200,
      "webhook": {
        "id": "V2ViaG9vay0x"
      }
    }
  }
}

Update Webhook

Querying Webhooks

Once you have created webhooks, you may wish to retrieve those via the API, this can be achieved via the webhooks query, an example of which is shown below:

query WebhooksQuery($pageSize: Int, $endCursor: String) {
 webhooks(first: $pageSize, after: $endCursor) {
  edges {
   node {
    id
    type
    url
    events {
     id
     eventName
     sentAt
    }
   }
  }
 }
}

We will pass the pagination variables in the following way:

{
  "pageSize": 10,
  "endCursor": null
}

This would yield the following result, noting that we are also querying the events (WebhookEvent entity) related to that webhook:

{
  "data": {
    "webhooks": {
      "edges": [
        {
          "node": {
            "id": "V2ViaG9vay0x",
            "type": "INVOICE",
            "url": "https://example.com/your_post_endpoint",
            "events": []
          }
        }
      ]
    }
  }
}

In this instance we have not yet generated any webhook events, therefore our collection of events is empty.

Querying Webhook Events

As you saw in the previous example, you can query for webhook events via the webhooks query, however you can also use the webhookEvents query directly, which allows you to isolate the events to just 1 webhook. An example of this is shown below:

query WebhookEventQuery($webhookId: ID, $pageSize: Int, $endCursor: String) {
 webhookEvents(webhookId: $webhookId, first: $pageSize, after: $endCursor) {
  nodes {
   id
   eventName
   status
   skipped
  }
 }
}

We will pass the pagination variables and webhook id in the following way:

{
  "webhookId": "V2ViaG9vay0x",
  "pageSize": 10,
  "endCursor": null
}

This would yield the following result:

{
  "data": {
    "webhookEvents": {
      "nodes": [
        {
          "id": "V2ViaG9va0V2ZW50LTI=",
          "eventName": "update",
          "status": "sent",
          "skipped": false
        },
        {
          "id": "V2ViaG9va0V2ZW50LTE=",
          "eventName": "update",
          "status": "sent",
          "skipped": false
        }
      ]
    }
  }
}

Querying Event Responses

While you can reach the webhookEventResponses from both the webhooks and webhookEvents queries, given the potential volumes of data involved, it is not recommended that you access responses in this way. Instead isolate the WebhookEvent that you are interested in (obtain its ID), and use a node query for that individual event to get the responses.

An example of how to do this is shown below:

query GetWebhookEventResponses($id: ID!) {
 node(id: $id) {
  ... on WebhookEvent {
   id
   responses {
    status
    createdAt
    headers
   }
  }
 }
}

We can pass the Webhook Event Id as follows:

{
  "id": "V2ViaG9va0V2ZW50LTE="
}

This would yield the following response:

{
  "data": {
    "node": {
      "id": "V2ViaG9va0V2ZW50LTE=",
      "responses": [
        {
          "status": 200,
          "createdAt": "2024-07-23T10:14:01+10:00",
          "headers": {
            "Date": "Tue, 23 Jul 2024 00:14:01 GMT",
            "Vary": "Accept-Encoding",
            "Server": "nginx",
            "X-Token-Id": "27980a7b-3439-4cb4-8488-7d8fb9a887fb",
            "Content-Type": "text/html; charset=UTF-8",
            "X-Request-Id": "a1caccce-3fb9-46e7-904d-84e53668e433",
            "Cache-Control": "no-cache, private",
            "Content-Encoding": "gzip",
            "Transfer-Encoding": "chunked"
          }
        }
      ]
    }
  }
}