API reference
Webhook endpoints and deliveries
Event types, endpoints, test events and the delivery log.
11 actions · base URL https://api.bizisy.com/v1 · generated from the same definitions as the API.
List webhook event types#
POST/v1/webhooks/events.listRead
Lists the event types an endpoint can subscribe to: type (e.g. person.hired), group and when it fires. Payloads carry ids, the time and the record's public and job details (never private or pay data); fetch more through the API. Owners and admins.
- Who can call it
- Manage key owner admin
- MCP tool
webhooks_events_liston HR Assistant- Method
POSTwith a JSON body, orGETwith the input as query parameters
Input
No input: send {}.
Returns
An array of objects:
typestringrequiredgroupstringrequireddescriptionstringrequired
Errors
validation_failed unauthenticated forbidden not_found rate_limited internal
curl https://api.bizisy.com/v1/webhooks/events.list \
-H "Authorization: Bearer $BIZISY_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'const res = await fetch('https://api.bizisy.com/v1/webhooks/events.list', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.BIZISY_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({}),
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
console.log(body.data);import os
import requests
res = requests.post(
"https://api.bizisy.com/v1/webhooks/events.list",
headers={"Authorization": f"Bearer {os.environ['BIZISY_API_KEY']}"},
json={},
)
body = res.json()
if not res.ok:
raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
print(body["data"]){
"data": [
{
"type": "person.hired",
"group": "People",
"description": "Someone was added with their first job."
}
]
}List webhook endpoints#
POST/v1/webhooks/endpoints.listRead
Lists the organization's webhook endpoints, oldest first: URL, description, subscribed event types, whether it is on (disabled_reason says why not), health (failing_since, consecutive_failures, last_delivery) and the secret hint. Never returns secrets. Owners and admins.
- Who can call it
- Manage key owner admin
- MCP tool
webhooks_endpoints_liston HR Assistant- Method
POSTwith a JSON body, orGETwith the input as query parameters
Input
No input: send {}.
Returns
An array of objects with 14 fields
An array of objects:
idstringrequiredurlstringrequireddescriptionstringrequiredevent_typesstring[]requiredenabledbooleanrequireddisabled_reason"manual" | "failing" | "closed"requiredWhy it is off: manual (someone turned it off), failing (Bizisy turned it off after a day of failed deliveries), closed (company closure).
disabled_atstring | nullrequiredfailing_sincestring | nullrequiredFirst failed attempt since the last success; null when the last attempt succeeded.
consecutive_failuresintegerrequiredlast_deliveryobject | nullrequired3 fields
atstringrequiredstatus"succeeded" | "failed"requiredresponse_statusinteger | nullrequired
secret_hintstringrequiredThe signing secret's prefix and last 4 characters; the secret itself is shown only once.
previous_secret_expires_atstring | nullrequiredAfter a roll: until when the previous secret also signs each request.
created_atstringrequiredupdated_atstringrequired
Errors
validation_failed unauthenticated forbidden not_found rate_limited internal
curl https://api.bizisy.com/v1/webhooks/endpoints.list \
-H "Authorization: Bearer $BIZISY_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'const res = await fetch('https://api.bizisy.com/v1/webhooks/endpoints.list', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.BIZISY_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({}),
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
console.log(body.data);import os
import requests
res = requests.post(
"https://api.bizisy.com/v1/webhooks/endpoints.list",
headers={"Authorization": f"Bearer {os.environ['BIZISY_API_KEY']}"},
json={},
)
body = res.json()
if not res.ok:
raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
print(body["data"]){
"data": [
{
"id": "we1",
"url": "https://hooks.example.com/bizisy",
"description": "Payroll sync",
"event_types": [
"person.hired",
"person.terminated"
],
"enabled": true,
"disabled_reason": null,
"disabled_at": null,
"failing_since": null,
"consecutive_failures": 0,
"last_delivery": {
"at": "2026-10-04T10:01:00.000Z",
"status": "succeeded",
"response_status": 200
},
"secret_hint": "whsec_…Ab3=",
"previous_secret_expires_at": null,
"created_at": "2026-10-04T10:00:00.000Z",
"updated_at": "2026-10-04T10:00:00.000Z"
}
]
}Get a webhook endpoint#
POST/v1/webhooks/endpoints.getRead
Returns one webhook endpoint (as in webhooks_endpoints_list). Owners and admins.
- Who can call it
- Manage key owner admin
- MCP tool
webhooks_endpoints_geton HR Assistant- Method
POSTwith a JSON body, orGETwith the input as query parameters
Input
endpoint_idstringrequired
Returns
14 fields
idstringrequiredurlstringrequireddescriptionstringrequiredevent_typesstring[]requiredenabledbooleanrequireddisabled_reason"manual" | "failing" | "closed"requiredWhy it is off: manual (someone turned it off), failing (Bizisy turned it off after a day of failed deliveries), closed (company closure).
disabled_atstring | nullrequiredfailing_sincestring | nullrequiredFirst failed attempt since the last success; null when the last attempt succeeded.
consecutive_failuresintegerrequiredlast_deliveryobject | nullrequired3 fields
atstringrequiredstatus"succeeded" | "failed"requiredresponse_statusinteger | nullrequired
secret_hintstringrequiredThe signing secret's prefix and last 4 characters; the secret itself is shown only once.
previous_secret_expires_atstring | nullrequiredAfter a roll: until when the previous secret also signs each request.
created_atstringrequiredupdated_atstringrequired
Errors
validation_failed unauthenticated forbidden not_found rate_limited internal
curl https://api.bizisy.com/v1/webhooks/endpoints.get \
-H "Authorization: Bearer $BIZISY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"endpoint_id":"we1"}'const res = await fetch('https://api.bizisy.com/v1/webhooks/endpoints.get', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.BIZISY_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"endpoint_id": "we1"
}),
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
console.log(body.data);import os
import requests
res = requests.post(
"https://api.bizisy.com/v1/webhooks/endpoints.get",
headers={"Authorization": f"Bearer {os.environ['BIZISY_API_KEY']}"},
json={
"endpoint_id": "we1",
},
)
body = res.json()
if not res.ok:
raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
print(body["data"]){
"data": {
"id": "we1",
"url": "https://hooks.example.com/bizisy",
"description": "Payroll sync",
"event_types": [
"person.hired",
"person.terminated"
],
"enabled": true,
"disabled_reason": null,
"disabled_at": null,
"failing_since": null,
"consecutive_failures": 0,
"last_delivery": {
"at": "2026-10-04T10:01:00.000Z",
"status": "succeeded",
"response_status": 200
},
"secret_hint": "whsec_…Ab3=",
"previous_secret_expires_at": null,
"created_at": "2026-10-04T10:00:00.000Z",
"updated_at": "2026-10-04T10:00:00.000Z"
}
}Add a webhook endpoint#
POST/v1/webhooks/endpoints.createWrite
Registers an HTTPS endpoint that receives the chosen event types (event_types from webhooks_events_list; at least one) as signed POST requests (Standard Webhooks: webhook-id, webhook-timestamp, webhook-signature headers). url must be https:// with a public host name (no IP addresses, no private or Bizisy hosts, port 443 or 1024–65535); description is optional; enabled defaults to true. Returns the signing secret (whsec_…) ONCE: store it in the receiver to verify signatures. Only events that happen after it is added are sent. At most 10 endpoints. Owners and admins, in the app only (refused over an API key or MCP). A dry run checks the input and never issues a secret.
- Web app only
- Refused for API keys and connected apps. Endpoints are added in the app only (the result is a secret, and data starts flowing to a new place).
- MCP tool
webhooks_endpoints_createon HR Assistant- Preview
?dry_run=trueruns every check and saves nothing- Retries
- An Idempotency-Key prevents a second run, but the result is never stored (it holds a secret or personal data): a retry gets a 409 that points to Activity
Input
urlstringrequiredhttps:// URL of your receiver (public host name, port 443 or 1024–65535).
1–2000 characters.
descriptionstringWhat this endpoint is for, e.g. "Payroll sync".
Up to 200 characters. Default
"".event_typesstring[]requiredEvent types to send, from
webhooks_events_list.1–100 characters. 1–100 items.
enabledbooleanDefault
true.
Returns
15 fields
idstringrequiredurlstringrequireddescriptionstringrequiredevent_typesstring[]requiredenabledbooleanrequireddisabled_reason"manual" | "failing" | "closed"requiredWhy it is off: manual (someone turned it off), failing (Bizisy turned it off after a day of failed deliveries), closed (company closure).
disabled_atstring | nullrequiredfailing_sincestring | nullrequiredFirst failed attempt since the last success; null when the last attempt succeeded.
consecutive_failuresintegerrequiredlast_deliveryobject | nullrequired3 fields
atstringrequiredstatus"succeeded" | "failed"requiredresponse_statusinteger | nullrequired
secret_hintstringrequiredThe signing secret's prefix and last 4 characters; the secret itself is shown only once.
previous_secret_expires_atstring | nullrequiredAfter a roll: until when the previous secret also signs each request.
created_atstringrequiredupdated_atstringrequiredsecretstringrequiredThe signing secret. Shown once; roll it with
webhooks_endpoints_roll_secretif lost.
Errors
validation_failed unauthenticated forbidden not_found conflict rate_limited internal
curl https://api.bizisy.com/v1/webhooks/endpoints.create \
-H "Authorization: Bearer $BIZISY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"url": "https://hooks.example.com/bizisy",
"description": "Payroll sync",
"event_types": [
"person.hired"
]
}'const res = await fetch('https://api.bizisy.com/v1/webhooks/endpoints.create', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.BIZISY_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({
"url": "https://hooks.example.com/bizisy",
"description": "Payroll sync",
"event_types": [
"person.hired"
]
}),
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
console.log(body.data);import os, uuid
import requests
res = requests.post(
"https://api.bizisy.com/v1/webhooks/endpoints.create",
headers={"Authorization": f"Bearer {os.environ['BIZISY_API_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"url": "https://hooks.example.com/bizisy",
"description": "Payroll sync",
"event_types": [
"person.hired",
],
},
)
body = res.json()
if not res.ok:
raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
print(body["data"]){
"data": {
"id": "we1",
"url": "https://hooks.example.com/bizisy",
"description": "Payroll sync",
"event_types": [
"person.hired",
"person.terminated"
],
"enabled": true,
"disabled_reason": null,
"disabled_at": null,
"failing_since": null,
"consecutive_failures": 0,
"last_delivery": {
"at": "2026-10-04T10:01:00.000Z",
"status": "succeeded",
"response_status": 200
},
"secret_hint": "whsec_…Ab3=",
"previous_secret_expires_at": null,
"created_at": "2026-10-04T10:00:00.000Z",
"updated_at": "2026-10-04T10:00:00.000Z",
"secret": "whsec_c2VjcmV0c2VjcmV0c2VjcmV0c2VjcmV0c2VjcmU="
}
}Change a webhook endpoint#
POST/v1/webhooks/endpoints.updateWrite
Changes an endpoint's url, description, event_types or enabled. Turning it off stops its pending deliveries (they become failed with endpoint_disabled; resend them later). Turning it back on clears the failure state, including after Bizisy turned it off for failing. A new host stops pending deliveries too, and every owner and admin is emailed. The secret is unchanged (see webhooks_endpoints_roll_secret). Over an API key or MCP only turning it off, the description and removing event types are allowed: a new URL, more events or turning it on happen in the app. Owners and admins.
- Who can call it
- Manage key owner admin
- Keys and apps
- Only turning an endpoint off, its description and removing event types; a new URL, more events or turning it on happen in the app.
- MCP tool
webhooks_endpoints_updateon HR Assistant- Preview
?dry_run=trueruns every check and saves nothing- Retries
- An Idempotency-Key prevents a second run, but the result is never stored (it holds a secret or personal data): a retry gets a 409 that points to Activity
Input
endpoint_idstringrequiredurlstringhttps:// URL of your receiver (public host name, port 443 or 1024–65535).
1–2000 characters.
descriptionstringWhat this endpoint is for, e.g. "Payroll sync".
Up to 200 characters.
event_typesstring[]Event types to send, from
webhooks_events_list.1–100 characters. 1–100 items.
enabledboolean
Returns
14 fields
idstringrequiredurlstringrequireddescriptionstringrequiredevent_typesstring[]requiredenabledbooleanrequireddisabled_reason"manual" | "failing" | "closed"requiredWhy it is off: manual (someone turned it off), failing (Bizisy turned it off after a day of failed deliveries), closed (company closure).
disabled_atstring | nullrequiredfailing_sincestring | nullrequiredFirst failed attempt since the last success; null when the last attempt succeeded.
consecutive_failuresintegerrequiredlast_deliveryobject | nullrequired3 fields
atstringrequiredstatus"succeeded" | "failed"requiredresponse_statusinteger | nullrequired
secret_hintstringrequiredThe signing secret's prefix and last 4 characters; the secret itself is shown only once.
previous_secret_expires_atstring | nullrequiredAfter a roll: until when the previous secret also signs each request.
created_atstringrequiredupdated_atstringrequired
Errors
validation_failed unauthenticated forbidden not_found conflict rate_limited internal
curl https://api.bizisy.com/v1/webhooks/endpoints.update \
-H "Authorization: Bearer $BIZISY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"endpoint_id": "we1",
"url": "https://h.example.com/y",
"description": "",
"event_types": [
"person.hired"
]
}'const res = await fetch('https://api.bizisy.com/v1/webhooks/endpoints.update', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.BIZISY_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({
"endpoint_id": "we1",
"url": "https://h.example.com/y",
"description": "",
"event_types": [
"person.hired"
]
}),
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
console.log(body.data);import os, uuid
import requests
res = requests.post(
"https://api.bizisy.com/v1/webhooks/endpoints.update",
headers={"Authorization": f"Bearer {os.environ['BIZISY_API_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"endpoint_id": "we1",
"url": "https://h.example.com/y",
"description": "",
"event_types": [
"person.hired",
],
},
)
body = res.json()
if not res.ok:
raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
print(body["data"]){
"data": {
"id": "we1",
"url": "https://h.example.com/y",
"description": "",
"event_types": [
"person.hired",
"person.terminated"
],
"enabled": false,
"disabled_reason": "manual",
"disabled_at": "2026-10-04T11:00:00.000Z",
"failing_since": null,
"consecutive_failures": 0,
"last_delivery": {
"at": "2026-10-04T10:01:00.000Z",
"status": "succeeded",
"response_status": 200
},
"secret_hint": "whsec_…Ab3=",
"previous_secret_expires_at": null,
"created_at": "2026-10-04T10:00:00.000Z",
"updated_at": "2026-10-04T10:00:00.000Z"
}
}Delete a webhook endpoint#
POST/v1/webhooks/endpoints.deleteDestructive
Deletes an endpoint and its delivery log. Nothing more is sent to it. Cannot be undone. Owners and admins, in the app only.
- Web app only
- Refused for API keys and connected apps. Endpoints are deleted in the app only.
- MCP tool
webhooks_endpoints_deleteon HR Assistant- Preview
?dry_run=trueruns every check and saves nothing- Retries
- An Idempotency-Key replays the first result
Input
endpoint_idstringrequired
Returns
idstringrequireddeletedtruerequired
Errors
validation_failed unauthenticated forbidden not_found conflict rate_limited internal
curl https://api.bizisy.com/v1/webhooks/endpoints.delete \
-H "Authorization: Bearer $BIZISY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"endpoint_id":"we1"}'const res = await fetch('https://api.bizisy.com/v1/webhooks/endpoints.delete', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.BIZISY_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({
"endpoint_id": "we1"
}),
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
console.log(body.data);import os, uuid
import requests
res = requests.post(
"https://api.bizisy.com/v1/webhooks/endpoints.delete",
headers={"Authorization": f"Bearer {os.environ['BIZISY_API_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"endpoint_id": "we1",
},
)
body = res.json()
if not res.ok:
raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
print(body["data"]){
"data": {
"id": "we1",
"deleted": true
}
}Roll a webhook signing secret#
POST/v1/webhooks/endpoints.roll_secretWrite
Replaces an endpoint's signing secret. Returns the new secret ONCE. For overlap_hours (0–72, default 24) every request carries signatures with both the new and the previous secret, so the receiver can switch without missing events; 0 stops the previous secret at once (use it when the secret leaked). Owners and admins, in the app only (the result is a secret).
- Web app only
- Refused for API keys and connected apps. Secrets are rolled in the app only (the result is a secret).
- MCP tool
webhooks_endpoints_roll_secreton HR Assistant- Preview
?dry_run=trueruns every check and saves nothing- Retries
- An Idempotency-Key prevents a second run, but the result is never stored (it holds a secret or personal data): a retry gets a 409 that points to Activity
Input
endpoint_idstringrequiredoverlap_hoursintegerFrom 0 to 72. Default
24.
Returns
endpointobjectrequired14 fields
idstringrequiredurlstringrequireddescriptionstringrequiredevent_typesstring[]requiredenabledbooleanrequireddisabled_reason"manual" | "failing" | "closed"requiredWhy it is off: manual (someone turned it off), failing (Bizisy turned it off after a day of failed deliveries), closed (company closure).
disabled_atstring | nullrequiredfailing_sincestring | nullrequiredFirst failed attempt since the last success; null when the last attempt succeeded.
consecutive_failuresintegerrequiredlast_deliveryobject | nullrequired3 fields
atstringrequiredstatus"succeeded" | "failed"requiredresponse_statusinteger | nullrequired
secret_hintstringrequiredThe signing secret's prefix and last 4 characters; the secret itself is shown only once.
previous_secret_expires_atstring | nullrequiredAfter a roll: until when the previous secret also signs each request.
created_atstringrequiredupdated_atstringrequired
secretstringrequired
Errors
validation_failed unauthenticated forbidden not_found conflict rate_limited internal
curl https://api.bizisy.com/v1/webhooks/endpoints.roll_secret \
-H "Authorization: Bearer $BIZISY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"endpoint_id":"we1","overlap_hours":0}'const res = await fetch('https://api.bizisy.com/v1/webhooks/endpoints.roll_secret', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.BIZISY_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({
"endpoint_id": "we1",
"overlap_hours": 0
}),
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
console.log(body.data);import os, uuid
import requests
res = requests.post(
"https://api.bizisy.com/v1/webhooks/endpoints.roll_secret",
headers={"Authorization": f"Bearer {os.environ['BIZISY_API_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"endpoint_id": "we1",
"overlap_hours": 0,
},
)
body = res.json()
if not res.ok:
raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
print(body["data"]){
"data": {
"endpoint": {
"id": "we1",
"url": "https://hooks.example.com/bizisy",
"description": "Payroll sync",
"event_types": [
"person.hired",
"person.terminated"
],
"enabled": true,
"disabled_reason": null,
"disabled_at": null,
"failing_since": null,
"consecutive_failures": 0,
"last_delivery": {
"at": "2026-10-04T10:01:00.000Z",
"status": "succeeded",
"response_status": 200
},
"secret_hint": "whsec_…Ab3=",
"previous_secret_expires_at": "2026-10-05T10:00:00.000Z",
"created_at": "2026-10-04T10:00:00.000Z",
"updated_at": "2026-10-04T10:00:00.000Z"
},
"secret": "whsec_bmV3c2VjcmV0bmV3c2VjcmV0bmV3c2VjcmV0bmU="
}
}Send a test event#
POST/v1/webhooks/endpoints.testWrite
Queues a webhook.test event for one endpoint; it is sent within about a minute, signed like every event, and appears in the delivery log (webhooks_deliveries_list). The endpoint must be on. At most 30 test events and resends per endpoint per hour. Owners and admins.
- Who can call it
- Manage key owner admin
- MCP tool
webhooks_endpoints_teston HR Assistant- Preview
?dry_run=trueruns every check and saves nothing- Retries
- An Idempotency-Key replays the first result
Input
endpoint_idstringrequired
Returns
15 fields
idstringrequiredendpoint_idstringrequiredevent_typestringrequiredmessage_idstringrequiredThe webhook-id header: the same on every retry and resend.
status"pending" | "succeeded" | "failed"requiredattemptsintegerrequiredmax_attemptsintegerrequirednext_attempt_atstring | nullrequiredlast_attempt_atstring | nullrequiredresponse_statusinteger | nullrequiredduration_msinteger | nullrequirederrorstring | nullrequiredWhy the last attempt failed: timeout, dns, blocked_address (the host resolves to a private address), connection, tls, redirect (redirects are never followed), http_status (not 2xx), invalid_url, endpoint_disabled, not_configured.
testbooleanrequiredevent_atstringrequiredcreated_atstringrequired
Errors
validation_failed unauthenticated forbidden not_found conflict rate_limited internal
curl https://api.bizisy.com/v1/webhooks/endpoints.test \
-H "Authorization: Bearer $BIZISY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"endpoint_id":"we1"}'const res = await fetch('https://api.bizisy.com/v1/webhooks/endpoints.test', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.BIZISY_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({
"endpoint_id": "we1"
}),
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
console.log(body.data);import os, uuid
import requests
res = requests.post(
"https://api.bizisy.com/v1/webhooks/endpoints.test",
headers={"Authorization": f"Bearer {os.environ['BIZISY_API_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"endpoint_id": "we1",
},
)
body = res.json()
if not res.ok:
raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
print(body["data"]){
"data": {
"id": "01k0000000000000000000000c.we1",
"endpoint_id": "we1",
"event_type": "webhook.test",
"message_id": "msg_01k0000000000000000000000b",
"status": "pending",
"attempts": 0,
"max_attempts": 8,
"next_attempt_at": "2026-10-04T10:02:00.000Z",
"last_attempt_at": null,
"response_status": null,
"duration_ms": null,
"error": null,
"test": true,
"event_at": "2026-10-04T10:00:30.000Z",
"created_at": "2026-10-04T10:01:00.000Z"
}
}List webhook deliveries#
POST/v1/webhooks/deliveries.listRead
The delivery log of one endpoint (last 30 days), newest first: event type, status (pending, succeeded, failed), attempts, the last response status, duration and error. Filter by status; page with before = the previous page's next_before. limit 1–100 (default 25). Owners and admins.
- Who can call it
- Manage key owner admin
- MCP tool
webhooks_deliveries_liston HR Assistant- Method
POSTwith a JSON body, orGETwith the input as query parameters
Input
endpoint_idstringrequiredstatus"pending" | "succeeded" | "failed"beforestringlimitintegerFrom 1 to 100. Default
25.
Returns
deliveriesobject[]required15 fields
idstringrequiredendpoint_idstringrequiredevent_typestringrequiredmessage_idstringrequiredThe webhook-id header: the same on every retry and resend.
status"pending" | "succeeded" | "failed"requiredattemptsintegerrequiredmax_attemptsintegerrequirednext_attempt_atstring | nullrequiredlast_attempt_atstring | nullrequiredresponse_statusinteger | nullrequiredduration_msinteger | nullrequirederrorstring | nullrequiredWhy the last attempt failed: timeout, dns, blocked_address (the host resolves to a private address), connection, tls, redirect (redirects are never followed), http_status (not 2xx), invalid_url, endpoint_disabled, not_configured.
testbooleanrequiredevent_atstringrequiredcreated_atstringrequired
next_beforestring | nullrequired
Errors
validation_failed unauthenticated forbidden not_found rate_limited internal
curl https://api.bizisy.com/v1/webhooks/deliveries.list \
-H "Authorization: Bearer $BIZISY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"endpoint_id": "we1",
"status": "failed",
"before": "01k0000000000000000000000b.we1",
"limit": 50
}'const res = await fetch('https://api.bizisy.com/v1/webhooks/deliveries.list', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.BIZISY_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"endpoint_id": "we1",
"status": "failed",
"before": "01k0000000000000000000000b.we1",
"limit": 50
}),
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
console.log(body.data);import os
import requests
res = requests.post(
"https://api.bizisy.com/v1/webhooks/deliveries.list",
headers={"Authorization": f"Bearer {os.environ['BIZISY_API_KEY']}"},
json={
"endpoint_id": "we1",
"status": "failed",
"before": "01k0000000000000000000000b.we1",
"limit": 50,
},
)
body = res.json()
if not res.ok:
raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
print(body["data"]){
"data": {
"deliveries": [
{
"id": "01k0000000000000000000000b.we1",
"endpoint_id": "we1",
"event_type": "person.hired",
"message_id": "msg_01k0000000000000000000000b",
"status": "succeeded",
"attempts": 1,
"max_attempts": 8,
"next_attempt_at": null,
"last_attempt_at": "2026-10-04T10:01:00.000Z",
"response_status": 200,
"duration_ms": 182,
"error": null,
"test": false,
"event_at": "2026-10-04T10:00:30.000Z",
"created_at": "2026-10-04T10:01:00.000Z"
}
],
"next_before": null
}
}Get a webhook delivery#
POST/v1/webhooks/deliveries.getRead
One delivery: the JSON body as it would be sent now (payload; delivery records keep ids only and each attempt fills in the record's current public and job details), its attempts and the start of the last answer (response_excerpt, at most 1 KB). Owners and admins.
- Who can call it
- Manage key owner admin
- MCP tool
webhooks_deliveries_geton HR Assistant- Method
POSTwith a JSON body, orGETwith the input as query parameters
Input
delivery_idstringrequired
Returns
18 fields
idstringrequiredendpoint_idstringrequiredevent_typestringrequiredmessage_idstringrequiredThe webhook-id header: the same on every retry and resend.
status"pending" | "succeeded" | "failed"requiredattemptsintegerrequiredmax_attemptsintegerrequirednext_attempt_atstring | nullrequiredlast_attempt_atstring | nullrequiredresponse_statusinteger | nullrequiredduration_msinteger | nullrequirederrorstring | nullrequiredWhy the last attempt failed: timeout, dns, blocked_address (the host resolves to a private address), connection, tls, redirect (redirects are never followed), http_status (not 2xx), invalid_url, endpoint_disabled, not_configured.
testbooleanrequiredevent_atstringrequiredcreated_atstringrequiredpayloadanyThe JSON body as it would be sent now: delivery records keep ids only, and the record's details are filled in at each attempt.
attempt_logobject[]required4 fields
atstringrequiredresponse_statusinteger | nullrequiredduration_msintegerrequirederrorstring | nullrequired
response_excerptstring | nullrequiredThe start of the last answer (at most 1 KB).
Errors
validation_failed unauthenticated forbidden not_found rate_limited internal
curl https://api.bizisy.com/v1/webhooks/deliveries.get \
-H "Authorization: Bearer $BIZISY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"delivery_id":"01k0000000000000000000000b.we1"}'const res = await fetch('https://api.bizisy.com/v1/webhooks/deliveries.get', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.BIZISY_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"delivery_id": "01k0000000000000000000000b.we1"
}),
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
console.log(body.data);import os
import requests
res = requests.post(
"https://api.bizisy.com/v1/webhooks/deliveries.get",
headers={"Authorization": f"Bearer {os.environ['BIZISY_API_KEY']}"},
json={
"delivery_id": "01k0000000000000000000000b.we1",
},
)
body = res.json()
if not res.ok:
raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
print(body["data"]){
"data": {
"id": "01k0000000000000000000000b.we1",
"endpoint_id": "we1",
"event_type": "person.hired",
"message_id": "msg_01k0000000000000000000000b",
"status": "succeeded",
"attempts": 1,
"max_attempts": 8,
"next_attempt_at": null,
"last_attempt_at": "2026-10-04T10:01:00.000Z",
"response_status": 200,
"duration_ms": 182,
"error": null,
"test": false,
"event_at": "2026-10-04T10:00:30.000Z",
"created_at": "2026-10-04T10:01:00.000Z",
"payload": {
"type": "person.hired",
"timestamp": "2026-10-04T10:00:30.000Z",
"data": {
"organization_id": "o1",
"person_id": "p1"
}
},
"attempt_log": [
{
"at": "2026-10-04T10:01:00.000Z",
"response_status": 200,
"duration_ms": 182,
"error": null
}
],
"response_excerpt": "ok"
}
}Resend a webhook delivery#
POST/v1/webhooks/deliveries.resendWrite
Sends a delivery again with a fresh retry schedule (same webhook-id, so receivers that already processed it can skip it; the record's details are as they are when it is sent). Within about a minute. Not for pending deliveries; the endpoint must be on. At most 30 test events and resends per endpoint per hour. Owners and admins.
- Who can call it
- Manage key owner admin
- MCP tool
webhooks_deliveries_resendon HR Assistant- Preview
?dry_run=trueruns every check and saves nothing- Retries
- An Idempotency-Key replays the first result
Input
delivery_idstringrequired
Returns
15 fields
idstringrequiredendpoint_idstringrequiredevent_typestringrequiredmessage_idstringrequiredThe webhook-id header: the same on every retry and resend.
status"pending" | "succeeded" | "failed"requiredattemptsintegerrequiredmax_attemptsintegerrequirednext_attempt_atstring | nullrequiredlast_attempt_atstring | nullrequiredresponse_statusinteger | nullrequiredduration_msinteger | nullrequirederrorstring | nullrequiredWhy the last attempt failed: timeout, dns, blocked_address (the host resolves to a private address), connection, tls, redirect (redirects are never followed), http_status (not 2xx), invalid_url, endpoint_disabled, not_configured.
testbooleanrequiredevent_atstringrequiredcreated_atstringrequired
Errors
validation_failed unauthenticated forbidden not_found conflict rate_limited internal
curl https://api.bizisy.com/v1/webhooks/deliveries.resend \
-H "Authorization: Bearer $BIZISY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"delivery_id":"01k0000000000000000000000b.we1"}'const res = await fetch('https://api.bizisy.com/v1/webhooks/deliveries.resend', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.BIZISY_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({
"delivery_id": "01k0000000000000000000000b.we1"
}),
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
console.log(body.data);import os, uuid
import requests
res = requests.post(
"https://api.bizisy.com/v1/webhooks/deliveries.resend",
headers={"Authorization": f"Bearer {os.environ['BIZISY_API_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"delivery_id": "01k0000000000000000000000b.we1",
},
)
body = res.json()
if not res.ok:
raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
print(body["data"]){
"data": {
"id": "01k0000000000000000000000b.we1",
"endpoint_id": "we1",
"event_type": "person.hired",
"message_id": "msg_01k0000000000000000000000b",
"status": "pending",
"attempts": 0,
"max_attempts": 8,
"next_attempt_at": "2026-10-04T11:00:00.000Z",
"last_attempt_at": "2026-10-04T10:01:00.000Z",
"response_status": 200,
"duration_ms": 182,
"error": null,
"test": false,
"event_at": "2026-10-04T10:00:30.000Z",
"created_at": "2026-10-04T10:01:00.000Z"
}
}Something missing or wrong on this page? Write to hello@bizisy.com.