---
title: Webhooks API | TestingBot API Documentation
description: Create, update and test the HTTP callbacks TestingBot sends when a test
  finishes, and rotate their signing secrets.
source_url:
  html: https://testingbot.com/support/api/webhooks
  md: https://testingbot.com/support/api/webhooks.md
---

# Webhooks

Manage the callbacks TestingBot posts when a test finishes, and verify them without waiting for a run.

- **Endpoint:** api.testingbot.com
- **Version:** v1
- **Format:** JSON
- **Auth:** [HTTP Basic](https://testingbot.com/support/api#authentication)

GET `/v1/webhooks`

## List your webhooks
 Returns every webhook on the team. Webhooks fire when a test finishes; use `failure_only`, `alert_types` and `name_filter` to narrow which tests trigger a delivery. The signing secret is never returned here — it is shown once when the webhook is created or its secret is rotated. 
### Arguments

- **`offset` integer:** Skip this many webhooks from the start of the result set.
- **`count` integer:** Number of webhooks to return.

### Response fields

- **`data` array of webhook objects:** Webhooks on this team.
- **`meta` meta object:** —

GET `/v1/webhooks`
[cURL](https://testingbot.com#)
Request

```bash
$ curl "https://api.testingbot.com/v1/webhooks?offset=0&count=10" \
-u key:secret
```

Response

```json
{
  "data": [
    {
      "id": 50,
      "name": "CI notifier",
      "url": "https://example.com/hooks/testingbot",
      "http_method": "POST",
      "failure_only": true,
      "alert_types": "ALL",
      "name_filter": null,
      "auth_type": "NONE",
      "headers": [{ "key": "X-Source", "value": "testingbot" }],
      "params": [],
      "payload_template": null,
      "created_at": "2026-08-03T10:00:32.000Z",
      "updated_at": "2026-08-03T10:00:32.000Z"
    }
  ],
  "meta": { "offset": 0, "count": 10, "total": 1 }
}
```

GET `/v1/webhooks/{id}`

## Get a specific webhook
 Returns a single webhook by ID. Receiver credentials and the signing secret are never included. 
### Arguments

- **`id` integer required:** Numeric webhook ID.

### Response fields

- **`id` integer:** Unique numeric webhook ID.
- **`name` string:** Label for the webhook, shown on the dashboard.
- **`url` string:** Destination URL. May contain `{{VARIABLES}}`, which are substituted at delivery time.
- **`http_method` string:** HTTP method used to deliver: POST, PUT or PATCH.
- **`failure_only` boolean:** When true, only failed tests trigger a delivery.
- **`alert_types` string:** Which grid the test ran on: ALL, VIRTUAL (VM) or REAL (physical device).
- **`name_filter` string:** Glob matched against the test name, falling back to the build identifier. Empty means every test.
- **`auth_type` string:** How the request authenticates against your endpoint: NONE, BASIC or BEARER. The credentials themselves are never returned.
- **`headers` array of object:** Custom request headers, each `{ "key": ..., "value": ... }`. Values support `{{VARIABLES}}`.
- **`params` array of object:** Custom query parameters appended to the URL, each `{ "key": ..., "value": ... }`.
- **`payload_template` string:** Custom JSON body template. Empty means the default TestingBot payload is sent.
- **`created_at` timestamp:** When the webhook was created.
- **`updated_at` timestamp:** When the webhook was last changed.
- **`signing_secret` string:** Secret used to verify the `X-TestingBot-Signature` header. Only present when the webhook is created or its secret is rotated; store it then, because it is never returned again.

GET `/v1/webhooks/{id}`
[cURL](https://testingbot.com#)
Request

```bash
$ curl "https://api.testingbot.com/v1/webhooks/{id}" \
-u key:secret
```

Response

```json
{
  "id": 50,
  "name": "CI notifier",
  "url": "https://example.com/hooks/testingbot",
  "http_method": "POST",
  "failure_only": true,
  "alert_types": "ALL",
  "name_filter": null,
  "auth_type": "NONE",
  "headers": [{ "key": "X-Source", "value": "testingbot" }],
  "params": [],
  "payload_template": null,
  "created_at": "2026-08-03T10:00:32.000Z",
  "updated_at": "2026-08-03T10:00:32.000Z"
}
```

POST `/v1/webhooks`

## Create a webhook
 Creates a webhook. The response includes `signing_secret` — the only time it is ever returned — which you use to verify the `X-TestingBot-Signature` header on deliveries. A team may have at most 5 webhooks. 
### Arguments

- **`url` string required:** Destination URL. Must be a public http(s) address; private, loopback and link-local hosts are rejected.
- **`name` string:** Label for the webhook. Required once the extended webhook columns are present.
- **`http_method` string:** HTTP method used to deliver. Defaults to POST.
- **`failure_only` boolean:** Deliver only for failed tests. Defaults to false.
- **`alert_types` string:** Which grid to report on: ALL, VIRTUAL or REAL.
- **`name_filter` string:** Glob matched against the test name, falling back to the build identifier.
- **`auth_type` string:** How to authenticate against your endpoint: NONE, BASIC or BEARER.
- **`auth_username` string:** Username for BASIC auth. Write-only, never returned.
- **`auth_password` string:** Password for BASIC auth. Write-only, never returned.
- **`auth_token` string:** Token for BEARER auth. Write-only, never returned.
- **`headers` array:** Custom request headers, each an object with `key` and `value`.
- **`params` array:** Custom query parameters appended to the URL, each an object with `key` and `value`.
- **`payload_template` string:** Custom JSON body template using `{{VARIABLES}}`. Omit to send the default TestingBot payload.

POST `/v1/webhooks`
[cURL](https://testingbot.com#)
Request

```bash
$ curl -X POST "https://api.testingbot.com/v1/webhooks" \
-u key:secret \
-H "Content-Type: application/json" \
-d '{
  "name": "CI notifier",
  "url": "https://example.com/hooks/testingbot",
  "failure_only": true,
  "alert_types": "ALL",
  "headers": [{ "key": "X-Source", "value": "testingbot" }]
}'
```

Response

```json
{
  "id": 50,
  "name": "CI notifier",
  "url": "https://example.com/hooks/testingbot",
  "http_method": "POST",
  "failure_only": true,
  "alert_types": "ALL",
  "name_filter": null,
  "auth_type": "NONE",
  "headers": [{ "key": "X-Source", "value": "testingbot" }],
  "params": [],
  "payload_template": null,
  "created_at": "2026-08-03T10:00:32.000Z",
  "updated_at": "2026-08-03T10:00:32.000Z",
  "signing_secret": "whsec_a1b2c3d4e5f60718293a4b5c6d7e8f90"
}
```

PUT `/v1/webhooks/{id}`

## Update a webhook
 Updates a webhook. Only the fields you send are changed. Sending `auth_password` or `auth_token` replaces the stored value; omitting them leaves it alone. The signing secret is not returned — rotate it if you have lost it. 
### Arguments

- **`id` integer required:** Numeric webhook ID.
- **`url` string:** Destination URL. Must be a public http(s) address.
- **`name` string:** Label for the webhook.
- **`http_method` string:** HTTP method used to deliver.
- **`failure_only` boolean:** Deliver only for failed tests.
- **`alert_types` string:** Which grid to report on: ALL, VIRTUAL or REAL.
- **`name_filter` string:** Glob matched against the test name, falling back to the build identifier.
- **`auth_type` string:** How to authenticate against your endpoint.
- **`auth_username` string:** Username for BASIC auth. Write-only.
- **`auth_password` string:** Password for BASIC auth. Write-only.
- **`auth_token` string:** Token for BEARER auth. Write-only.
- **`headers` array:** Custom request headers, each an object with `key` and `value`. Replaces the existing set.
- **`params` array:** Custom query parameters, each an object with `key` and `value`. Replaces the existing set.
- **`payload_template` string:** Custom JSON body template. Send an empty string to go back to the default payload.

### Response fields

- **`id` integer:** Unique numeric webhook ID.
- **`name` string:** Label for the webhook, shown on the dashboard.
- **`url` string:** Destination URL. May contain `{{VARIABLES}}`, which are substituted at delivery time.
- **`http_method` string:** HTTP method used to deliver: POST, PUT or PATCH.
- **`failure_only` boolean:** When true, only failed tests trigger a delivery.
- **`alert_types` string:** Which grid the test ran on: ALL, VIRTUAL (VM) or REAL (physical device).
- **`name_filter` string:** Glob matched against the test name, falling back to the build identifier. Empty means every test.
- **`auth_type` string:** How the request authenticates against your endpoint: NONE, BASIC or BEARER. The credentials themselves are never returned.
- **`headers` array of object:** Custom request headers, each `{ "key": ..., "value": ... }`. Values support `{{VARIABLES}}`.
- **`params` array of object:** Custom query parameters appended to the URL, each `{ "key": ..., "value": ... }`.
- **`payload_template` string:** Custom JSON body template. Empty means the default TestingBot payload is sent.
- **`created_at` timestamp:** When the webhook was created.
- **`updated_at` timestamp:** When the webhook was last changed.
- **`signing_secret` string:** Secret used to verify the `X-TestingBot-Signature` header. Only present when the webhook is created or its secret is rotated; store it then, because it is never returned again.

PUT `/v1/webhooks/{id}`
[cURL](https://testingbot.com#)
Request

```bash
$ curl -X PUT "https://api.testingbot.com/v1/webhooks/{id}" \
-u key:secret \
-H "Content-Type: application/json" \
-d '{ "name": "CI notifier (failures only)", "failure_only": true }'
```

Response

```json
{
  "id": 50,
  "name": "CI notifier (failures only)",
  "url": "https://example.com/hooks/testingbot",
  "http_method": "POST",
  "failure_only": true,
  "alert_types": "ALL",
  "name_filter": null,
  "auth_type": "NONE",
  "headers": [{ "key": "X-Source", "value": "testingbot" }],
  "params": [],
  "payload_template": null,
  "created_at": "2026-08-03T10:00:32.000Z",
  "updated_at": "2026-08-03T10:04:11.000Z"
}
```

DELETE `/v1/webhooks/{id}`

## Delete a webhook
 Permanently deletes the webhook. Deliveries stop immediately; tests already in flight will not fire it. 
### Arguments

- **`id` integer required:** Numeric webhook ID.

DELETE `/v1/webhooks/{id}`
[cURL](https://testingbot.com#)
Request

```bash
$ curl -X DELETE "https://api.testingbot.com/v1/webhooks/{id}" \
-u key:secret
```

Response

```json
{
  "success": true,
  "message": "Webhook \"https://example.com/hooks/testingbot\" deleted."
}
```

POST `/v1/webhooks/{id}/rotate-secret`

## Rotate a webhook signing secret
 Issues a new signing secret and returns it. The previous secret stops verifying immediately, so update your receiver before rotating in production. This is the only other time the secret is returned. 
### Arguments

- **`id` integer required:** Numeric webhook ID.

POST `/v1/webhooks/{id}/rotate-secret`
[cURL](https://testingbot.com#)
Request

```bash
$ curl -X POST "https://api.testingbot.com/v1/webhooks/{id}/rotate-secret" \
-u key:secret
```

Response

```json
{
  "id": 50,
  "signing_secret": "whsec_f0e9d8c7b6a5948372615f4e3d2c1b0a"
}
```

POST `/v1/webhooks/{id}/test`

## Send a test delivery
 Delivers a sample payload to the webhook right now and returns what your endpoint responded, so you can verify the URL, authentication and signature verification without waiting for a test to finish. Sample data is used, not a real test result. Rate limited separately from the rest of the API. 
### Arguments

- **`id` integer required:** Numeric webhook ID.

POST `/v1/webhooks/{id}/test`
[cURL](https://testingbot.com#)
Request

```bash
$ curl -X POST "https://api.testingbot.com/v1/webhooks/{id}/test" \
-u key:secret
```

Response

```json
{
  "ok": true,
  "status": 200,
  "duration_ms": 148,
  "headers": { "content-type": "application/json" },
  "body": "{\"received\":true}",
  "sent_payload": "{\"id\":1,\"status\":\"FAILED\",\"name\":\"MyTest::testTitle\"}"
}
```

[Previous TestingBot Storage](https://testingbot.com/support/api/storage) [Next App Automate](https://testingbot.com/support/api/app-automate)
