149 lines
6.3 KiB
Markdown
Executable File
149 lines
6.3 KiB
Markdown
Executable File
# 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
|