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

FieldTypeRequiredDescription
moduleModuleYesThe module to listen to (see Modules).
event_typesActionType[]YesOne or more event types to subscribe to (see Event Types). At least one value is required.
urlstringYesThe HTTPS URL that will receive the webhook POST requests. Must be a valid https:// URL.
secret_keystringNoIf 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.
descriptionstringNoA human-readable description of this webhook.
headersobjectNoAdditional HTTP headers (as a JSON key-value object) to include in every webhook request. Useful for passing authorization tokens to your endpoint.
included_fieldsstring[]NoWhitelist 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 https scheme.
  • 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

ParameterTypeDescription
webhook_idintegerThe 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

ParameterTypeDescription
webhook_idintegerThe unique ID of the webhook registration.

Request body (all fields optional)

FieldTypeDescription
moduleModuleChange the module this webhook listens to.
event_typesActionType[]Replace the subscribed event types. Must contain at least one value if provided.
urlstringChange the delivery URL. Must be a valid https:// URL.
secret_keystringUpdate or set the HMAC signing secret. Never returned in any API response.
is_activebooleanEnable (true) or disable (false) the webhook without deleting it.
descriptionstringUpdate the description.
headersobjectReplace the custom headers.
included_fieldsstring[]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

ParameterTypeDescription
webhook_idintegerThe 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

FieldTypeRequiredDescription
moduleModuleYesThe module the test event belongs to.
event_typeActionTypeYesThe type of action to simulate.
item_idintegerYesThe ID of the item the event relates to.
payloadobjectYesThe 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

This is the object returned by all webhook management endpoints.

FieldTypeDescription
idintegerUnique identifier for this webhook.
customerNameAndIdThe customer this webhook belongs to.
moduleModuleThe module being monitored.
event_typesActionType[]The subscribed event types.
urlstringThe delivery URL.
is_activebooleanWhether the webhook is currently active.
descriptionstring | nullOptional description.
headersobject | nullCustom headers sent with every delivery.
included_fieldsstring[] | nullField whitelist; null or empty means all fields.
created_atdatetimeWhen this webhook was created.
updated_atdatetimeWhen this webhook was last updated.
created_byNameAndIdEmployee who created the webhook.
updated_byNameAndIdEmployee who last updated the webhook.

Note: The secret_key field 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:

ValueDescription
CREATEAn item was created
UPDATEAn item was updated
DELETEAn item was deleted
CLONEAn item was cloned
ARCHIVEAn item was archived
UNARCHIVEAn item was unarchived
REVIEWA review was completed on an item
LOANAn item was loaned out
RETURNA loaned item was returned
UPLOAD_DOCUMENTATIONDocumentation was uploaded to an item
COMMENTA comment was added to an item
READAn item was read (Document module only)
MARK_AS_DONEAn 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

MethodEndpointEvent Type
POST/v1/equipmentsCREATE
PATCH/v1/equipments/{equipment_id}UPDATE
DELETE/v1/equipments/{equipment_id}DELETE
POST/v1/equipments/{equipment_id}/cloneCLONE
POST/v1/equipments/{equipment_id}/loanLOAN
POST/v1/equipments/{equipment_id}/returnRETURN
POST/v1/equipments/archiveARCHIVE
POST/v1/equipments/unarchiveUNARCHIVE

Employee

MethodEndpointEvent Type
POST/v1/employeesCREATE
PATCH/v1/employees/{employee_id}UPDATE
POST/v1/employees/archiveARCHIVE
POST/v1/employees/unarchiveUNARCHIVE

Document

MethodEndpointEvent Type
POST/v1/documents/archiveARCHIVE
POST/v1/documents/unarchiveUNARCHIVE

Supplier

MethodEndpointEvent Type
POST/v1/suppliers/archiveARCHIVE
POST/v1/suppliers/unarchiveUNARCHIVE

Task

MethodEndpointEvent Type
POST/v1/tasksCREATE
PATCH/v1/tasks/{task_id}UPDATE
POST/v1/tasks/archiveARCHIVE
POST/v1/tasks/unarchiveUNARCHIVE

Location

MethodEndpointEvent Type
POST/v1/locationsCREATE
PATCH/v1/locations/{location_id}UPDATE
DELETE/v1/locations/{location_id}DELETE
POST/v1/locations/archiveARCHIVE
POST/v1/locations/unarchiveUNARCHIVE

Team

MethodEndpointEvent Type
POST/v1/teamsCREATE
PATCH/v1/teams/{team_id}UPDATE
DELETE/v1/teams/{team_id}DELETE
POST/v1/teams/archiveARCHIVE
POST/v1/teams/unarchiveUNARCHIVE

Category

MethodEndpointEvent Type
POST/v1/categoriesCREATE
PATCH/v1/categories/{category_id}UPDATE
DELETE/v1/categories/{category_id}/{category_source}DELETE
POST/v1/categories/tradesCREATE
PATCH/v1/categories/trades/{trade_id}UPDATE
DELETE/v1/categories/trades/{trade_id}DELETE
POST/v1/categories/main-tradesCREATE
PATCH/v1/categories/main-trades/{main_trade_id}UPDATE
DELETE/v1/categories/main-trades/{main_trade_id}DELETE

Review Group

MethodEndpointEvent Type
POST/v1/reviews/groupsCREATE
PATCH/v1/reviews/groups/{id}UPDATE
DELETE/v1/reviews/groups/{id}DELETE
POST/v1/reviews/groups/{id}/cloneCLONE
PATCH/v1/reviews/groups/{id}/archiveARCHIVE
PATCH/v1/reviews/groups/{id}/unarchiveUNARCHIVE

Review Template

MethodEndpointEvent Type
POST/v1/reviews/templatesCREATE
PATCH/v1/reviews/templates/{id}UPDATE
DELETE/v1/reviews/templates/{id}DELETE
POST/v1/reviews/templates/{id}/cloneCLONE
PATCH/v1/reviews/templates/{id}/archiveARCHIVE
PATCH/v1/reviews/templates/{id}/unarchiveUNARCHIVE

Other

MethodEndpointEvent Type
POST/v1/reviews/completereview/{id}REVIEW
POST/v1/reviews/startreview/{id}/quickanswerREVIEW
POST/v1/reviews/equipment/{equipment_id}/quickreviewREVIEW
POST/v1/documentation/uploadUPLOAD_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

HeaderDescription
Content-TypeAlways application/json
X-Webhook-IDThe ID of the webhook registration that triggered this delivery
X-Webhook-Delivery-IDA unique UUID for this specific delivery attempt
X-Webhook-Event-ModuleThe module of the event (e.g., equipment)
X-Webhook-Event-TypeThe action type of the event (e.g., UPDATE)
X-Webhook-SignatureHMAC-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)

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:

AttemptDelay before retry
1st retry60 seconds
2nd retry120 seconds
3rd retry240 seconds

After 3 failed retries the delivery is marked as EXHAUSTED and no further attempts are made.

Delivery Statuses

StatusDescription
PENDINGDelivery is queued, not yet attempted
SUCCESSDelivered successfully (2xx response received)
FAILEDDelivery failed, retry scheduled
RETRYINGCurrently being retried
EXHAUSTEDAll 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.