Key cards
Connect a hotel's key-card system to ChatBeds. ChatBeds asks it for a guest's key at check-in and cancels the key at check-out, through an https address or the bridge on the desk computer.
A hotel keeps its own key-card system: its locks, encoders, licence and the lock company's hotel-system interface. ChatBeds sends that system key requests. At check-in, at the reception kiosk or the desk, it asks for a key valid until check-out. At any check-out, from the dashboard, WhatsApp or the kiosk, it cancels the key.
This page is for lock companies and connector services, and for whoever sets up a hotel's bridge.
Two ways to connect
| Where the key-card system is | How ChatBeds reaches it | |
|---|---|---|
| An https address | In the lock company's cloud, or behind a connector service | ChatBeds sends each request to the address, signed |
| The bridge | On a server in the hotel's own network | A small ChatBeds program on the desk computer asks for requests and passes them on. Nothing at the hotel is opened to the internet |
The hotel chooses one in Settings → Reception → Key cards. There is also a test lock, which answers yes to everything, so a hotel can try the whole check-in first.
The request
Every request has the same shape, whichever way it travels:
{
"id": "6b1e4f0e-3c55-4a8e-9f61-1f0b8a9c2d10",
"action": "make",
"hotel": "Pearl Hotel",
"room": "101",
"guest": "Sara B.",
"valid_from": "2026-10-12T09:30:00+00:00",
"valid_until": "2026-10-14T07:00:00+00:00",
"cards": 1,
"where": "desk",
"key_ref": null
}| Field | Meaning |
|---|---|
id | The request's id. Send it back with the bridge's answer. Use it to ignore a repeat |
action | make a key, cancel one (key_ref says which), or test the connection without a real key |
room | The room's name in ChatBeds, which is usually its number. Map it to the lock's own room if they differ |
guest | First name and the surname's initial only |
valid_from, valid_until | When the key works: from now until the check-out time on the departure day, in UTC |
cards | How many cards to make, 1 to 4 |
where | desk (the encoder at the desk), dispenser (next to the kiosk) or mobile (a phone key, if the system has them) |
key_ref | For cancel: the reference your system gave when the key was made |
The answer
{ "ok": true, "key_ref": "VL-0007781" }{ "ok": false, "error": "Encoder 2 is offline" }Give a key_ref for every key made: ChatBeds sends it back to cancel that key. A short, plain error is shown to the hotel's staff, who then make the key by hand. A failed key never stops a check-in.
An https address
ChatBeds sends POST requests with the JSON body and these headers:
| Header | |
|---|---|
Content-Type | application/json |
ChatBeds-Signature | t=<unix seconds>,v1=<HMAC-SHA256 of "t.body" with the secret, lowercase hex>, as for webhooks |
ChatBeds-Key-Id | The request's id |
- The secret starts with
cks_and is shown once when the hotel connects. Refuse any request whose signature doesn't match, or whosetis more than five minutes old. - The answer: send it in the same response, within 15 seconds, with status 200. A 4xx or 5xx counts as failed.
- The address must be public
https, and ChatBeds doesn't follow redirects.
The bridge
The bridge is tools/keycard-bridge/bridge.py from ChatBeds. It needs only Python 3.9 or later. It runs on a computer that can reach the key-card system's server.
CHATBEDS_BRIDGE_TOKEN=ckb_... python3 bridge.py --handler http --target http://127.0.0.1:8090/keysThe token is shown once when the hotel chooses the bridge. Saving the settings again with a new token stops the old one.
Every two seconds, the bridge:
- asks
GET /api/v1/keycard-bridge/jobs(withAuthorization: Bridge ckb_...) for the waiting requests; - hands each request to its handler;
- sends the answer to
POST /api/v1/keycard-bridge/jobs/{id}.
A request is handed out once. If its answer doesn't arrive within two minutes, it fails and the desk is told.
| Handler | Passes each request to |
|---|---|
http | A local address, as JSON: the lock company's interface, or a connector program |
command | A program, with the request as JSON on its standard input; it prints the answer as JSON |
module | A Python module in handlers/ with handle(request) -> answer, where a brand's own protocol is written |
test | Nobody: it answers yes |
Writing a brand's handler
Each lock company gives its hotel-system interface to its partners. Copy handlers/template.py and write handle from that specification:
makegives a new key for the room, valid for the times given. A new key normally stops earlier guests' keys for that room.cancelstops the key withkey_ref.testproves the connection.
Never log the guest's name.
Brands
| Brand | Systems | What the hotel asks the lock company |
|---|---|---|
| Salto | Salto KS (cloud), Salto Space | To enable the hotel-system interface, through the cloud or the key server |
| dormakaba | Ambiance, Saflok, Community | To enable the hotel-system interface on its server |
| ASSA ABLOY (VingCard) | Visionline, Vostio | To enable the hotel-system interface |
| Onity | Onity's encoders and hotel-system interface | To enable the hotel-system interface |
| Others | Any system with a hotel-system interface, or a multi-brand connector | To enable the interface, or a connector |
ChatBeds writes the message to the lock company for the hotel, in Settings → Reception → Key cards. The lock company usually charges for its interface.
Building something?