Register an endpoint
Register an HTTPS URL to receive signed sailing event deliveries. The signing secret is returned once here and never again: store it before you close the connection. An unrecognised event type is dropped silently rather than rejected, so read event_types back from the response. Answers 201 on success, 400 INVALID_URL when the URL is missing or not https.
Registering, updating and testing an endpoint need SchedulesMCP connected to your account. Listing, reading and deleting need only a valid key, so an account whose access has lapsed can still inspect and remove its endpoints.
Counted: 1 call when the request succeeds; refusals and errors are free. Needs SchedulesMCP connected to your account. The event deliveries we send are free. See how calls are counted.
Request body
Where we post deliveries. Must start with https://.
Event types to receive. Omit or send [] to receive every event type we emit. Accepted values: blank_sailing, cutoff_approaching, sailing_slipped and reliability_drop.
Your own label. We never interpret it.
Response schema
9 fields
Derived from the example response, nested as the JSON is.
Whether the request succeeded.
data
The payload. Everything an endpoint returns sits under this key.
Stable identifier for the record. On the tracking endpoints this is the container UUID, except on a portfolio summary row, where it is the container number.
Where we POST the events.
The events this endpoint receives. Anything not listed is not delivered.
The carrier own phrasing for the event, falling back to our word for the code.
False while the endpoint is paused. A paused endpoint keeps its secret and its history.
When the record was created (ISO 8601).
Signing secret, returned ONLY on creation. Store it then: we keep a hash, so it cannot be shown again.
Errors
Every refusal is { "ok": false, "error": { "code", "message" } }. Branch on the code, and log the message. No refusal or error is counted as a call.
url is missing or does not start with https://. Not counted.
The key is missing, unknown, revoked or past its own expiry date. Not counted.
SchedulesMCP is not connected to your account, or its access period has ended. Not counted.
The monthly call limit or the key's daily limit is spent. Retry-After gives the seconds until it resets. Not counted.
Too many requests in a short window. Wait Retry-After seconds. Not counted.
curl -X POST 'https://api.schedulesmcp.com/v1/webhooks' \
-H "Authorization: Bearer smcp_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://hooks.example.com/schedulesmcp","event_types":["blank_sailing","cutoff_approaching"],"description":"Sailing alerts, booking desk"}'const res = await fetch("https://api.schedulesmcp.com/v1/webhooks", {
method: "POST",
headers: {
"Authorization": "Bearer smcp_YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({
"url": "https://hooks.example.com/schedulesmcp",
"event_types": [
"blank_sailing",
"cutoff_approaching"
],
"description": "Sailing alerts, booking desk"
})
});
const data = await res.json();import requests
res = requests.post(
"https://api.schedulesmcp.com/v1/webhooks",
headers={"Authorization": "Bearer smcp_YOUR_API_KEY"},
json={
"url": "https://hooks.example.com/schedulesmcp",
"event_types": [
"blank_sailing",
"cutoff_approaching"
],
"description": "Sailing alerts, booking desk"
},
)
data = res.json() {
"ok": true,
"data": {
"id": "3f1c9a4e-7b52-4f0e-9a41-2c9d5e6b8a10",
"url": "https://hooks.example.com/schedulesmcp",
"event_types": ["blank_sailing", "cutoff_approaching"],
"description": "Sailing alerts, booking desk",
"active": true,
"created_at": "2026-08-11T09:12:04.881Z",
"secret": "whsec_3f9a1c7e5b204d8619ac0f73e26b8d45a1c9e30f7b264d58"
}
}