Revtek API Documentation ← Back to revtek.nl
RTK API Revtek Parking Manager

Parking Manager API Reference

A REST API for managing license plates, visitor bookings, and live occupancy on your parking location — the same actions available in the dashboard, exposed for your own systems and integrations.

Version v1 Base /chatbot/api/v1 Auth API key Format JSON · UTF-8 Nederlands ↗

Overview

With the Parking Manager API, an external system can perform the day-to-day access tasks your team now does by hand — most often temporarily adding a license plate for a visitor.

The recommended way to grant temporary access is a visitor booking: a license plate that is only valid between a start and end time, and then expires automatically. You can also add a plate permanently, read live occupancy, and check available timeslots before booking.

Base URL

All paths below are relative to your instance, e.g. https://your-instance.revtek.nl/chatbot/api/v1. You receive the exact hostname for your location together with your API key.

Conventions

  • All requests and responses use application/json.
  • Every response includes a "status" field: "success", "partial", or "error".
  • License plates are automatically normalized to uppercase and trimmed.
  • Every authenticated request must name a tenant — see Tenants & scope.

Authentication

Every endpoint requires an API key, except the public endpoints /health and /webhooks/event-types.

Pass your key in either header with every request:

Request headers

X-API-Key: your_api_key_here
# — or —
Authorization: Bearer your_api_key_here

Handling keys

Keys are stored hashed and can be given an expiry date. Treat your key like a password — only send it over HTTPS and never put it in client-side code. Contact us to rotate or revoke a key.

Example — a full request with curl

curl https://your-instance.revtek.nl/chatbot/api/v1/occupancy?tenant_name=Silverflow \
  -H "X-API-Key: your_api_key_here"

Tenants & scope

A tenant is your organization at a shared parking location. Every request acts on behalf of a single tenant, and your key only touches your own tenant.

Include tenant_name in the request body (for POST/PUT) or as a query parameter (for GET/DELETE). Name matching is lenient — exact, then case-insensitive, then partial — so small variations still match. Your key is bound to your tenant and cannot read or modify data belonging to other companies at the same location.

Note

Because your key is tenant-bound, you still pass tenant_name for clarity, but you can only act on your own tenant.

Dates & times

All timestamps are ISO 8601 strings.

  • Send times in UTC with a trailing Z — e.g. 2026-07-10T14:00:00Z — or with an explicit offset.
  • A timestamp without a time zone is interpreted as Central European Time (Amsterdam).
  • All timestamps in responses are returned in UTC.

Errors

Errors return a non-2xx status code and a JSON body with a human-readable message.

CodeMeaningTypical cause
200 / 201SuccessRequest completed.
400Bad requestMissing or invalid field (e.g. no plate_number).
401UnauthorizedMissing, invalid, or expired API key.
403ForbiddenVisitor parking not enabled, or plate belongs to a different tenant.
404Not foundTenant or resource does not exist.
409ConflictPlate already exists, or no visitor slots available.
500Server errorUnexpected error on our side.

Error body

{
  "status": "error",
  "message": "plate_number is required"
}

Visitor bookings

The primary way to grant temporary access. A booking makes a plate valid only between start_time and end_time, and counts toward your visitor capacity.

post /visitors API key

Create a visitor booking. Optionally recurring — see Recurrence.

FieldTypeDescription
tenant_namestringrequiredYour tenant.
visitor_namestringrequiredName of the visitor.
start_timeISO 8601requiredWhen access begins.
end_timeISO 8601optionalWhen access ends. Defaults to start_time + 1 hour.
plate_numberstringoptionalThe visitor's license plate. Omitted? Then the slot is reserved and the plate can be filled in later.
recurrence_rulestringoptionalweekly, biweekly, or monthly. Omit for a one-off.
recurrence_weekdaysint[]optionalMon=0 … Sun=6. Only for weekly/biweekly; each day becomes its own series.
recurrence_end_dateISO 8601optionalStop recurring after this date.

