With webhooks, Time Slot Control sends an HTTP request to your system on its own whenever a selected event occurs, for example when a reservation is created, changed, moved or deleted. Your system does not have to keep polling the API for changes.
A webhook contains the reservation identifier and basic status data. After receiving a webhook, download the full reservation detail (slot time, ramp, carrier, vehicle type…) via GET /v3/{tenant}/Reservations/{id} (see Reading reservations).
We recommend combining webhooks with a scheduled download of changes through the API. That way you do not miss any change even if your server is unavailable for a longer time.
webhook.test event). Use payload preview to see a sample request body for a selected event.To synchronize reservations into an external system, we recommend subscribing at least to
reservation.created,reservation.updated,reservation.moved,reservation.resizedandreservation.deleted.
reservation.created – reservation createdreservation.updated – reservation changedreservation.deleted – reservation deletedreservation.deleted.recurrence – recurring reservation deletedreservation.moved – reservation moved in the plan (e.g. to another ramp)reservation.resized – slot length changedreservation.branchoffice.changed – branch office changedreservation.markedasarrival – vehicle marked as arrivedreservation.markedasdeparted – vehicle marked as departedreservation.processingstarted – processing startedreservation.processingcompleted – processing completedreservation.delivered – deliveredreservation.pending – pendingreservation.carrier.notarrived – carrier did not arrivereservation.action.notcompleted – requested action not completedreservation.delivery.urgent – urgent deliveryreservation.customaction.updated – custom action changedreservation.actiondialog.updated – action dialog changedreservation.approval.approved / reservation.approval.rejected – reservation approved / rejectedreservation.ipp.approval.pending / .approved / .rejected – IPP approval statusreservation.vehicle.platechanged – license plate changedreservation.carrier.contactchanged – carrier contact changedreservation.driver.changed – driver changedreservation.carrier.detailschanged – carrier details changedreservation.note.updated – note changedorder.created, order.updated, order.deletedorder.confirmed, order.confirmation.canceledwebhook.test – test event sent from AdministrationEach webhook is sent as a POST request with the Content-Type: application/json header. The body looks like this:
{
"schemaVersion": "1.0",
"eventId": "6a1f0c2e-8d3b-4f7a-9c1e-2b5d7e9f0a11",
"event": "reservation.updated",
"tenantId": "0f4e2c1a-...",
"occurredAt": "2026-10-06T08:15:42.123Z",
"data": {
"id": "3f6c2a1e-...",
"deliveryDateUtc": "2026-10-06T06:00:00Z",
"realGateVehicleArrivalUtc": "2026-10-06T05:52:10Z"
}
}
eventId
event
occurredAt
data.id
order.* events).data.*
approvalStatus and ippApprovalStatus (numeric status code), carrierNotArrived, deliveryDateUtc, realGateVehicleArrivalUtc, realGateVehicleDepartureUtc. Fields without a value are omitted.The payload does not contain the slot time, ramp, carrier or vehicle type. After receiving the webhook, load the detail via
GET /v3/{tenant}/Reservations/{data.id}. For thereservation.deletedevent, the detail is no longer available.
Every request is signed with HMAC-SHA256 using the subscription secret. The signature is always sent, even when authentication (Basic, Bearer, OAuth2) is configured as well.
X-TSC-Timestamp
X-TSC-Signature
sha256= + lowercase hex HMAC-SHA256 of the string {timestamp}.{request body}.Verification steps:
X-TSC-Timestamp header and the raw request body exactly as received, without re-formatting the JSON.HMAC-SHA256(secret, timestamp + "." + body) and convert it to lowercase hex.sha256= in the X-TSC-Signature header, ideally using a constant-time comparison.Example (C#):
using System.Security.Cryptography;
using System.Text;
static bool VerifyTscSignature(string secret, string timestamp, string body, string signatureHeader)
{
using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret));
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(timestamp + "." + body));
var expected = "sha256=" + Convert.ToHexString(hash).ToLowerInvariant();
return CryptographicOperations.FixedTimeEquals(
Encoding.ASCII.GetBytes(expected),
Encoding.ASCII.GetBytes(signatureHeader ?? ""));
}
Example (Node.js):
const crypto = require('crypto');
function verifyTscSignature(secret, timestamp, rawBody, signatureHeader) {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(`${timestamp}.${rawBody}`, 'utf8')
.digest('hex');
const a = Buffer.from(expected);
const b = Buffer.from(signatureHeader || '');
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
429 Too Many Requests) is treated as a permanent error and is not retried.The same event may arrive more than once, for example after a retry. Process webhooks idempotently by
eventId. Delivery order is not guaranteed. Rely onoccurredAt, or on the current reservation state loaded through the API.
Recommendations for the receiving endpoint:
200 OK as soon as possible and do the actual processing (e.g. downloading the detail through the API) asynchronously.