Manage Webhooks
6 minute read
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
What are webhooks
If you’re reading this we assume you already know what webhooks are, if you’d like a refresher - you can read all about webhooks here.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
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:
- The payload to be sent (as JSON)
- The status of the event
- Responses received from the destination endpoint - see Webhook Event Responses
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"
}
}
}
}
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"
}
}
}
}
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"
}
}
]
}
}
}