SIGNALS Documentation
API Reference

Webhooks

Subscribe to real-time event notifications delivered to your server via HTTPS.

Overview

Webhooks let you receive real-time notifications when events happen in Signals. Register an endpoint URL, choose which events to subscribe to, and Signals will send a signed HTTP POST to your server whenever those events occur.

Managing Webhooks

Webhooks can be managed via the API (/api/v1/webhooks) or from the admin panel at Admin > Settings > Webhooks.

Events

Accounts

Event Trigger
account.created A new account is created
account.updated A account's details are updated
account.archived A account is archived
account.restored An archived account is restored
account.deleted A account is permanently deleted
account.merged Two accounts are merged (secondary archived into primary)
account.anonymised A account's personally identifiable information is erased
account.vat_validated A account's VAT number is validated (VIES or manual confirmation)

CatalogueItems

Event Trigger
catalogue_item.created A new catalogue item is created
catalogue_item.updated A catalogue item's details are updated
catalogue_item.archived A catalogue item is archived (soft-deleted, recoverable)
catalogue_item.restored An archived catalogue item is restored
catalogue_item.deleted A catalogue item is deleted
catalogue_item.merged Two catalogue items are merged
catalogue_item_group.created A new catalogue item group is created
catalogue_item_group.updated A catalogue item group is updated
catalogue_item_group.deleted A catalogue item group is deleted
accessory.created An accessory link is added to a catalogue item
accessory.updated An accessory link is updated
accessory.deleted An accessory link is removed
kit_component.created A kit bill-of-materials component is added
kit_component.updated A kit bill-of-materials component is updated
kit_component.deleted A kit bill-of-materials component is removed

Stock

Event Trigger
asset.created An asset record is created
asset.updated An asset is updated
asset.deleted An asset is deleted
asset_transaction.created An asset transaction is recorded
asset_transaction.deleted An asset transaction is deleted

Flightcases

Event Trigger
flightcase.created A flightcase is created (catalogue-item-backed or temporary)
flightcase.item.packed An item is packed into a flightcase
flightcase.item.unpacked An item is unpacked from a flightcase
flightcase.item.transferred An item is moved between flightcases in one step
flightcase.nested A flightcase is packed inside another flightcase
flightcase.sealed A flightcase passes the seal gate and is sealed
flightcase.unsealed A sealed flightcase is reopened (manual or transfer-triggered)
flightcase.dissolved A flightcase is manually or dispatch-dissolved
flightcase.dispatched A kit/hybrid flightcase is dispatched as a persistent unit
flightcase.returned A kit/hybrid flightcase is returned from a rental
flightcase.repack.started Repack-on-return initiated for a transport flightcase housing
flightcase.repack.item An item is returned and repacked during a repack session
flightcase.checkin_verified A flightcase's contents are verified during check-in

Activities

Event Trigger
activity.created A new activity is created
activity.updated An activity is updated
activity.deleted An activity is deleted
activity.completed An activity is marked as completed

Rate specifications

Event Trigger
rate_specification.created A rate specification is created
rate_specification.updated A rate specification is updated
rate_specification.deleted A rate specification is deleted
catalogue_item_rate.created A catalogue item rate is assigned
catalogue_item_rate.updated A catalogue item rate is updated
catalogue_item_rate.deleted A catalogue item rate is removed

Tax

Event Trigger
tax_rate.created A tax rate is created
tax_rate.updated A tax rate is updated
tax_rate.deleted A tax rate is deleted
tax_rule.created A tax rule is created
tax_rule.updated A tax rule is updated
tax_rule.deleted A tax rule is deleted
tax_zone.created A tax zone is created
tax_zone.updated A tax zone is updated
tax_zone.deleted A tax zone is deleted
tax_category.created A tax category is created
tax_category.updated A tax category is updated
tax_category.deleted A tax category is deleted

Pricing

