API reference
Webhooks
We tell your server when something changes that you did not cause: a hold running out, a staging area closing, a rule changing. Nothing is sent for what you did yourself, such as checking in or cancelling. Register an endpoint, and we send each event to it as a signed POST.
Each POST carries a Lanoo-Signature header, t=<unix seconds>,v1=<hex>, where v1 is an HMAC-SHA256 of <t>.<raw body> with the endpoint's secret. Compare it in constant time and reject a t, the time we sent it, more than 5 minutes from your clock either way. Answer with a 2xx; anything else, or no answer, counts as failed, and failed deliveries are retried with backoff. Events can arrive more than once and out of order.
The event object
Unique, starting evt_. The same event may arrive more than once; use this to notice.
reservation.expired: the vehicle did not check in before held_until. reservation.cancelled: the staging area closed and gave up your hold; alternatives lists others with room. Not sent when you cancel yourself. reservation.overstayed: a checked-in vehicle is past leave_by; sent once. What follows is for the staging area's owner to decide. reservation.must_leave: the staging area closed suddenly with your vehicle checked in; it has to leave now, and alternatives lists others with room. staging_area.updated: its rules, details or planned closures changed. staging_area.closed and staging_area.reopened: it stopped or started taking vehicles. ping: a test event, sent only when you ask for one; you need not list it.
One of reservation.expired, reservation.cancelled, reservation.overstayed, reservation.must_leave, staging_area.updated, staging_area.closed, staging_area.reopened, ping.
The API version the event is written in.
object is the reservation or staging area as it is after the change. On ping, it is the endpoint.
{ "id": "evt_1c7e55", "object": "event", "type": "reservation.expired", "created_at": "2026-11-02T14:02:00Z", "api_version": "2026-10-30", "data": { "object": { "id": "res_8f2c41", "object": "reservation", "vehicle_id": "rt-0417", "staging_area": "sa_norreport", "spot": "2", "location": { "lat": 55.6838, "lng": 12.5721 }, "status": "held", "arrive_by": "2026-11-02T14:02:00Z", "held_until": "2026-11-02T14:02:00Z", "checked_in_at": "2026-11-02T14:02:00Z", "leave_by": "2026-11-02T14:02:00Z", "checked_out_at": "2026-11-02T14:02:00Z", "cancellation_reason": "requested", "metadata": {}, "created_at": "2026-11-02T14:02:00Z" }, "alternatives": [ { "object": "availability", "staging_area": "sa_norreport", "name": "Nørreport", "distance_m": 420, "free_spots": 3, "chance_free": 0.92 } ] }}Add a webhook endpoint
POST/v1/webhook_endpoints
Where to send events, and which. The response carries the endpoint's signing secret, once: store it, you need it to check every event.
Body
Where to send events. HTTPS only.
Which events to send.
Headers
A unique key, such as a UUID, for this request. Send the same key when you retry: the request takes effect once, and the retry gets the first answer back. Kept for 24 hours. The same key with a different body is refused with idempotency_key_reused (422).
Responses
The endpoint, with its secret.
url_invalidThe URL is not HTTPS, or does not resolve.
POST https://api.golanoo.com/v1/webhook_endpoints
curl -X POST https://api.golanoo.com/v1/webhook_endpoints \ -H "Authorization: Bearer lk_test_..." \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "url": "https://dispatch.example.com/lanoo/events", "events": [ "reservation.expired", "reservation.cancelled", "staging_area.closed" ] }'{ "id": "we_3b91d0", "object": "webhook_endpoint", "url": "https://dispatch.example.com/lanoo/events", "events": [ "reservation.expired", "reservation.cancelled", "staging_area.closed" ], "secret": "whsec_6f1c0a…", "created_at": "2026-11-01T10:00:00Z"}List webhook endpoints
GET/v1/webhook_endpoints
Parameters
How many to return, 1 to 100. Defaults to 20.
For the next page, the id of the last item on this one.
Responses
A page of endpoints. Secrets are not shown again.
GET https://api.golanoo.com/v1/webhook_endpoints
curl https://api.golanoo.com/v1/webhook_endpoints \ -H "Authorization: Bearer lk_test_..."{ "object": "list", "data": [ { "id": "we_3b91d0", "object": "webhook_endpoint", "url": "string", "events": [ "reservation.expired" ], "secret": "whsec_6f1c0a…", "created_at": "2026-11-02T14:02:00Z" } ], "has_more": true}Remove a webhook endpoint
DEL/v1/webhook_endpoints/{id}
No more events are sent to it, including retries still waiting.
Parameters
The endpoint's id.
Responses
The endpoint, removed.
not_foundNo endpoint with this id.
DELETE https://api.golanoo.com/v1/webhook_endpoints/{id}
curl -X DELETE https://api.golanoo.com/v1/webhook_endpoints/we_3b91d0 \ -H "Authorization: Bearer lk_test_..."{ "id": "we_3b91d0", "object": "webhook_endpoint", "deleted": true}Change a webhook endpoint
PATCH/v1/webhook_endpoints/{id}
A new URL, other events, or both. Send only what changes. Events on their way go to the new URL from the moment it changes, and the secret stays the same.
Parameters
The endpoint's id.
Body
Where to send events. HTTPS only.
Which events to send, in place of the ones before.
Headers
A unique key, such as a UUID, for this request. Send the same key when you retry: the request takes effect once, and the retry gets the first answer back. Kept for 24 hours. The same key with a different body is refused with idempotency_key_reused (422).
Responses
The endpoint as it is now.
not_foundNo endpoint with this id.
url_invalidThe URL is not HTTPS, or does not resolve.
PATCH https://api.golanoo.com/v1/webhook_endpoints/{id}
curl -X PATCH https://api.golanoo.com/v1/webhook_endpoints/we_3b91d0 \ -H "Authorization: Bearer lk_test_..." \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "events": [ "reservation.expired", "reservation.cancelled", "reservation.overstayed", "staging_area.closed" ] }'{ "id": "we_3b91d0", "object": "webhook_endpoint", "url": "https://dispatch.example.com/lanoo/events", "events": [ "reservation.expired", "reservation.cancelled", "reservation.overstayed", "staging_area.closed" ], "created_at": "2026-11-01T10:00:00Z"}Get a new secret
POST/v1/webhook_endpoints/{id}/roll_secret
For a secret that has leaked, or one you want to change. The response carries the new secret, once. Choose when the old one stops: now for a leaked secret, or in_24_hours to swap it without missing an event. Until the old one stops, every event is signed with both.
Parameters
The endpoint's id.
Body
When the old secret stops working.
One of now, in_24_hours.
Headers
A unique key, such as a UUID, for this request. Send the same key when you retry: the request takes effect once, and the retry gets the first answer back. Kept for 24 hours. The same key with a different body is refused with idempotency_key_reused (422).
Responses
The endpoint, with its new secret.
not_foundNo endpoint with this id.
POST https://api.golanoo.com/v1/webhook_endpoints/{id}/roll_secret
curl -X POST https://api.golanoo.com/v1/webhook_endpoints/we_3b91d0/roll_secret \ -H "Authorization: Bearer lk_test_..." \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "expire_old_secret": "in_24_hours" }'{ "id": "we_3b91d0", "object": "webhook_endpoint", "url": "https://dispatch.example.com/lanoo/events", "events": [ "reservation.expired", "reservation.cancelled", "reservation.overstayed", "staging_area.closed" ], "created_at": "2026-11-01T10:00:00Z", "secret": "whsec_9d2e4b…"}Send a test event
POST/v1/webhook_endpoints/{id}/ping
Sends a ping event to the endpoint straight away, signed like every other event, so you can see your server receive and check it. It is sent whichever events the endpoint asks for.
Parameters
The endpoint's id.
Responses
The event is on its way.
not_foundNo endpoint with this id.
POST https://api.golanoo.com/v1/webhook_endpoints/{id}/ping
curl -X POST https://api.golanoo.com/v1/webhook_endpoints/we_3b91d0/ping \ -H "Authorization: Bearer lk_test_..."{ "id": "evt_0a4f93", "object": "event", "type": "ping"}