Request

POST /chatbot/api/v1/visitors
{
  "tenant_name": "Silverflow",
  "visitor_name": "Jan Jansen",
  "plate_number": "12ABC3",
  "start_time": "2026-07-10T09:00:00Z",
  "end_time": "2026-07-10T17:00:00Z"
}

Response · 201

{
  "status": "success",
  "message": "Visitor booking created",
  "booking": {
    "id": 142,
    "plate_number": "12ABC3",
    "visitor_name": "Jan Jansen",
    "start_time": "2026-07-10T09:00:00+00:00",
    "end_time": "2026-07-10T17:00:00+00:00",
    "status": "active"
  }
}

When the location is full

If no visitor slots are available for that window, the response is 409 with an alternative_slots array proposing up to three nearby free timeslots. For a multi-day recurring request, days that don't fit go into a skipped array while the rest are still created ("status": "partial").

get /visitors API key

Retrieve visitor bookings for your tenant.

Query paramTypeDescription
tenant_namestringYour tenant. required
statusstringFilter: active, arrived, completed, cancelled.
from_dateISO 8601Start of the window. Default: now.
to_dateISO 8601End of the window. Default: 7 days from now.
recurring_onlybooltrue — only the parent bookings of recurrences.
include_occurrencesbooltrue — include automatically generated copies of recurring bookings.

Response · 200

{
  "status": "success",
  "count": 1,
  "bookings": [{
    "id": 142,
    "plate_number": "12ABC3",
    "visitor_name": "Jan Jansen",
    "start_time": "2026-07-10T09:00:00+00:00",
    "end_time": "2026-07-10T17:00:00+00:00",
    "status": "active",
    "recurrence_rule": null,
    "is_recurring_copy": false
  }]
}
put /visitors/{id} API key

Update a booking. All body fields are optional; send only what you want to change.

FieldTypeDescription
plate_numberstringNew license plate for the visitor.
visitor_namestringNew name of the visitor.
start_timeISO 8601New start time.
end_timeISO 8601New end time.
recurrence_end_dateISO 8601Change when a recurring series stops (parent booking only).

Request

PUT /chatbot/api/v1/visitors/142
{
  "tenant_name": "Silverflow",
  "plate_number": "99XYZ9"
}
delete /visitors/{id} API key

Cancel a booking.

Query paramTypeDescription
tenant_namestringYour tenant. required
cancel_seriesbooltrue — cancel all future recurrences in a series, whether you pass the parent booking or a copy. Past recurrences are left untouched.

Request

DELETE /chatbot/api/v1/visitors/142?tenant_name=Silverflow
post /visitors/create-with-invitation API key

Create a booking and receive a self-registration link. Send the link to the visitor; they open it to register their own license plate. The invitation expires at end_time. Accepts the same fields as POST /visitors (including recurrence — one link per weekday series).

Response · 201 (shape)

{
  "status": "success",
  "booking": { "id": 143, /* … */ },
  "invitation_url": "https://your-instance.revtek.nl/invite/<token>"
}

Recurrence

Bookings can repeat. Add the recurrence fields to POST /visitors and the system creates future recurrences automatically.

  • weekly — every 7 days.
  • biweekly — every 14 days.
  • monthly — the same date every month.