Event Trigger
discount_category.created A discount category is created
discount_category.updated A discount category is updated
discount_category.deleted A discount category is deleted
discount_rule.created A discount rule is created
discount_rule.updated A discount rule is updated
discount_rule.deleted A discount rule is deleted
surcharge.created A surcharge is created
surcharge.updated A surcharge is updated
surcharge.deleted A surcharge is deleted
surcharge_group.created A surcharge group is created
surcharge_group.updated A surcharge group is updated
surcharge_group.deleted A surcharge group is deleted
price_category.created A price category is created
price_category.updated A price category is updated
price_category.deleted A price category is deleted
bundle_rule.created A bundle rule is created
bundle_rule.updated A bundle rule is updated
bundle_rule.deleted A bundle rule is deleted

Warehouses

Event Trigger
warehouse.created A warehouse location is created
warehouse.updated A warehouse location is updated
warehouse.deleted A warehouse location is deleted

Exchange Rates

Event Trigger
exchange_rate.created An exchange rate is created
exchange_rate.updated An exchange rate is updated
exchange_rate.deleted An exchange rate is deleted

Users

Event Trigger
user.created A new user is invited or created
user.updated A user's profile or roles are updated
user.deactivated A user account is deactivated
user.deleted A user is deleted

Roles

Event Trigger
role.created A new role is created
role.updated A role's name or permissions are modified
role.deleted A role is deleted

Settings

Event Trigger
settings.updated Application settings are changed

Rentals

Rental events fire on every committed mutation of a rental, its line items, costs, allocated assets, and quote versions. They are never re-delivered when the event warehouse is rebuilt.

Event Trigger
rental.created A new rental (quote) is created
rental.updated A rental's header fields are updated
rental.quoted A rental is marked as quoted
rental.converted_to_order A quote is converted to an order
rental.reverted_to_quotation An order is reverted back to a quotation
rental.reverted_to_enquiry A quotation is reverted back to a draft
rental.reinstated A lost, dead, postponed, or cancelled rental is reinstated
rental.reopened A completed order is re-opened back to an active order
rental.locks_applied FX/tax locks are applied to an order
rental.locks_released An order's FX/tax locks are released for re-pricing
rental.status_changed A rental's status changes
rental.status_promoted A rental's status is promoted along its workflow
rental.cloned A rental is cloned into a new rental
rental.deleted A rental is soft-deleted
rental.restored A soft-deleted rental is restored
rental.deal_price_set A negotiated deal total is set
rental.deal_price_cleared A negotiated deal total is cleared
rental.group_deal_price_set A negotiated deal total is set on a line-item group
rental.group_deal_price_cleared A negotiated deal total is cleared from a line-item group
rental.pricing_recalculated Rental pricing is recalculated (rates, tax, surcharges)
rental.discount_reset Applied discounts are cleared from a rental
rental.discount_category_applied A discount category is applied to a rental
rental.discount_manually_overridden A discount category percentage is manually overridden
rental.item_added A line item is added
rental.item_details_updated A line item's details (description, notes, etc.) are updated
rental.item_renamed A line item is renamed
rental.item_removed A line item is removed
rental.item_quantity_changed A line item's quantity changes
rental.item_dates_changed A line item's hire dates change
rental.item_discount_set A line item discount is set
rental.item_deal_price_discount_set A line item deal-price-derived discount is set or cleared
rental.item_optional_toggled A line item is toggled optional/required
rental.item_price_overridden A line item unit price is overridden
rental.item_substituted A line item catalogue item is substituted
rental.item_surcharge_overridden A line item surcharge amount is manually overridden
rental.items_restructured A rental's line-item tree is restructured
rental.items_reordered A rental's line items are reordered
rental.surcharge_group_toggled A surcharge group is enabled or disabled on a rental
rental.cost_added An additional cost is added
rental.cost_updated An additional cost is updated
rental.cost_removed An additional cost is removed
rental.version_created A new quote version is created
rental.version_activated A quote version is made active
rental.version_accepted A quote version is accepted by the customer
rental.version_declined A quote version is declined
rental.version_sent A quote version is sent to the customer
rental.version_relabelled A quote version's label is changed
rental.version_superseded A quote version is superseded by a newer one
rental.version_deleted A quote version is deleted
rental.asset_allocated A barcoded asset is allocated to a line item
rental.asset_deallocated A barcoded asset is deallocated
rental.asset_substituted An allocated asset is substituted for another
rental.asset_prepared An asset is marked prepared for dispatch
rental.asset_preparation_reverted An asset's prepared state is reverted
rental.asset_checked An asset is scan-checked
rental.asset_dispatched An asset is dispatched
rental.asset_on_hire An asset is marked on-hire
rental.asset_returned An asset is returned
rental.asset_status_reverted An asset's lifecycle status is reverted
rental.asset_flightcase_set An asset is placed in a flightcase
rental.asset_flightcase_cleared An asset is removed from its flightcase
rental.bulk_dispatched A bulk (non-barcoded) quantity is dispatched
rental.bulk_returned A loose quantity is returned
rental.bulk_quantity_adjusted A bulk dispatched/returned quantity is adjusted

