Webhook
Webhook System Documentation
Overview
Ledoc webhooks let you receive near real-time HTTP notifications whenever events occur inside the system (e.g., an item is created, updated, archived, etc.). When a matching event fires, Ledoc sends an HTTP POST request to your registered URL with a JSON body describing the event.
Required role: All webhook management endpoints require the caller to be a Primary Admin.
Endpoints
1. Register a Webhook
POST /v1/webhooks
Register a new webhook to receive event notifications for a specific module.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
module | Module | Yes | The module to listen to (see Modules). |
event_types | ActionType[] | Yes | One or more event types to subscribe to (see Event Types). At least one value is required. |
url | string | Yes | The HTTPS URL that will receive the webhook POST requests. Must be a valid https:// URL. |
secret_key | string | No | If provided, each request will include an X-Webhook-Signature header containing an HMAC-SHA256 hex digest of the payload (see Verifying Signatures). Never returned in any API response. |
description | string | No | A human-readable description of this webhook. |
headers | object | No | Additional HTTP headers (as a JSON key-value object) to include in every webhook request. Useful for passing authorization tokens to your endpoint. |
included_fields | string[] | No | Whitelist of payload field names to send (e.g., ["id", "name"]). If null or empty, the full payload is sent. |
Constraints
- The URL must use the
httpsscheme. - The combination of
(module, url)must be unique per customer — you cannot register the same URL for the same module twice.
Response 200 OK — returns the created WebhookRegistration object.
2. List All Webhooks
GET /v1/webhooks
Returns all webhook registrations for the current authenticated customer.
Response 200 OK — returns an array of WebhookRegistration objects.
3. Get a Webhook
GET /v1/webhooks/{webhook_id}
Returns a single webhook registration by its ID.
Path parameters
| Parameter | Type | Description |
|---|---|---|
webhook_id | integer | The unique ID of the webhook registration. |
Response 200 OK — returns a single WebhookRegistration object.
Error responses
404 Not Found— webhook does not exist.
4. Update a Webhook
PATCH /v1/webhooks/{webhook_id}
Partially updates an existing webhook registration. All fields are optional — only the fields you provide will be changed.
Path parameters
| Parameter | Type | Description |
|---|---|---|
webhook_id | integer | The unique ID of the webhook registration. |
Request body (all fields optional)
| Field | Type | Description |
|---|---|---|
module | Module | Change the module this webhook listens to. |
event_types | ActionType[] | Replace the subscribed event types. Must contain at least one value if provided. |
url | string | Change the delivery URL. Must be a valid https:// URL. |
secret_key | string | Update or set the HMAC signing secret. Never returned in any API response. |
is_active | boolean | Enable (true) or disable (false) the webhook without deleting it. |
description | string | Update the description. |
headers | object | Replace the custom headers. |
included_fields | string[] | Update the field whitelist. |
Response 200 OK — returns the updated WebhookRegistration object.
Error responses
400 Bad Request— validation failure (invalid URL, empty event_types, etc.).404 Not Found— webhook does not exist.409 Conflict— the new(module, url)combination already exists for this customer.
5. Delete a Webhook
DELETE /v1/webhooks/{webhook_id}
Permanently deletes a webhook registration. All associated delivery history is also removed (cascade).
Path parameters
| Parameter | Type | Description |
|---|---|---|
webhook_id | integer | The unique ID of the webhook registration. |
Response 204 No Content
Error responses
404 Not Found— webhook does not exist.
6. Send a Test Event
POST /v1/webhooks/events/send_test
Manually publishes a test event that triggers delivery to any matching registered webhooks. Useful for validating your endpoint is working correctly before relying on real events.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
module | Module | Yes | The module the test event belongs to. |
event_type | ActionType | Yes | The type of action to simulate. |
item_id | integer | Yes | The ID of the item the event relates to. |
payload | object | Yes | The JSON payload to deliver. You can send any arbitrary JSON object. |
Response 200 OK
{
"message_id": "<SQS message ID or fallback ID>"
}The test event is published to the same delivery pipeline as real events. Any registered webhook whose module and event_types match the request will receive a delivery.
WebhookRegistration Object
WebhookRegistration ObjectThis is the object returned by all webhook management endpoints.
| Field | Type | Description |
|---|---|---|
id | integer | Unique identifier for this webhook. |
customer | NameAndId | The customer this webhook belongs to. |
module | Module | The module being monitored. |
event_types | ActionType[] | The subscribed event types. |
url | string | The delivery URL. |
is_active | boolean | Whether the webhook is currently active. |
description | string | null | Optional description. |
headers | object | null | Custom headers sent with every delivery. |
included_fields | string[] | null | Field whitelist; null or empty means all fields. |
created_at | datetime | When this webhook was created. |
updated_at | datetime | When this webhook was last updated. |
created_by | NameAndId | Employee who created the webhook. |
updated_by | NameAndId | Employee who last updated the webhook. |
Note: The
secret_keyfield is never included in API responses for security reasons.
Modules
The following module values are accepted for the module field:
| Value |
|---|
Equipment |
Document |
Employee |
Supplier |
Task |
Board |
Location |
ReviewTemplate |
ReviewGroup |
Team |
Category |
Customer |
Event Types
The following values are accepted for the event_types / event_type fields:
| Value | Description |
|---|---|
CREATE | An item was created |
UPDATE | An item was updated |
DELETE | An item was deleted |
CLONE | An item was cloned |
ARCHIVE | An item was archived |
UNARCHIVE | An item was unarchived |
REVIEW | A review was completed on an item |
LOAN | An item was loaned out |
RETURN | A loaned item was returned |
UPLOAD_DOCUMENTATION | Documentation was uploaded to an item |
COMMENT | A comment was added to an item |
READ | An item was read (Document module only) |
MARK_AS_DONE | An item was marked as done (Task module only) |
Supported Events by API
The tables below list every API endpoint that publishes a webhook event, grouped by module.
Equipment
| Method | Endpoint | Event Type |
|---|---|---|
POST | /v1/equipments | CREATE |
PATCH | /v1/equipments/{equipment_id} | UPDATE |
DELETE | /v1/equipments/{equipment_id} | DELETE |
POST | /v1/equipments/{equipment_id}/clone | CLONE |
POST | /v1/equipments/{equipment_id}/loan | LOAN |
POST | /v1/equipments/{equipment_id}/return | RETURN |
POST | /v1/equipments/archive | ARCHIVE |
POST | /v1/equipments/unarchive | UNARCHIVE |
Employee
| Method | Endpoint | Event Type |
|---|---|---|
POST | /v1/employees | CREATE |
PATCH | /v1/employees/{employee_id} | UPDATE |
POST | /v1/employees/archive | ARCHIVE |
POST | /v1/employees/unarchive | UNARCHIVE |
Document
| Method | Endpoint | Event Type |
|---|---|---|
POST | /v1/documents/archive | ARCHIVE |
POST | /v1/documents/unarchive | UNARCHIVE |
Supplier
| Method | Endpoint | Event Type |
|---|---|---|
POST | /v1/suppliers/archive | ARCHIVE |
POST | /v1/suppliers/unarchive | UNARCHIVE |
Task
| Method | Endpoint | Event Type |
|---|---|---|
POST | /v1/tasks | CREATE |
PATCH | /v1/tasks/{task_id} | UPDATE |
POST | /v1/tasks/archive | ARCHIVE |
POST | /v1/tasks/unarchive | UNARCHIVE |
Location
| Method | Endpoint | Event Type |
|---|---|---|
POST | /v1/locations | CREATE |
PATCH | /v1/locations/{location_id} | UPDATE |
DELETE | /v1/locations/{location_id} | DELETE |
POST | /v1/locations/archive | ARCHIVE |
POST | /v1/locations/unarchive | UNARCHIVE |
Team
| Method | Endpoint | Event Type |
|---|---|---|
POST | /v1/teams | CREATE |
PATCH | /v1/teams/{team_id} | UPDATE |
DELETE | /v1/teams/{team_id} | DELETE |
POST | /v1/teams/archive | ARCHIVE |
POST | /v1/teams/unarchive | UNARCHIVE |
Category
| Method | Endpoint | Event Type |
|---|---|---|
POST | /v1/categories | CREATE |
PATCH | /v1/categories/{category_id} | UPDATE |
DELETE | /v1/categories/{category_id}/{category_source} | DELETE |
POST | /v1/categories/trades | CREATE |
PATCH | /v1/categories/trades/{trade_id} | UPDATE |
DELETE | /v1/categories/trades/{trade_id} | DELETE |
POST | /v1/categories/main-trades | CREATE |
PATCH | /v1/categories/main-trades/{main_trade_id} | UPDATE |
DELETE | /v1/categories/main-trades/{main_trade_id} | DELETE |
Review Group
| Method | Endpoint | Event Type |
|---|---|---|
POST | /v1/reviews/groups | CREATE |
PATCH | /v1/reviews/groups/{id} | UPDATE |
DELETE | /v1/reviews/groups/{id} | DELETE |
POST | /v1/reviews/groups/{id}/clone | CLONE |
PATCH | /v1/reviews/groups/{id}/archive | ARCHIVE |
PATCH | /v1/reviews/groups/{id}/unarchive | UNARCHIVE |
Review Template
| Method | Endpoint | Event Type |
|---|---|---|
POST | /v1/reviews/templates | CREATE |
PATCH | /v1/reviews/templates/{id} | UPDATE |
DELETE | /v1/reviews/templates/{id} | DELETE |
POST | /v1/reviews/templates/{id}/clone | CLONE |
PATCH | /v1/reviews/templates/{id}/archive | ARCHIVE |
PATCH | /v1/reviews/templates/{id}/unarchive | UNARCHIVE |
Other
| Method | Endpoint | Event Type |
|---|---|---|
POST | /v1/reviews/completereview/{id} | REVIEW |
POST | /v1/reviews/startreview/{id}/quickanswer | REVIEW |
POST | /v1/reviews/equipment/{equipment_id}/quickreview | REVIEW |
POST | /v1/documentation/upload | UPLOAD_DOCUMENTATION |
Receiving Webhook Deliveries
When a subscribed event occurs, Ledoc sends an HTTP POST request to your registered URL with the following characteristics:
Request Headers
| Header | Description |
|---|---|
Content-Type | Always application/json |
X-Webhook-ID | The ID of the webhook registration that triggered this delivery |
X-Webhook-Delivery-ID | A unique UUID for this specific delivery attempt |
X-Webhook-Event-Module | The module of the event (e.g., equipment) |
X-Webhook-Event-Type | The action type of the event (e.g., UPDATE) |
X-Webhook-Signature | HMAC-SHA256 hex digest of the payload — only present if a secret_key is configured |
| (custom headers) | Any additional headers configured in the headers field of the registration |
Request Body
The body is a JSON object containing the event data for the affected item. The exact structure depends on the module and event type. If you configured included_fields, only the whitelisted fields will be present.
Example — CLONE event payload:
{
"cloned_from": 123,
"cloned_to": 456
}Example — REVIEW event payload:
{
"overall_status": "PASS"
}Example — DELETE, ARCHIVE, UNARCHIVE event payload:
{}Expected Response
Your endpoint should return any 2xx HTTP status code to indicate successful receipt. If a non-2xx status is returned, or if the request times out (60-second timeout), the delivery is marked as failed and will be retried.
Verifying Signatures
If you configure a secret_key on a webhook, every delivery will include an X-Webhook-Signature header. This allows you to verify that the request genuinely came from Ledoc and that the payload has not been tampered with.
Algorithm: HMAC-SHA256
How to verify (pseudocode):
expected_signature = HMAC-SHA256(secret_key, JSON.stringify(request_body))
if hex(expected_signature) == request.headers["X-Webhook-Signature"]:
# Payload is authentic
Field Filtering (included_fields)
included_fields)By default, webhooks deliver the full event payload. You can limit the fields sent using included_fields — only top-level JSON keys that appear in this list will be included in the delivery.
Example: If included_fields is ["id", "name", "status"], the delivered payload will only contain those three fields even if the full item has many more.
If included_fields is null or an empty array, the complete payload is delivered.
Retry Behavior
If delivery fails (non-2xx response or network error), Ledoc will retry up to 3 times using exponential backoff:
| Attempt | Delay before retry |
|---|---|
| 1st retry | 60 seconds |
| 2nd retry | 120 seconds |
| 3rd retry | 240 seconds |
After 3 failed retries the delivery is marked as EXHAUSTED and no further attempts are made.
Delivery Statuses
| Status | Description |
|---|---|
PENDING | Delivery is queued, not yet attempted |
SUCCESS | Delivered successfully (2xx response received) |
FAILED | Delivery failed, retry scheduled |
RETRYING | Currently being retried |
EXHAUSTED | All retry attempts have been exhausted |
Disabling a Webhook
Instead of deleting a webhook, you can temporarily disable it by setting is_active to false via the Update endpoint. Disabled webhooks will not receive any deliveries until re-enabled.
Updated 6 days ago