LatchleyLatchley

Documentation

Latchley Platform

Generate time-limited door access codes for your properties from any external system (your own booking flow, a PMS, or a no-code tool) with a single REST call. Authenticate with a per-property API key, and Latchley creates the code, emails it to the guest, and the door opens for exactly the window you set.

Overview

The Access Code API lets any external system generate a Latchley door code for a property it holds an API key for. You send the guest details and the validity window; Latchley picks (or accepts) a PIN, emails it to the guest, and the code opens the door for exactly that window. Codes are enforced on-device, so they keep working even if the door's internet drops.

StepYouLatchley
1Generate a per-property API key in the dashboardScopes the key to that one property
2POST /api/v1/codes with guest + validity windowValidates, creates a time-limited PIN
3(nothing)Emails the code to the guest and syncs it to the door
4Guest enters the PIN at the doorOpens for the window; auto-expires after
Access only

This API generates access codes. It does not manage reservations, availability, or payments. Pair it with whatever booking/PMS you already run: when a stay is confirmed on your side, call this endpoint to issue the guest their door code.

Quickstart

Generate a key under Settings → API Keys, then create a code. Replace YOUR_DOMAIN with your Latchley host.

curl -X POST https://YOUR_DOMAIN/api/v1/codes \
  -H "Authorization: Bearer latchley_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "guest_name":  "Sarah Chen",
    "guest_email": "sarah@example.com",
    "valid_from":  "2026-07-10T15:00:00Z",
    "valid_until": "2026-07-13T11:00:00Z"
  }'

The response contains the generated pin. The guest also receives it by email automatically.

Authentication

Every request authenticates with a per-property API key sent as a Bearer token:

Authorization: Bearer latchley_live_…

A key is scoped to exactly one property, so you never pass a property id. The key itself determines which property the code is created for. Keys come in two flavours by prefix:

PrefixModeBehaviour
latchley_live_ProductionCreates real codes and emails the guest
latchley_test_TestValidates your request and returns a masked code, but creates nothing and sends no email

A missing, malformed, or revoked key returns 401 INVALID_API_KEY.

Generating an API key

In the dashboard, open Settings → API Keys, pick the property in the switcher, and click Generate Key. Give it a name you'll recognise (e.g. “Booking website”).

Shown once

The full key is displayed a single time, on creation, so copy it into your integration's secrets right away. Latchley only stores a hash, so it can never show you the key again; if you lose it, revoke it and generate a new one. Tick Test key to create a latchley_test_ key for wiring up safely.

GET /api/v1/doors

Lists the doors on the key's property, so you can discover the device_ids to scope a per-door code (and tell whether scoping is needed at all). The key determines the property, so there are no parameters.

Example response

{
  "ok": true,
  "door_scope_mode": "per_door",
  "doors": [
    { "id": "a1b2…", "name": "Main entrance", "shared": true,  "status": "online" },
    { "id": "c3d4…", "name": "Room 2",        "shared": false, "status": "online" },
    { "id": "e5f6…", "name": "Room 3",        "shared": false, "status": "offline" }
  ]
}
FieldMeaning
door_scope_modeper_door means a code must name its doors via device_ids. all_doors means every code opens all doors and device_ids is not accepted.
doors[].idThe value to put in device_ids on POST /v1/codes.
doors[].sharedA shared door (e.g. a main entrance). Always added to every code automatically, so you don't need to pass it.
doors[].statusonline, offline, or pending_config.

POST /api/v1/codes

Creates a time-limited access code for the key's property and emails it to the guest.

FieldTypeRequiredDescription
guest_namestringYesGuest name, shown in the dashboard and the email.
guest_emailstringYesWhere the code is emailed. Must be a valid address.
valid_fromISO 8601YesWhen the code becomes active. Use a UTC (…Z) timestamp to avoid ambiguity.
valid_untilISO 8601One of*When the code expires.
duration_hoursnumberOne of*Alternative to valid_until: hours after valid_from.
guest_phonestringNoOptional contact number stored with the code.
device_idsstring[]Per-doorWhich doors the code opens. Required when the property is in per-door mode; rejected otherwise. Shared doors are always added automatically.
pinstringNoForce a specific 6-digit PIN, or an nfc:<tag-id>. Omit to auto-generate a unique PIN.

* Provide either valid_until or duration_hours.

Example response

{
  "ok": true,
  "code": {
    "id":          "8f3c…",
    "pin":         "486213",
    "status":      "active",
    "guest_name":  "Sarah Chen",
    "guest_email": "sarah@example.com",
    "valid_from":  "2026-07-10T15:00:00.000Z",
    "valid_until": "2026-07-13T11:00:00.000Z",
    "device_ids":  []
  }
}
Per-door properties

If the property is in per-door mode, device_ids is required, so a code must name at least one door. Fetch the ids from GET /v1/doors. Any door marked as shared (e.g. a main entrance) is always included on top of your list, server-side, so you can't accidentally issue a code that skips it, and you don't need to pass it yourself. For all-doors properties, omit device_ids.

Error Codes

Errors return { "ok": false, "error": "CODE", "message": "…" } with the matching HTTP status.

ErrorHTTPMeaning
INVALID_API_KEY401Missing, malformed, or revoked key.
INVALID_REQUEST400A field failed validation. The message says which.
MISSING_FIELDS400Request body wasn't valid JSON.
NOT_FOUND404The key's property no longer exists.
RATE_LIMIT_EXCEEDED429Over the per-key hourly limit.
SERVER_ERROR500Something failed on our side. Safe to retry.

Rate Limits

Each API key is limited to 100 requests per hour. Over the limit returns 429 RATE_LIMIT_EXCEEDED. Back off and retry after the window resets. Issuing a code per confirmed stay stays comfortably within this; if you expect higher volume, email luca@eventcage.com.

Questions? Email luca@eventcage.com