Documents

Event Trigger
document.created A document is generated from a template
document.pdf_generated A PDF is generated and stored for a document
document.finalised A document is finalised (locked for sharing)
document.voided A finalised document is voided
document.emailed A document is emailed to a recipient (Notification Engine, P38)
document.public_link_created A public sharing link is created for a document
document.public_link_accessed A public sharing link is accessed for the first time
document.public_link_revoked A public sharing link is revoked
document.public_link_configured A public link's expiry or PIN settings are changed
document_template.created A document template is created or duplicated
document_template.updated A document template is saved
document_template.deleted A custom document template is deleted
document_template.restored A system template is restored to its shipped default
document_template.set_as_default A template is marked as the default for its type
document_sequence.reset A document numbering sequence rolls over to a new period

Attachments

Event Trigger
attachment.created A file is attached to an entity
attachment.deleted An attachment is deleted from an entity

Invoices

Event Trigger
invoice.created A draft invoice is generated
invoice.issued A draft invoice is issued to the customer
invoice.voided An invoice is voided
invoice.overdue An issued invoice passes its due date with an outstanding balance
payment.recorded A payment is recorded against an invoice — payload embeds payment fields (see Invoices API)
payment.refunded A refund is recorded against an invoice — payload embeds payment/refund fields (see Invoices API)
credit_note.draft_created A draft credit note is created against an invoice
credit_note.issued A credit note is issued against an invoice
credit_note.applied A credit note is applied to an invoice
credit_note.voided A credit note is voided

Availability

Event Trigger
availability.changed A catalogue-item/warehouse's availability read model has been recalculated

Shortages

Event Trigger
shortage.detected A shortage is detected for an order line
shortage.cleared A previously-detected shortage no longer exists
shortage.acknowledged A shortage is acknowledged at a confirmation gate
shortage.resolution.created A shortage resolution is created
shortage.resolution.confirmed A shortage resolution is confirmed
shortage.resolution.in_progress A shortage resolution's fulfilment has begun
shortage.resolution.fulfilled A shortage resolution completes and stock is available
shortage.resolution.failed A shortage resolution attempt fails
shortage.resolution.cancelled A shortage resolution is cancelled
shortage.waitlist.created A waitlist monitor is placed on a shortage
shortage.waitlist.matched Monitored stock becomes available
shortage.waitlist.expired A waitlist monitor expires without matching
shortage.escalated An unresolved shortage passes the configured escalation threshold

Purchase Orders

Event Trigger
purchase_order.created A draft purchase order is created
purchase_order.updated A draft purchase order is updated
purchase_order.sent A purchase order is sent to the supplier
purchase_order.received Goods are received against a purchase order
purchase_order.cancelled A purchase order is cancelled
purchase_order.deleted A draft purchase order is deleted
purchase_order_document.created A document (e.g. supplier PDF) is generated for a purchase order

Virtual Stock

Event Trigger
virtual_stock_intake.created A draft virtual stock intake is created
virtual_stock_intake.updated A draft virtual stock intake is updated
virtual_stock_intake.confirmed A virtual stock intake is confirmed
virtual_stock_intake.received Virtual stock is received into availability
virtual_stock_intake.returned Virtual stock is returned after the hire window
virtual_stock_intake.cancelled A virtual stock intake is cancelled
virtual_stock_intake.deleted A draft virtual stock intake is deleted

