Webhooks
Get told when links change, milestones are reached or conversions come in.
Webhooks need the Business plan, and the Administrator role or higher. Each event is posted as JSON, signed with the webhook's secret in the Blackgum-Signature header. The guide to receiving and checking events is at /docs/webhooks.
Every path below starts with https://bgum.me/api/v1/workspaces/{workspaceId}. Send your API key in the Authorization header as described in the API overview.
| Operation | Method and path |
|---|---|
| List webhooks | GET /webhooks |
| Add a webhook | POST /webhooks |
| Get a webhook | GET /webhooks/{webhookId} |
| Change a webhook | PATCH /webhooks/{webhookId} |
| Remove a webhook | DELETE /webhooks/{webhookId} |
| Replace the signing secret | POST /webhooks/{webhookId}/secret |
| Send a test event | POST /webhooks/{webhookId}/test |
| List deliveries | GET /webhooks/{webhookId}/deliveries |
| Send a delivery again | POST /webhooks/{webhookId}/deliveries/{deliveryId}/resend |
List webhooks
GET /webhooks
Lists the workspace's webhooks. Signing secrets are never shown again after they're created.
- Full path
/api/v1/workspaces/{workspaceId}/webhooks- API key scope
-
webhooks:read - Role needed
- Administrator or above
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
workspaceId |
string | Yes | Your workspace ID, from Settings → Workspace. |
Example request
curl
curl "https://bgum.me/api/v1/workspaces/$WORKSPACE_ID/webhooks" \
-H "Authorization: Bearer $BGL_API_KEY"
JavaScript
const res = await fetch(`https://bgum.me/api/v1/workspaces/${process.env.WORKSPACE_ID}/webhooks`, {
headers: {
Authorization: `Bearer ${process.env.BGL_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const data = await res.json();
console.log(data);
Python
import os
import requests
res = requests.get(
f"https://bgum.me/api/v1/workspaces/{os.environ['WORKSPACE_ID']}/webhooks",
headers={
"Authorization": f"Bearer {os.environ['BGL_API_KEY']}",
},
timeout=30,
)
res.raise_for_status()
print(res.json())
Response
200 OK · application/json
JSON
{
"items": [
{
"id": "hk7Qm2VfXa9R",
"url": "https://example.com/hooks/blackgum",
"description": "CRM sync",
"format": "Json",
"events": [
"link.created",
"link.click_threshold",
"conversion.recorded"
],
"clickThresholds": [
100,
1000
],
"enabled": true,
"disabledAt": null,
"disabledReason": null,
"consecutiveFailures": 0,
"lastSuccessAt": "2026-10-15T01:12:09+00:00",
"createdAt": "2026-10-14T23:40:00+00:00",
"updatedAt": "2026-10-14T23:40:00+00:00"
}
]
}
Errors
Any request can also return the general errors: 401 for a missing or wrong key, 403 for a missing scope or plan feature, 404 for an unknown workspace and 429 when you're sending too fast.
Add a webhook
POST /webhooks
Adds a webhook and returns it with its signing secret. Store the secret now: it isn't shown again.
- Full path
/api/v1/workspaces/{workspaceId}/webhooks- API key scope
-
webhooks:write - Role needed
- Administrator or above
- Plan
- Needs webhooks in your plan (compare plans)
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
workspaceId |
string | Yes | Your workspace ID, from Settings → Workspace. |
Request body
JSON (Content-Type: application/json). Leave out fields you don't need.
| Name | Type | Required | Description |
|---|---|---|---|
url |
string | Yes | Where to post events: a full https:// address on the public internet. For Slack, the incoming webhook address (https://hooks.slack.com/…); for Teams, the workflow or incoming webhook address. |
format |
string | No | Json (default): the signed event, for your own code, Zapier or Make. Slack or Teams: a short message for a channel. |
events |
string[] | Yes | Event types to send, such as ["link.created", "conversion.recorded"]. See the webhooks guide for the list. |
clickThresholds |
integer[] | No | Click milestones for link.click_threshold, such as [100, 1000]: numbers of clicks from people, up to 10 of them. |
description |
string | No | A note for yourself, up to 200 characters. |
enabled |
boolean | No | false stops sending without removing the webhook. Default true. |
Example request
curl
curl -X POST "https://bgum.me/api/v1/workspaces/$WORKSPACE_ID/webhooks" \
-H "Authorization: Bearer $BGL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/hooks/blackgum",
"description": "CRM sync",
"events": [
"link.created",
"link.click_threshold",
"conversion.recorded"
],
"clickThresholds": [
100,
1000
]
}'
JavaScript
const res = await fetch(`https://bgum.me/api/v1/workspaces/${process.env.WORKSPACE_ID}/webhooks`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.BGL_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"url": "https://example.com/hooks/blackgum",
"description": "CRM sync",
"events": [
"link.created",
"link.click_threshold",
"conversion.recorded"
],
"clickThresholds": [
100,
1000
]
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const data = await res.json();
console.log(data);
Python
import os
import requests
res = requests.post(
f"https://bgum.me/api/v1/workspaces/{os.environ['WORKSPACE_ID']}/webhooks",
headers={
"Authorization": f"Bearer {os.environ['BGL_API_KEY']}",
},
json={
"url": "https://example.com/hooks/blackgum",
"description": "CRM sync",
"events": ["link.created", "link.click_threshold", "conversion.recorded"],
"clickThresholds": [100, 1000],
},
timeout=30,
)
res.raise_for_status()
print(res.json())
Response
201 Created · application/json
JSON
{
"webhook": {
"id": "hk7Qm2VfXa9R",
"url": "https://example.com/hooks/blackgum",
"description": "CRM sync",
"format": "Json",
"events": [
"link.created",
"link.click_threshold",
"conversion.recorded"
],
"clickThresholds": [
100,
1000
],
"enabled": true,
"disabledAt": null,
"disabledReason": null,
"consecutiveFailures": 0,
"lastSuccessAt": "2026-10-15T01:12:09+00:00",
"createdAt": "2026-10-14T23:40:00+00:00",
"updatedAt": "2026-10-14T23:40:00+00:00"
},
"secret": "whsec_8yJ2kQ0w-LmV3pX9sT4rZbN6cF1aGhD5eU7iO2qWnYk"
}
Good to know
- secret is null for Slack and Teams webhooks: those requests aren't signed.
- A workspace can have up to 10 webhooks. One webhook can receive several event types.
- Send a test event to check the address works before you rely on it.
Errors
| Status | Code | Meaning |
|---|---|---|
| 422 | webhook.url_required | url is missing. |
| 422 | webhook.url_invalid | url isn't a full web address, or it includes a user name or password. |
| 422 | webhook.url_https | url starts with http://. |
| 422 | webhook.url_private | url points at a local or private network address. |
| 422 | webhook.url_not_slack | format is slack, but url isn't a Slack incoming webhook address. |
| 422 | webhook.url_not_teams | format is teams, but url isn't a Microsoft Teams webhook address. |
| 422 | webhook.format_invalid | format isn't one of the allowed values. |
| 422 | webhook.events_required | events is empty. |
| 422 | webhook.event_unknown | events contains a name we don't send. |
| 422 | webhook.threshold_invalid | A click milestone isn't a whole number from 1 to 1,000,000,000. |
| 422 | webhook.too_many_thresholds | More than 10 click milestones. |
| 422 | webhook.thresholds_required | link.click_threshold is chosen but there are no click milestones. |
| 422 | webhook.description_too_long | description is longer than 200 characters. |
| 409 | webhook.limit_reached | The workspace already has 10 webhooks. |
Any request can also return the general errors: 401 for a missing or wrong key, 403 for a missing scope or plan feature, 404 for an unknown workspace and 429 when you're sending too fast.
Get a webhook
GET /webhooks/{webhookId}
Returns one webhook, including whether it's failing or was turned off after failures.
- Full path
/api/v1/workspaces/{workspaceId}/webhooks/{webhookId}- API key scope
-
webhooks:read - Role needed
- Administrator or above
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
workspaceId |
string | Yes | Your workspace ID, from Settings → Workspace. |
webhookId |
string | Yes | The webhook's ID, as returned when it was created or listed. |
Example request
curl
curl "https://bgum.me/api/v1/workspaces/$WORKSPACE_ID/webhooks/hk7Qm2VfXa9R" \
-H "Authorization: Bearer $BGL_API_KEY"
JavaScript
const res = await fetch(`https://bgum.me/api/v1/workspaces/${process.env.WORKSPACE_ID}/webhooks/hk7Qm2VfXa9R`, {
headers: {
Authorization: `Bearer ${process.env.BGL_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const data = await res.json();
console.log(data);
Python
import os
import requests
res = requests.get(
f"https://bgum.me/api/v1/workspaces/{os.environ['WORKSPACE_ID']}/webhooks/hk7Qm2VfXa9R",
headers={
"Authorization": f"Bearer {os.environ['BGL_API_KEY']}",
},
timeout=30,
)
res.raise_for_status()
print(res.json())
Response
200 OK · application/json
JSON
{
"id": "hk7Qm2VfXa9R",
"url": "https://example.com/hooks/blackgum",
"description": "CRM sync",
"format": "Json",
"events": [
"link.created",
"link.click_threshold",
"conversion.recorded"
],
"clickThresholds": [
100,
1000
],
"enabled": true,
"disabledAt": null,
"disabledReason": null,
"consecutiveFailures": 0,
"lastSuccessAt": "2026-10-15T01:12:09+00:00",
"createdAt": "2026-10-14T23:40:00+00:00",
"updatedAt": "2026-10-14T23:40:00+00:00"
}
Good to know
- consecutiveFailures counts failed attempts since the last success. disabledAt and disabledReason are set when we turned the webhook off because nothing got through for about a day.
Errors
| Status | Code | Meaning |
|---|---|---|
| 404 | webhook.not_found | No webhook with that ID in this workspace. |
Any request can also return the general errors: 401 for a missing or wrong key, 403 for a missing scope or plan feature, 404 for an unknown workspace and 429 when you're sending too fast.
Change a webhook
PATCH /webhooks/{webhookId}
Changes the fields you send and leaves the rest. Send enabled: true to turn a webhook back on after it was turned off.
- Full path
/api/v1/workspaces/{workspaceId}/webhooks/{webhookId}- API key scope
-
webhooks:write - Role needed
- Administrator or above
- Plan
- Needs webhooks in your plan (compare plans)
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
workspaceId |
string | Yes | Your workspace ID, from Settings → Workspace. |
webhookId |
string | Yes | The webhook's ID, as returned when it was created or listed. |
Request body
JSON (Content-Type: application/json). Leave out fields you don't need.
| Name | Type | Required | Description |
|---|---|---|---|
url |
string | No | Where to post events: a full https:// address on the public internet. For Slack, the incoming webhook address (https://hooks.slack.com/…); for Teams, the workflow or incoming webhook address. |
format |
string | No | Json (default): the signed event, for your own code, Zapier or Make. Slack or Teams: a short message for a channel. |
events |
string[] | No | Event types to send, such as ["link.created", "conversion.recorded"]. See the webhooks guide for the list. |
clickThresholds |
integer[] | No | Click milestones for link.click_threshold, such as [100, 1000]: numbers of clicks from people, up to 10 of them. |
description |
string | No | A note for yourself, up to 200 characters. |
enabled |
boolean | No | false stops sending without removing the webhook. Default true. |
Example request
curl
curl -X PATCH "https://bgum.me/api/v1/workspaces/$WORKSPACE_ID/webhooks/hk7Qm2VfXa9R" \
-H "Authorization: Bearer $BGL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"enabled": true,
"events": [
"link.created",
"link.deleted"
]
}'
JavaScript
const res = await fetch(`https://bgum.me/api/v1/workspaces/${process.env.WORKSPACE_ID}/webhooks/hk7Qm2VfXa9R`, {
method: "PATCH",
headers: {
Authorization: `Bearer ${process.env.BGL_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"enabled": true,
"events": [
"link.created",
"link.deleted"
]
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const data = await res.json();
console.log(data);
Python
import os
import requests
res = requests.patch(
f"https://bgum.me/api/v1/workspaces/{os.environ['WORKSPACE_ID']}/webhooks/hk7Qm2VfXa9R",
headers={
"Authorization": f"Bearer {os.environ['BGL_API_KEY']}",
},
json={
"enabled": True,
"events": ["link.created", "link.deleted"],
},
timeout=30,
)
res.raise_for_status()
print(res.json())
Response
200 OK · application/json
JSON
{
"id": "hk7Qm2VfXa9R",
"url": "https://example.com/hooks/blackgum",
"description": "CRM sync",
"format": "Json",
"events": [
"link.created",
"link.deleted"
],
"clickThresholds": [
100,
1000
],
"enabled": true,
"disabledAt": null,
"disabledReason": null,
"consecutiveFailures": 0,
"lastSuccessAt": "2026-10-15T01:12:09+00:00",
"createdAt": "2026-10-14T23:40:00+00:00",
"updatedAt": "2026-10-14T23:40:00+00:00"
}
Good to know
- Turning a webhook back on clears its failure count. Events that happened while it was off aren't sent.
Errors
| Status | Code | Meaning |
|---|---|---|
| 404 | webhook.not_found | No webhook with that ID in this workspace. |
| 422 | webhook.url_invalid | url isn't a full web address, or it includes a user name or password. |
| 422 | webhook.url_https | url starts with http://. |
| 422 | webhook.url_private | url points at a local or private network address. |
| 422 | webhook.url_not_slack | format is slack, but url isn't a Slack incoming webhook address. |
| 422 | webhook.url_not_teams | format is teams, but url isn't a Microsoft Teams webhook address. |
| 422 | webhook.format_invalid | format isn't one of the allowed values. |
| 422 | webhook.events_required | events is empty. |
| 422 | webhook.event_unknown | events contains a name we don't send. |
| 422 | webhook.threshold_invalid | A click milestone isn't a whole number from 1 to 1,000,000,000. |
| 422 | webhook.too_many_thresholds | More than 10 click milestones. |
| 422 | webhook.thresholds_required | link.click_threshold is chosen but there are no click milestones. |
| 422 | webhook.description_too_long | description is longer than 200 characters. |
Any request can also return the general errors: 401 for a missing or wrong key, 403 for a missing scope or plan feature, 404 for an unknown workspace and 429 when you're sending too fast.
Remove a webhook
DELETE /webhooks/{webhookId}
Removes the webhook and its delivery history. Events waiting to be sent to it are dropped.
- Full path
/api/v1/workspaces/{workspaceId}/webhooks/{webhookId}- API key scope
-
webhooks:write - Role needed
- Administrator or above
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
workspaceId |
string | Yes | Your workspace ID, from Settings → Workspace. |
webhookId |
string | Yes | The webhook's ID, as returned when it was created or listed. |
Example request
curl
curl -X DELETE "https://bgum.me/api/v1/workspaces/$WORKSPACE_ID/webhooks/hk7Qm2VfXa9R" \
-H "Authorization: Bearer $BGL_API_KEY"
JavaScript
const res = await fetch(`https://bgum.me/api/v1/workspaces/${process.env.WORKSPACE_ID}/webhooks/hk7Qm2VfXa9R`, {
method: "DELETE",
headers: {
Authorization: `Bearer ${process.env.BGL_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
// 204 No Content: nothing to read.
Python
import os
import requests
res = requests.delete(
f"https://bgum.me/api/v1/workspaces/{os.environ['WORKSPACE_ID']}/webhooks/hk7Qm2VfXa9R",
headers={
"Authorization": f"Bearer {os.environ['BGL_API_KEY']}",
},
timeout=30,
)
res.raise_for_status()
# 204 No Content: nothing to read.
Response
204 No Content
Errors
| Status | Code | Meaning |
|---|---|---|
| 404 | webhook.not_found | No webhook with that ID in this workspace. |
Any request can also return the general errors: 401 for a missing or wrong key, 403 for a missing scope or plan feature, 404 for an unknown workspace and 429 when you're sending too fast.
Replace the signing secret
POST /webhooks/{webhookId}/secret
Makes a new signing secret and returns it once. The old secret stops working straight away, so update your receiver at the same time.
- Full path
/api/v1/workspaces/{workspaceId}/webhooks/{webhookId}/secret- API key scope
-
webhooks:write - Role needed
- Administrator or above
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
workspaceId |
string | Yes | Your workspace ID, from Settings → Workspace. |
webhookId |
string | Yes | The webhook's ID, as returned when it was created or listed. |
Example request
curl
curl -X POST "https://bgum.me/api/v1/workspaces/$WORKSPACE_ID/webhooks/hk7Qm2VfXa9R/secret" \
-H "Authorization: Bearer $BGL_API_KEY"
JavaScript
const res = await fetch(`https://bgum.me/api/v1/workspaces/${process.env.WORKSPACE_ID}/webhooks/hk7Qm2VfXa9R/secret`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.BGL_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const data = await res.json();
console.log(data);
Python
import os
import requests
res = requests.post(
f"https://bgum.me/api/v1/workspaces/{os.environ['WORKSPACE_ID']}/webhooks/hk7Qm2VfXa9R/secret",
headers={
"Authorization": f"Bearer {os.environ['BGL_API_KEY']}",
},
timeout=30,
)
res.raise_for_status()
print(res.json())
Response
200 OK · application/json
JSON
{
"webhook": {
"id": "hk7Qm2VfXa9R",
"url": "https://example.com/hooks/blackgum",
"description": "CRM sync",
"format": "Json",
"events": [
"link.created",
"link.click_threshold",
"conversion.recorded"
],
"clickThresholds": [
100,
1000
],
"enabled": true,
"disabledAt": null,
"disabledReason": null,
"consecutiveFailures": 0,
"lastSuccessAt": "2026-10-15T01:12:09+00:00",
"createdAt": "2026-10-14T23:40:00+00:00",
"updatedAt": "2026-10-14T23:40:00+00:00"
},
"secret": "whsec_Q2fN7mV0pX4sK9tR1zB6cL3aJ8hE5dU0yW2oI7gTnMk"
}
Errors
| Status | Code | Meaning |
|---|---|---|
| 404 | webhook.not_found | No webhook with that ID in this workspace. |
Any request can also return the general errors: 401 for a missing or wrong key, 403 for a missing scope or plan feature, 404 for an unknown workspace and 429 when you're sending too fast.
Send a test event
POST /webhooks/{webhookId}/test
Queues a ping event for this webhook. It's usually sent within a few seconds; check the result with List deliveries.
- Full path
/api/v1/workspaces/{workspaceId}/webhooks/{webhookId}/test- API key scope
-
webhooks:write - Role needed
- Administrator or above
- Plan
- Needs webhooks in your plan (compare plans)
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
workspaceId |
string | Yes | Your workspace ID, from Settings → Workspace. |
webhookId |
string | Yes | The webhook's ID, as returned when it was created or listed. |
Example request
curl
curl -X POST "https://bgum.me/api/v1/workspaces/$WORKSPACE_ID/webhooks/hk7Qm2VfXa9R/test" \
-H "Authorization: Bearer $BGL_API_KEY"
JavaScript
const res = await fetch(`https://bgum.me/api/v1/workspaces/${process.env.WORKSPACE_ID}/webhooks/hk7Qm2VfXa9R/test`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.BGL_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const data = await res.json();
console.log(data);
Python
import os
import requests
res = requests.post(
f"https://bgum.me/api/v1/workspaces/{os.environ['WORKSPACE_ID']}/webhooks/hk7Qm2VfXa9R/test",
headers={
"Authorization": f"Bearer {os.environ['BGL_API_KEY']}",
},
timeout=30,
)
res.raise_for_status()
print(res.json())
Response
202 · application/json
JSON
{
"id": "dQ4nT8wLp2Zs",
"eventId": "evt_3kQ9zV1mXw7TbR2aYpLc",
"eventType": "ping",
"state": "Pending",
"attempts": 0,
"statusCode": null,
"durationMs": null,
"error": null,
"responseBody": null,
"createdAt": "2026-10-15T01:12:08+00:00",
"lastAttemptAt": null,
"nextAttemptAt": "2026-10-15T01:12:08+00:00",
"deliveredAt": null
}
Errors
| Status | Code | Meaning |
|---|---|---|
| 404 | webhook.not_found | No webhook with that ID in this workspace. |
| 409 | webhook.disabled | The webhook is turned off, so it can't be sent a test or a repeat. |
Any request can also return the general errors: 401 for a missing or wrong key, 403 for a missing scope or plan feature, 404 for an unknown workspace and 429 when you're sending too fast.
List deliveries
GET /webhooks/{webhookId}/deliveries
Returns the webhook's last 50 deliveries, newest first, with the response we got back.
- Full path
/api/v1/workspaces/{workspaceId}/webhooks/{webhookId}/deliveries- API key scope
-
webhooks:read - Role needed
- Administrator or above
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
workspaceId |
string | Yes | Your workspace ID, from Settings → Workspace. |
webhookId |
string | Yes | The webhook's ID, as returned when it was created or listed. |
Example request
curl
curl "https://bgum.me/api/v1/workspaces/$WORKSPACE_ID/webhooks/hk7Qm2VfXa9R/deliveries" \
-H "Authorization: Bearer $BGL_API_KEY"
JavaScript
const res = await fetch(`https://bgum.me/api/v1/workspaces/${process.env.WORKSPACE_ID}/webhooks/hk7Qm2VfXa9R/deliveries`, {
headers: {
Authorization: `Bearer ${process.env.BGL_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const data = await res.json();
console.log(data);
Python
import os
import requests
res = requests.get(
f"https://bgum.me/api/v1/workspaces/{os.environ['WORKSPACE_ID']}/webhooks/hk7Qm2VfXa9R/deliveries",
headers={
"Authorization": f"Bearer {os.environ['BGL_API_KEY']}",
},
timeout=30,
)
res.raise_for_status()
print(res.json())
Response
200 OK · application/json
JSON
{
"items": [
{
"id": "dQ4nT8wLp2Zs",
"eventId": "evt_3kQ9zV1mXw7TbR2aYpLc",
"eventType": "link.created",
"state": "Delivered",
"attempts": 1,
"statusCode": 200,
"durationMs": 184,
"error": null,
"responseBody": "ok",
"createdAt": "2026-10-15T01:12:08+00:00",
"lastAttemptAt": "2026-10-15T01:12:09+00:00",
"nextAttemptAt": null,
"deliveredAt": "2026-10-15T01:12:09+00:00"
}
]
}
Good to know
- state is Pending (waiting for its first try or a retry), Delivered (your server answered with a 2xx status) or Failed (every retry failed, or the webhook was turned off first).
- responseBody holds the first 2,000 characters of your server's answer. Deliveries are kept for 30 days.
Errors
| Status | Code | Meaning |
|---|---|---|
| 404 | webhook.not_found | No webhook with that ID in this workspace. |
Any request can also return the general errors: 401 for a missing or wrong key, 403 for a missing scope or plan feature, 404 for an unknown workspace and 429 when you're sending too fast.
Send a delivery again
POST /webhooks/{webhookId}/deliveries/{deliveryId}/resend
Queues the same event again, with the same event ID, as a new delivery. Useful after fixing your receiver.
- Full path
/api/v1/workspaces/{workspaceId}/webhooks/{webhookId}/deliveries/{deliveryId}/resend- API key scope
-
webhooks:write - Role needed
- Administrator or above
- Plan
- Needs webhooks in your plan (compare plans)
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
workspaceId |
string | Yes | Your workspace ID, from Settings → Workspace. |
webhookId |
string | Yes | The webhook's ID, as returned when it was created or listed. |
deliveryId |
string | Yes | The delivery's ID, as returned when it was created or listed. |
Example request
curl
curl -X POST "https://bgum.me/api/v1/workspaces/$WORKSPACE_ID/webhooks/hk7Qm2VfXa9R/deliveries/dQ4nT8wLp2Zs/resend" \
-H "Authorization: Bearer $BGL_API_KEY"
JavaScript
const res = await fetch(`https://bgum.me/api/v1/workspaces/${process.env.WORKSPACE_ID}/webhooks/hk7Qm2VfXa9R/deliveries/dQ4nT8wLp2Zs/resend`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.BGL_API_KEY}`,
},
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const data = await res.json();
console.log(data);
Python
import os
import requests
res = requests.post(
f"https://bgum.me/api/v1/workspaces/{os.environ['WORKSPACE_ID']}/webhooks/hk7Qm2VfXa9R/deliveries/dQ4nT8wLp2Zs/resend",
headers={
"Authorization": f"Bearer {os.environ['BGL_API_KEY']}",
},
timeout=30,
)
res.raise_for_status()
print(res.json())
Response
202 · application/json
JSON
{
"id": "fR6uY1kM9cVb",
"eventId": "evt_3kQ9zV1mXw7TbR2aYpLc",
"eventType": "link.created",
"state": "Pending",
"attempts": 0,
"statusCode": null,
"durationMs": null,
"error": null,
"responseBody": null,
"createdAt": "2026-10-15T01:12:08+00:00",
"lastAttemptAt": null,
"nextAttemptAt": "2026-10-15T02:00:00+00:00",
"deliveredAt": null
}
Errors
| Status | Code | Meaning |
|---|---|---|
| 404 | webhook.not_found | No webhook with that ID in this workspace. |
| 404 | webhook.delivery_not_found | No delivery with that ID for this webhook. |
| 409 | webhook.disabled | The webhook is turned off, so it can't be sent a test or a repeat. |
Any request can also return the general errors: 401 for a missing or wrong key, 403 for a missing scope or plan feature, 404 for an unknown workspace and 429 when you're sending too fast.
Something missing or unclear? Tell us and we'll improve this page.