Brings the key for a stay into line with the reservation as it stands right now,
creating it if it does not exist yet. Safe to call repeatedly with the same body.
This is the operation to use when a caller is driving keys from reservation data and
cannot easily track whether it has already created one — a workflow retrying after a
failure, a connector replaying an event, a scheduled reconciliation. Rather than
asking the caller to check first and branch, the key is resolved from
stayExternalId and either created or updated in place.
The pin is never regenerated. Once a pin has been issued for a stay it stays the
same for the life of that key, however many times this operation runs. A guest who
has been told their pin will not find it changed underneath them.
Each call re-evaluates the request against the controller's current configuration —
unit mapping, the unit matrix, timezone handling. Dates that moved, a unit assigned
late, or a changed configuration are therefore picked up simply by calling again;
there is nothing to replay and no separate reconciliation verb.
externalId in the body must agree with the path. stayExternalId says which
stay is being addressed and the body describes it; if the body carries a different
externalId the request contradicts itself and is refused with 400. Omitting it is
not a disagreement — the path value is used. Send it only if it matches.
Virtual pins. On a controller configured with virtualBefore, a key whose start
is far enough out is created virtual — the pin is returned immediately but is not
written to the locking system yet. Calling this operation once the window has opened
and a unit is assigned writes it to the locking system and flips isVirtual to
false. That is the only way a virtual pin is materialised: there is deliberately no
separate endpoint for it, because materialisation needs the current reservation data
that this request already carries.
Both conditions are needed, so the request that materialises a key must carry
unitName. A virtual key minted before a room was assigned stays virtual until a
call supplies one; a call made after the window has opened but still without a unit is
refused with 422, and the held key is left untouched rather than half-written. Call
again with the unit once the reservation has one.
Interpreting the outcome. Every successful call returns 200 with the key as it
now stands — whether it was created, materialised, or already correct and left
untouched. Do not branch on the status code; read isVirtual to find out whether the
pin is live in the locking system. A 404 means the controller or the stay's key is
gone (a cancelled reservation, for instance) and the caller should stop rather than
retry; 5xx is worth retrying.