Check-in Instructions
An instruction is one step of the guided arrival or departure a guest follows in the guest portal: “Park in bay 3”, “Enter the side door with your code”, “Leave the keys on the counter”. Each step belongs to one stage, check_in or check_out, and to either one property or one property group. This guide covers managing those steps. Every field is listed on the operation’s page in the API Reference.
| Operation | Request | Permission |
|---|---|---|
listInstructions | GET /instructions | view_properties |
getInstruction | GET /instructions/{id} | view_properties |
createInstruction | POST /instructions | modify_properties |
updateInstruction | PATCH /instructions/{id} | modify_properties |
reorderInstruction | POST /instructions/{id}/reorder | modify_properties |
deleteInstruction | DELETE /instructions/{id} | modify_properties |
Paths are relative to your region’s base URL, for example https://api-us.suiteop.com/api/v1. See Authentication for permissions.
What the guest sees
Section titled “What the guest sees”A property’s guests see its group’s steps first, then the property’s own steps. Each scope keeps its own order; the two lists are never interleaved or deduplicated. There is no draft or publish state: the portal renders the stored steps, so a create, edit, reorder or delete shows on the guest’s next load.
Titles and descriptions can contain merge tokens, which the portal fills in per reservation: {{door_code}}, {{wifi_name}}, {{wifi_password}}, {{guest_name}}, {{checkin_time}}, {{checkout_time}}, {{address}} and {{host_name}}. A known token with no value renders empty. Anything else in double braces is shown as typed.
Listing steps
Section titled “Listing steps”GET /instructions returns every matching step as a bare array under data. It is not paginated, so there is no limit, offset or meta.pagination. Steps come back in the order guests see them within their scope: by sortOrder, then creation time.
curl "https://api-us.suiteop.com/api/v1/instructions?propertyId=9a3d7e40-5b1c-4f2e-8d6a-1c2b3d4e5f60&type=check_in" \ -H "Authorization: Bearer sk_live_your_key_here"{ "data": [ { "id": "3f2b8c1d-7e4a-4b9f-a2c6-5d1e0f9a8b7c", "type": "check_in", "sortOrder": 0, "title": "Find the side entrance", "description": "Walk past the garden gate of Harbour Cottage and follow the path to the blue side door.", "fixedCode": null, "videoUrl": null, "isAccessDisplayed": false, "codeType": null, "propertyId": "9a3d7e40-5b1c-4f2e-8d6a-1c2b3d4e5f60", "propertyGroupId": null, "deviceId": null, "isTapToUnlockEnabled": false, "imageUrl": "https://images.example.com/harbour-cottage/side-door.jpg", "createdAt": "2026-07-01T09:12:44.000Z", "updatedAt": "2026-07-01T09:12:44.000Z" } ], "meta": { "requestId": "…" }}| Filter | Notes |
|---|---|
propertyId | Only the property’s own steps. Its group’s steps aren’t included; list them with propertyGroupId |
propertyGroupId | Only the group’s shared steps (listPropertyGroups gives group IDs) |
type | check_in or check_out. Omit for both stages |
| (neither ID) | Every step you can reach: property steps, group steps, and steps bound to neither. Check propertyId and propertyGroupId to tell them apart |
To reconstruct what a guest of one property sees, list the group’s steps and the property’s steps separately and concatenate them in that order.
GET /instructions/{id} returns one step with the same fields. A step from another organization, or outside your property scope, returns 404.
title and description are always the English text, whatever languages your organization uses.
Creating a step
Section titled “Creating a step”type, title and description are required, plus exactly one of propertyId or propertyGroupId. Sending both, or neither, is rejected with 400.
curl -X POST https://api-us.suiteop.com/api/v1/instructions \ -H "Authorization: Bearer sk_live_your_key_here" \ -H "Idempotency-Key: 7c9e6679-7425-40de-944b-e07fc1f90ae7" \ -H "Content-Type: application/json" \ -d '{ "type": "check_in", "propertyId": "9a3d7e40-5b1c-4f2e-8d6a-1c2b3d4e5f60", "title": "Open the side door", "description": "Enter {{door_code}} on the keypad, then press the lock button.", "isAccessDisplayed": true, "codeType": "property_fixed_code" }'The response is 201, with the stored step under data:
{ "data": { "id": "5e8a2f14-3c6b-4d7e-9f10-a1b2c3d4e5f6", "type": "check_in", "sortOrder": 1, "title": "Open the side door", "description": "Enter {{door_code}} on the keypad, then press the lock button.", "fixedCode": null, "videoUrl": null, "isAccessDisplayed": true, "codeType": "property_fixed_code", "propertyId": "9a3d7e40-5b1c-4f2e-8d6a-1c2b3d4e5f60", "propertyGroupId": null, "deviceId": null, "isTapToUnlockEnabled": null, "createdAt": "2026-07-02T14:03:10.000Z", "updatedAt": "2026-07-02T14:03:10.000Z" }, "meta": { "requestId": "…" }}const res = await fetch('https://api-us.suiteop.com/api/v1/instructions', { method: 'POST', headers: { Authorization: `Bearer ${process.env.SUITEOP_API_KEY}`, 'Content-Type': 'application/json', 'Idempotency-Key': crypto.randomUUID(), }, body: JSON.stringify({ type: 'check_out', propertyId: '9a3d7e40-5b1c-4f2e-8d6a-1c2b3d4e5f60', title: 'Leave the keys', description: 'Please leave both keys on the kitchen counter and pull the door shut.', }),})const { data } = await res.json()const stepId = data.idField notes:
titleis a single line of plain text, 1 to 500 characters.descriptionis plain text or HTML rich text, 1 to 20,000 characters. Both are stored as the English source and machine-translated into your organization’s other languages in the background, so other languages can lag behind the response.sortOrderis the zero-based position among steps of the same scope and stage. Omit it to append to the end. An explicit value doesn’t shift the other steps, so two steps can end up with the same position; usereorderInstructionto move a step instead.videoUrltakes anhttporhttpsURL of up to 2,000 characters, an empty string, ornull.- Images can’t be set through the API.
imageUrlappears onlistInstructionsandgetInstructiononly; create and update responses don’t carry it. - The create and update responses echo the stored
isTapToUnlockEnabled, which can benull(see below). The list and get responses return the resolvedtrueorfalsethe guest actually gets.
Showing an access code
Section titled “Showing an access code”Four fields decide what code a step shows and whether it offers a one-tap unlock button:
| Field | Meaning |
|---|---|
isAccessDisplayed | Shows the resolved code on the step. Without it the code only appears where {{door_code}} is typed in the text |
codeType | manual_code (the step’s fixedCode), reservation_dynamic_code (the code issued for the stay), property_fixed_code (the property’s static code), group_fixed_code (the group’s static code), or null |
fixedCode | Literal text up to 200 characters. It provisions nothing on a lock. manual_code shows it; on property_fixed_code and group_fixed_code it overrides the static code |
deviceId | The lock the step is about, from listDevices. It picks which lock’s stay code reservation_dynamic_code shows, and which lock the unlock button opens. It must be a lock reachable from the step’s property or group |
isTapToUnlockEnabled | Whether the guest gets an unlock button. Check-in steps only: check-out steps are always stored as false. null means the button appears whenever deviceId is set |
These combinations are rejected with 400 validation_error:
isAccessDisplayed: truewithreservation_dynamic_code, orisTapToUnlockEnabled: true, without adeviceId, when the step’s property or group has a lock that could serve it. On a group step a device is always required for these.- A
deviceIdthat isn’t a lock available to that property or group, or one that can’t display a dynamic code whenreservation_dynamic_codeis shown. property_fixed_codeon a group step without afixedCode. Each property’s own code would otherwise appear under a shared building step.
The static property code isn’t shown while the property has isUnitCodeDisabled set (see Properties).
Updating a step
Section titled “Updating a step”PATCH /instructions/{id} takes the fields to change inside a data object. Fields you leave out keep their current value; nullable fields take null to clear them.
curl -X PATCH https://api-us.suiteop.com/api/v1/instructions/5e8a2f14-3c6b-4d7e-9f10-a1b2c3d4e5f6 \ -H "Authorization: Bearer sk_live_your_key_here" \ -H "Content-Type: application/json" \ -d '{"data": {"title": "Open the blue side door", "videoUrl": "https://videos.example.com/harbour-cottage-entry.mp4"}}'The response is the updated step, in the same shape as the create response.
- Scope and stage can’t change. To move a step to another property or group, or from check-in to check-out, delete it and create it again.
- Changing
titleordescriptionreplaces the other languages. The new English text is machine-translated again and overwrites every existing translation of that field, including ones written by hand. Resending the stored text unchanged is a no-op and re-translates nothing. - Clearing
deviceIdalso turns the unlock button off on a check-in step, unless the same call sendsisTapToUnlockEnabled. - The access-code rules above are checked when you pick a new device or newly turn on dynamic-code display or unlock. Edits that don’t touch access leave an older step’s settings alone.
Reordering steps
Section titled “Reordering steps”POST /instructions/{id}/reorder moves one step and renumbers the rest of its scope and stage to 0, 1, 2, …:
curl -X POST https://api-us.suiteop.com/api/v1/instructions/5e8a2f14-3c6b-4d7e-9f10-a1b2c3d4e5f6/reorder \ -H "Authorization: Bearer sk_live_your_key_here" \ -H "Content-Type: application/json" \ -d '{"sortOrder": 0}'The response is {"data": {"success": true}, "meta": {"requestId": "…"}}. A sortOrder past the last position puts the step at the end. Call listInstructions afterwards to read the new order.
Deleting a step
Section titled “Deleting a step”DELETE /instructions/{id} removes the step permanently, along with its stored image file. There is no archive or undo. The remaining steps of the same scope and stage are renumbered from 0, so their sortOrder values change. The response is {"data": {"success": true}, "meta": {"requestId": "…"}}.
Property scope
Section titled “Property scope”API keys reach every property. A credential limited to some properties (see Members) works within that reach:
- Lists show only steps on its properties, on groups containing at least one of them, and steps bound to neither. Filtering by a property or group outside that reach returns an empty list, not an error.
getInstruction,updateInstruction,reorderInstructionanddeleteInstructionreturn404for a step outside that reach.createInstructionon a property outside the reach returns404. On a group, it needs every property in the group, since the step appears to all of their guests; otherwise it returns404.
Withheld door codes
Section titled “Withheld door codes”An sk_ API key always reads fixedCode. An OAuth token acts as its member, and unless the token carries modify_properties or manage_lock_code (granted to the token and held by the member), listInstructions and getInstruction withhold a step’s fixedCode until 00:00 property-local time on the due day of an open task of theirs (as assignee or collaborator). For a property step the task must be at that property; for a group step, at any property of the group. A step bound to neither is always withheld from such a token. A task with no due date counts only while in_progress, and an overdue task keeps counting for up to 7 days.
A withheld step has fixedCode: null plus codeWithheld: true and codeRevealAt, the ISO 8601 instant the code becomes visible (null when no task of theirs will reveal it in the next 14 days, or none ever can, as for a step bound to neither). Both fields are absent when the code is returned, so a null fixedCode without codeWithheld simply means the step has none.