For weekly/biweekly, each weekday in recurrence_weekdays becomes its own independent series. New recurrences are generated automatically as earlier ones near their end, up to recurrence_end_date (or indefinitely if it's absent). Use GET /visitors?recurring_only=true to see the parent bookings and include_occurrences=true for the generated copies.

Request — weekdays Mon/Wed/Fri, until March

POST /chatbot/api/v1/visitors
{
  "tenant_name": "Silverflow",
  "visitor_name": "Contractor",
  "start_time": "2026-07-13T08:00:00Z",
  "end_time": "2026-07-13T18:00:00Z",
  "recurrence_rule": "weekly",
  "recurrence_weekdays": [0, 2, 4],
  "recurrence_end_date": "2026-03-01T00:00:00Z"
}

License plates

For plates with permanent access rather than a time-bound booking. For temporary visitor access, prefer visitor bookings.

post /plates API key

Add a permanent license plate to your tenant.

FieldTypeDescription
tenant_namestringrequiredYour tenant.
plate_numberstringrequiredThe plate to add.
person_namestringoptionalWho the plate belongs to.

Request

POST /chatbot/api/v1/plates
{
  "tenant_name": "Silverflow",
  "plate_number": "12ABC3",
  "person_name": "Rogier de Vries"
}

Response · 201

{
  "status": "success",
  "message": "License plate added",
  "plate": { "id": 57, "plate_number": "12ABC3", "tenant_name": "Silverflow" }
}

Duplicate plates

If the plate already exists anywhere in the system, the response is 409.

get /plates API key

Retrieve all license plates for your tenant. Query param: tenant_name.

Response · 200

{
  "status": "success",
  "count": 1,
  "plates": [{
    "id": 57,
    "plate_number": "12ABC3",
    "person_name": "Rogier de Vries",
    "is_vip": false,
    "expiry_date": null
  }]
}
put /plates/{id} API key

Update the plate or the name. The body accepts plate_number and/or person_name, plus tenant_name.

PUT /chatbot/api/v1/plates/57
{ "tenant_name": "Silverflow", "person_name": "R. de Vries" }
delete /plates/{id} API key

Permanently delete a license plate from your tenant. Query param: tenant_name.

DELETE /chatbot/api/v1/plates/57?tenant_name=Silverflow

Availability & occupancy

Read-only endpoints to check capacity before you book.

get /occupancy API key

Live occupancy for your tenant — regular, VIP, and visitor slots with current counts and limits. Query param: tenant_name.

Response · 200

{
  "status": "success",
  "tenant": "Silverflow",
  "occupancy": [{
    "parking_object": "Willem Fenengastraat",
    "visitor_occupancy": 2,
    "visitor_limit": 5,
    "available_visitor_slots": 3
  }],
  "summary": { "total_occupancy": 2, "available_slots": 3 }
}
get /timeslots API key

Available visitor timeslots for a day (hourly, 08:00–20:00).

Query paramTypeDescription
tenant_namestringYour tenant. required
dateISO dateDay to check. Default: today.
duration_hoursintLength of each timeslot. Default: 4.

Response · 200

{
  "status": "success",
  "date": "2026-07-10",
  "duration_hours": 4,
  "available_timeslots": [{
    "start_time": "2026-07-10T08:00:00+00:00",
    "end_time": "2026-07-10T12:00:00+00:00",
    "available_slots": 3, "total_slots": 5
  }]
}
get /tenants API key

List the tenants your API key may act on. With a tenant-bound key, that's only your own tenant — handy for confirming the exact name for other calls.

Webhooks

Optional. Register a URL and we'll send a POST whenever parking events occur — so your systems react in real time instead of polling.

post /webhooks API key

Register a webhook.

FieldTypeDescription
namestringrequiredA label for this webhook.
urlstringrequiredWhere we POST the event.
event_typestringrequiredOne of the event types below.
secretstringoptionalHMAC-SHA256 signing secret; payloads are signed when this is set.
tenant_namestringoptionalOnly fire for this tenant.

Event types

visitor.arrivedA booked visitor's plate drives in.
visitor.departedA visitor session ends.
plate.entryAny plate drives in.
plate.exitAny plate drives out.

Other webhook endpoints: GET /webhooks (list yours), DELETE /webhooks/{id} (delete one), and GET /webhooks/event-types (list valid types — no auth required).

get /health No auth

Public health check. Handy for uptime monitoring.

{ "status": "ok", "service": "Parking Manager Chatbot API", "version": "1.0.0" }