Vehicles

Event Trigger
vehicle.created A vehicle is created
vehicle.updated A vehicle is updated
vehicle.deleted A vehicle is deleted
vehicle.assigned A vehicle is assigned to a rental or job
vehicle.assignment_updated A vehicle assignment's details are updated
vehicle.unassigned A vehicle is unassigned

Repair

Event Trigger
repair.created A stock item is placed into repair
repair.updated A repair record's details are updated
repair.released A repaired item is released back into service

EquipmentTests

Event Trigger
equipment_test.created An equipment_test record is created
equipment_test.updated An equipment_test record is updated
equipment_test.deleted An equipment_test record is deleted
equipment_test.completed An equipment_test is completed
equipment_test.failed An equipment_test is recorded as failed
equipment_test_result.created A result line is recorded against an equipment_test
equipment_test_result.deleted An equipment_test result line is deleted

Asset Lifecycle

Event Trigger
asset_cost.created A maintenance/asset cost is recorded
asset_cost.updated An asset cost is updated
asset_cost.deleted An asset cost is deleted
asset_retirement.created An asset is retired (disposed)
asset_retirement.voided A stock-check-sourced retirement is voided directly (not emitted on reinstate)
asset_retirement.reinstated A retired asset is reinstated (returned to active stock)
usage_reading.recorded A usage reading (e.g. odometer/hours) is recorded against a stock unit

Stock Checks

Event Trigger
stock_check.created A stock check is created
stock_check.updated A stock check is updated
stock_check.submitted A stock check is submitted for review
stock_check.completed A stock check is completed and reconciled
stock_check.reverted A completed stock check is reverted
stock_check.cancelled A stock check is cancelled
stock_check.discrepancy_resolved A stock check discrepancy is resolved (ledger/relocation applied)

Warehouse Transfers

Event Trigger
warehouse_transfer.created A warehouse transfer is created
warehouse_transfer.updated A warehouse transfer's details are updated
warehouse_transfer.dispatched A warehouse transfer is dispatched from the origin warehouse
warehouse_transfer.received A warehouse transfer is received at the destination warehouse
warehouse_transfer.cancelled A warehouse transfer is cancelled

Scan Sessions

Event Trigger
scan_session.completed A scanning session is completed
scan_session.abandoned A scanning session is abandoned

Payload Format

Every webhook delivery sends a JSON POST request with the event name and associated data:

{
    "event": "user.created",
    "timestamp": "2026-01-15T14:30:00Z",
    "data": {
        "user": {
            "id": 42,
            "name": "Jane Smith",
            "email": "jane@example.com"
        }
    }
}

Payload Schemas

Most events embed the affected resource under a singular key inside data, using the same shape the REST API returns. Lifecycle events that only need to identify a record (deletions, archive/restore) send just an id.

Tax Rate Events

tax_rate.created and tax_rate.updated include the full tax rate object:

{
    "event": "tax_rate.created",
    "timestamp": "2026-01-15T14:30:00Z",
    "data": {
        "tax_rate": {
            "id": 1,
            "name": "UK Standard",
            "description": "Standard rate VAT",
            "rate": "20.0000",
            "is_active": true,
            "created_at": "2026-01-15T14:30:00Z",
            "updated_at": "2026-01-15T14:30:00Z"
        }
    }
}
Field Type Description
id integer Tax rate identifier
name string Display name (e.g. UK Standard)
description string|null Optional description
rate string Percentage as a decimal string (e.g. 20.0000)
is_active boolean Whether the rate is active
created_at / updated_at string ISO 8601 UTC timestamps

tax_rate.deleted sends only the identifier:

{
    "event": "tax_rate.deleted",
    "timestamp": "2026-01-15T14:30:00Z",
    "data": { "id": 1 }
}

Tax Rule Events

tax_rule.created and tax_rule.updated include the full tax rule object:

