How to automate guest access for vacation rentals
Issue the guest's code in 60 seconds
1# The stay comes from your booking record. Computed here so the snippet runs.
2CHECK_IN=$(date -u +%Y-%m-%dT15:00:00Z)
3CHECK_OUT=$(date -u -v+3d +%Y-%m-%dT11:00:00Z 2>/dev/null || date -u -d '+3 days' +%Y-%m-%dT11:00:00Z)
4
5# One grant per booking: the guest, the unit's doors, the stay.
6curl -X POST "https://connect.getseam.com/access_grants/create" \
7 -H "Authorization: Bearer $SEAM_API_KEY" \
8 -H "Content-Type: application/json" \
9 -d '{
10 "user_identity": {
11 "full_name": "Jane Doe",
12 "email_address": "jane@example.com"
13 },
14 "device_ids": ["6ba7b811-9dad-11d1-80b4-00c04fd430c8"],
15 "requested_access_methods": [{ "mode": "code" }],
16 "starts_at": "'"$CHECK_IN"'",
17 "ends_at": "'"$CHECK_OUT"'"
18 }'Build it with your AI agent
- Reservation AutomationsPush reservations to Seam and let it manage codes across the booking lifecycle.
- Access GrantsPer-entrance, per-credential access: PIN codes, mobile keys and Instant Keys.
- Access CodesDirect, manual control of individual time-bound codes on a specific device.
1. Install the plugin
/plugin marketplace add seamapi/seam-plugin
/plugin install seam@seamapiThe Claude Code install also adds our documentation MCP server, so the agent can look up endpoints and device capabilities while it works. Cursor, Codex and other agents get the skills through npx skills add and can add the MCP server there separately.
2. Paste this prompt
Automate guest access for my vacation rental app with Seam, using the Access Grants skill.
Wire these four booking events to the Seam API:
- booking confirmed: /access_grants/create with a user_identity from the guest record, device_ids for the unit, requested_access_methods [{ mode: "code" }], and the stay as starts_at and ends_at. Store the access_grant_id on the booking.
- booking dates changed: /access_grants/update with the stored id and the new window. Do not create a second grant; the PIN digits survive an update.
- booking cancelled: /access_grants/delete with the stored id.
- check-in day: read the code with /access_methods/list, but only send it once is_issued is true. Prefer the access_method.issued webhook to polling.
Use a sandbox workspace with a virtual lock for the tests, and cover the shortened-stay and cancellation paths.What you can build
Self check-in without a lockbox
The code arrives in the guest's confirmation message and starts working at check-in. No key handover, no lockbox on the railing, and nothing to collect when they leave.
Access that follows the booking
A shortened stay updates the code's window in place, an extension stretches it, and a cancellation removes it. The lock always agrees with the reservation system.
One integration across every host's hardware
Hosts bring August, Yale, Schlage, TTLock, igloohome and whatever the last owner installed. The same grant programs all of them, so supporting a new host is connecting an account, not scoping a project.
How it works
Connect the host's locks once
Each host links their lock account through a Connect Webview during onboarding. Their locks come back as devices with capability flags, and locks they add later flow in without another login. Store the device ids against the unit.
1const connectWebview = await seam.connectWebviews.create({ 2 custom_redirect_url: "https://example.com/host/locks-connected", 3}) 4 5// The host logs in to their own lock account here, once. 6console.log(connectWebview.url)Create a grant when the booking is confirmed
One call on your booking webhook. The guest becomes a user identity, the unit's doors are the device_ids, and the stay is the window. Store the access_grant_id on the booking record, because every later change references it. Units behind offline hotel or multifamily systems also need a reservation_key on guest access; check can_belong_to_reservation on the entrance instead of branching on brand.
1const accessGrant = await seam.accessGrants.create({ 2 user_identity: { 3 full_name: booking.guestName, 4 email_address: booking.guestEmail, 5 }, 6 device_ids: [unit.frontDoorDeviceId], 7 requested_access_methods: [{ mode: "code" }], 8 starts_at: booking.checkIn, 9 ends_at: booking.checkOut, 10}) 11 12// Store the grant id on the booking. Every later change references it. 13await bookings.update(booking.id, { 14 accessGrantId: accessGrant.access_grant_id, 15})Send the code with the check-in details
Read the digits off the access method and drop them into the message you already send. Gate on is_issued: on real hardware the lock takes a moment to program, and the access_method.issued webhook tells you the moment the code is live.
1const [pinCode] = await seam.accessMethods.list({ 2 access_grant_id: booking.accessGrantId, 3}) 4 5// code is null until the lock is actually programmed. 6if (pinCode?.is_issued) { 7 await sendGuestMessage({ 8 body: `Your door code for check-in: ${pinCode.code}`, 9 }) 10}Map booking changes onto the grant
Date changes are /access_grants/update with the new window; the PIN digits survive, so there is nothing to re-send. A cancellation is /access_grants/delete, which revokes every credential under the grant. A booking that moves to a different unit is a delete plus a fresh grant, because update moves the time window only.
1// The guest extended a night. Same grant, same digits, new window. 2await seam.accessGrants.update({ 3 access_grant_id: booking.accessGrantId, 4 ends_at: booking.newCheckOut, 5}) 6 7// The booking was cancelled. This revokes every credential under the grant. 8await seam.accessGrants.delete({ 9 access_grant_id: booking.accessGrantId, 10})
Frequently asked questions
Where does the booking event come from?
Your own reservation system or PMS. Whatever fires when a booking is confirmed, changed or cancelled is the trigger; the Seam call is the same regardless of where the booking originated.
What happens if the lock is offline at check-in?
Seam queues the code and programs it when the lock reconnects, and the access method stays unissued until then. For units with unreliable connectivity, locks that take offline codes sidestep the problem entirely: the digits work without the lock ever being online.
Do cleaners and maintenance get the same code as guests?
Give them their own grants. A cleaner's grant can be ongoing or recurring per visit, and it is revocable on its own without touching a guest's access. One credential per person also keeps the door's log meaningful.
Can guests get a mobile key instead of a PIN?
Yes. Ask for both in one grant: requested_access_methods [{ mode: "code" }, { mode: "mobile_key" }]. The mobile key also carries an Instant Key link you can text, so guests who skip your app still get tap-to-unlock.
Which locks work best for vacation rentals?
Keypad locks that take remotely programmed codes are the workhorses: August, Yale, Schlage and TTLock models dominate the category. Our Airbnb smart lock guide compares the popular models; the capability pages list every lock that supports each credential.
What if the same guest books twice?
Reuse the user identity and create a grant per booking. Grants are the per-stay object, and identities are the per-person one, so a returning guest keeps one identity with a clean history of stays.
Related
- How to generate temporary access codes programmaticallyThe credential mechanics under this automation, including offline hotel systems and reservation keys.
- Best smart locks for AirbnbThe hardware side of the same job: which locks hosts actually buy, compared.
- Smart locks that support online access codesEvery model that takes a remotely programmed PIN, with live per-system status.
- Reservation Access GrantsWhen offline hotel and multifamily systems need a reservation_key, and how overrides work.