# Overview

# What is a Webhook?

A Webhook is a tool for retrieving and storing data from a certain event. They allow you to register an http\:// or https\:// URL where the event data can be received in JSON formats.

ServiceM8 Webhooks are commonly used for:

* Receiving scheduling changes
* Updating item/material’s price changes in your app
* Notifying staff with real-time job changes
* Collecting data for data-warehousing
* Integrating your accounting software

Think of it this way, if you would otherwise have to poll for a substantial amount of data, you should be using webhooks.

> 📘 Note that updates only indicate that a particular field has changed, they do not include the value of the field. When your application receives a webhook update from ServiceM8, you will need to use the [REST API](/documentation/rest-api/overview) to retrieve the record and get the field values.

# Creating and Updating Subscriptions

Webhooks are subscribed to by using the Webhooks API endpoint: `https://api.servicem8.com/webhook_subscriptions`

The basic operations are:

* Add or modify a subscription.
* List each of your existing subscriptions.
* Delete subscriptions.

# Setting Up your Callback URL

First you’ll need to prepare the page that will act as your callback URL. This URL will need to be accessible by ServiceM8 servers, and be able to receive form-encoded POST data that is sent when an update happens, and in order to verify subscriptions.

This URL should always return a HTTP 200 response when invoked by ServiceM8.

# Handling Verification Requests

> 🚧 Public Applications Only
>
> Public applications (OAuth 2) must complete a challenge request to subscribe to webhooks.
>
> Note that API key requests are not required to complete the challenge request process.

When you add a new subscription, or modify an existing one, ServiceM8 servers will make a HTTP POST request to your callback URL in order to verify the validity of the callback server. The request will include the following POST parameters.

| Parameter | Value            |
| :-------- | :--------------- |
| mode      | subscribe        |
| challenge | \<random string> |

When your server receives one of these requests, it needs to render a response to the request that includes only the challenge value. This confirms that this server is configured to accept callbacks, and is used for security verification on ServiceM8’s side.

Here's a simple example of how to implement the verification step.

```php
<?php

if ($_REQUEST['mode'] == 'subscribe' && $_REQUEST['challenge']) {
    echo $_REQUEST['challenge'];
} // else: handle webhook POST data
```

# Handling Webhooks

After your callback URL has been verified, ServiceM8 will send a HTTP POST to that URL each time one of the fields on the subscribed object changes. The data POSTed to your callback URL will be JSON in the following format:

```
{
 "object": "job",
 "entry": [{
   "changed_fields": ["badges","generated_job_id"],
   "time": "2015-01-01 00:00:00",
   "uuid": "de305d54-75b4-431b-adb2-eb6b9e546013"
 }],
 "resource_url": "https://api.servicem8.com/api_1.0/job/de305d54-75b4-431b-adb2-eb6b9e546013.json"
}
```

The **entry** parameter is an array which contains a single object. To read the values you'll need to use code similar to `myValue = entry[0].time`.

Note that the data POSTed to your callback URL does not contain the object itself — only the UUID and a list of fields that changed. You can request the URL specified by resource\_url to obtain the object itself. The timestamp provided will be in UTC.

> 📘 Most timestamps in ServiceM8 are in the account's local timezone. Webhooks are different, as they use UTC timestamps.

## Callback URL Response Codes

| Code    | Title     | Description                                                                                                   |
| :------ | :-------- | :------------------------------------------------------------------------------------------------------------ |
| 200     | Success   | Webhook has completed successfully                                                                            |
| 410     | Gone      | Webhook will be unsubscribed (the same as if you had called the webhook subscription endpoint and removed it) |
| 429     | Throttled | Webhook request volume will be gradually throttled for 15 minutes for this account                            |
| 4xx/5xx | Error     | Webhook will be retried for up to 72 hours, before automatically being cancelled                              |

## Troubleshooting Failed Webhooks

`GET /webhook_subscriptions` now supports a `status` query parameter so you can inspect deactivated subscriptions as part of debugging.

* `status=active` returns active subscriptions only. This is the default.
* `status=inactive` returns deactivated subscriptions only.
* `status=all` returns both active and inactive subscriptions.

If a webhook has stopped firing, request the inactive subscriptions and inspect the last recorded failure details:

```http
GET /webhook_subscriptions?status=inactive
```

Each returned subscription now includes these troubleshooting fields:

* `active` indicates whether the subscription is currently active.
* `last_failure_reason` contains the most recent failure reason recorded for the subscription, or `null` if none has been recorded.
* `last_failure_at` contains the UTC timestamp of the most recent recorded failure, or `null` if none has been recorded.

Example response:

```json
[
  {
    "type": "object",
    "object": "job",
    "callback_url": "https://example.com/hooks/JobChanged",
    "fields": ["uuid", "status"],
    "unique_id": "integration-a",
    "active": false,
    "last_failure_reason": "Webhook request failed for over 12 hours",
    "last_failure_at": "2026-04-14 03:25:00"
  }
]
```

Use `status=all` if you want to compare active and inactive subscriptions in the same response. When a subscription is successfully reactivated, its stored failure snapshot is cleared, so inspect the failure details before reactivating if you need them for debugging.

## How to Use the Webhooks API

Refer to the [Webhooks API Reference](https://developer.servicem8.com/reference/webhook-subscription) for details of the Webhooks endpoint.

## Which objects support webhooks?

The following objects/endpoints support webhooks:

* Job Activity
* Job
* Job Payment
* Note
* Task
* Material
* Company
* Attachment
* Form Response