{
    "event": "tax_rule.created",
    "timestamp": "2026-01-15T14:30:00Z",
    "data": {
        "tax_rule": {
            "id": 5,
            "company_tax_type_id": 1,
            "catalogue_item_tax_type_id": 2,
            "tax_rate_id": 1,
            "priority": 10,
            "is_active": true,
            "created_at": "2026-01-15T14:30:00Z",
            "updated_at": "2026-01-15T14:30:00Z"
        }
    }
}
Field Type Description
id integer Tax rule identifier
company_tax_type_id integer Company tax type matched by the rule
catalogue_item_tax_type_id integer Catalogue item tax type matched by the rule
tax_rate_id integer Tax rate applied when the rule matches
priority integer Higher priority rules win when several match
is_active boolean Whether the rule is active
created_at / updated_at string ISO 8601 UTC timestamps

tax_rule.deleted sends only the identifier:

{
    "event": "tax_rule.deleted",
    "timestamp": "2026-01-15T14:30:00Z",
    "data": { "id": 5 }
}

CatalogueItem Archive & Restore Events

catalogue_item.archived and catalogue_item.restored are lifecycle transitions on an existing catalogue item and carry only its identifier. Fetch the current state from GET /api/v1/catalogue_items/{id} if you need the full record.

{
    "event": "catalogue_item.archived",
    "timestamp": "2026-01-15T14:30:00Z",
    "data": { "id": 42 }
}
Field Type Description
id integer CatalogueItem identifier

Verifying Signatures

Every delivery includes an X-Signals-Signature header containing an HMAC-SHA256 signature of the request body. Verify it against the secret you received when creating the webhook:

$signature = hash_hmac('sha256', $requestBody, $webhookSecret);

if (! hash_equals($signature, $request->header('X-Signals-Signature'))) {
    abort(401, 'Invalid signature');
}

Retry Behaviour

Failed deliveries (non-2xx response or connection timeout) are retried with exponential backoff up to 6 times over approximately 12 hours. After 3 consecutive days of failures, the webhook is automatically disabled.

Re-enable a disabled webhook from the admin panel or by updating it via the API with is_active: true.

Delivery Logs

Every delivery attempt is logged. View logs via the API at GET /api/v1/webhooks/{id}/logs or from the API Console Webhooks page by clicking the logs icon on a webhook row. Deliveries also appear in the unified Request Log on the webhook_sent channel.

Outbound metering weights

Each outbound event carries a price weight (0–4) declared in WebhookEventRegistry. Weights default to 1 unless overridden at registration time. On the first delivery attempt of each job run, DeliverWebhook records the weight on the webhook_logs row and increments the webhook_sent daily rollup by the event's weight.

Weight 0 events are still logged but contribute zero weighted units toward usage totals.

Inbound webhook receiver

Signals can accept webhook POSTs from external systems via registered inbound sources. Manage sources from the API Console at /api/webhooks (Inbound tab) or programmatically when that surface is exposed.

Receive URL

POST {your-app-url}/webhooks/receive/{slug}

Replace {slug} with the source's URL slug. The route is public (no Sanctum token) — authentication is HMAC signature verification only.

Signature verification

Each source warehouses a secret, signature algorithm (default sha256), and header name (default X-Signature). The middleware computes:

$expected = hash_hmac($source->signature_algo, $requestBody, $source->secret);
$provided = $request->header($source->signature_header);

$valid = is_string($provided) && hash_equals($expected, $provided);

Send the HMAC digest as a plain string in the configured header (not prefixed with sha256=).

Responses

Status Condition Body
200 Valid signature {"status":"received"} — fires InboundWebhookReceived
401 Missing or invalid signature {"message":"Invalid signature"} — logged with weight 0
404 Unknown slug or inactive source Laravel 404 page

Inbound metering weights

Unlike outbound events (code-defined in WebhookEventRegistry), inbound weights are stored per source in inbound_webhook_sources.price_weight (0–4, editable in the console). Valid requests meter on the webhook_received channel; invalid signatures log detail rows but do not increment weighted units.

Inbound logs

Receipts are stored in inbound_webhook_logs and surfaced in the Request Log (webhook_received channel) and the source's logs modal in the API Console.