> ## Documentation Index
> Fetch the complete documentation index at: https://www.seam.co/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Get started with Yale Locks

> Connect a supported Yale lock, issue scheduled guest access, and verify changes with the Seam API.

Use Seam to connect a supported Yale lock, lock or unlock it remotely, and issue scheduled guest access. This guide uses the Yale Home or Yale Access connection and a keypad lock that supports online access codes.

## Check the connection path

| Your Yale setup                                                            | Start here                                                                                                                                        |
| -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| Yale Home or Yale Access, with built-in Wi-Fi or the required Wi-Fi bridge | Follow this guide. Use the `yale` provider key.                                                                                                   |
| Yale Z-Wave lock connected to a compatible SmartThings hub                 | Follow the [SmartThings guide](/docs/device-and-system-integration-guides/smartthings-hubs-+-devices/get-started-with-smartthings-hubs-+-smart-locks). |
| Another Yale app, module or model                                          | Check the [Yale supported devices and limitations](/docs/device-and-system-integration-guides/yale-locks/index) before building.                       |

Confirm the lock works in its manufacturer app and has the connection hardware its model requires. A Yale brand name alone does not establish which functions a device supports. Check the returned capability flags before using an operation.

[Create a Seam account and get an API key](https://console.seam.co/). Use a [sandbox workspace](/docs/core-concepts/workspaces#sandbox-workspaces) for virtual devices, or a production workspace for real locks. Keep the API key on your server.

## 1. Install the SDK

```bash theme={"dark"}
npm install seam
export SEAM_API_KEY='YOUR_SEAM_API_KEY'
```

The server-side examples use Node.js 24 and JavaScript. For other languages, see the [API and SDK reference](/docs/api/access_grants/create).

## 2. Connect the Yale account

Create a [Connect Webview](/docs/core-concepts/connect-webviews) and send its URL to the person who owns the Yale account. Use the `yale` provider key for this connection path.

```javascript JavaScript theme={"dark"}
import { Seam } from 'seam'

const seam = new Seam()
const connectWebview = await seam.connectWebviews.create({
  accepted_providers: ['yale'],
})
console.log(connectWebview.url)
```

For the [Yale sandbox account](/docs/device-and-system-integration-guides/yale-locks/yale-sample-data), use `jane@example.com`, password `1234`, and verification code `123456`. These credentials are only for virtual devices.

After the user finishes, retrieve the Connect Webview and list devices for that specific account:

```javascript JavaScript theme={"dark"}
const connected = await seam.connectWebviews.get({
  connect_webview_id: connectWebview.connect_webview_id,
})
if (!connected.login_successful || !connected.connected_account_id) {
  throw new Error('Complete the Yale account connection before continuing.')
}

const devices = await seam.devices.list({
  connected_account_id: connected.connected_account_id,
})
console.table(devices.map(({ device_id, display_name }) => ({ device_id, display_name })))
```

Choose the intended door's `device_id`. Do not automatically grant access to the first device returned from a customer's account.

## 3. Grant scheduled guest access

Use [Access Grants](/docs/use-cases/granting-access/index) for a guest's access lifecycle. The example below creates one code method for a keypad lock. Other credential types depend on the device and integration.

Set `YALE_DEVICE_ID` to the chosen virtual lock, then run this example on your server. It starts five minutes from now, uses whole-minute boundaries, and ends one hour later. For a real booking, convert the property's local check-in and checkout times to ISO timestamps with an explicit UTC offset.

```javascript JavaScript theme={"dark"}
const lock = await seam.devices.get({ device_id: process.env.YALE_DEVICE_ID })
if (!lock.properties.online || !lock.can_program_online_access_codes) {
  throw new Error('Choose an online Yale lock that supports online access codes.')
}

const startsAt = new Date(Math.ceil(Date.now() / 60000) * 60000 + 5 * 60000)
const endsAt = new Date(startsAt.getTime() + 60 * 60000)
const grant = await seam.accessGrants.create({
  user_identity: {
    full_name: 'Sandbox guest',
    email_address: `sandbox-${crypto.randomUUID()}@example.com`,
  },
  device_ids: [lock.device_id],
  starts_at: startsAt.toISOString(),
  ends_at: endsAt.toISOString(),
  requested_access_methods: [{ mode: 'code' }],
})
console.log(grant.access_grant_id)
```

Persist the returned grant and user identity IDs with your booking. Reuse them for changes; do not create another guest or grant every time your booking system retries a notification.

### Check issuance before sharing the code

A successful create request is not confirmation that the lock has received its code. Read the related access methods, or subscribe to [access method events](/docs/api/access_methods/events).

```javascript JavaScript theme={"dark"}
const related = await seam.accessGrants.getRelated({
  access_grant_ids: [grant.access_grant_id],
  include: ['access_methods'],
})
const methods = related.access_methods.filter((method) => method.mode === 'code')
const ready = methods.length > 0 && methods.every((method) =>
  method.is_issued && method.errors.length === 0 && method.pending_mutations.length === 0,
)
console.log({ ready })
```

If `ready` is false, retain a pending state and check the grant and method errors. Retry status checks with a bounded timeout or process the subsequent webhook. Share the method's `code` through your guest delivery flow only after issuance is confirmed. Do not log guest codes in production.

### Change or cancel the booking

Update the existing grant when checkout changes. Read it back and track the access method's pending changes before reporting completion.

```javascript JavaScript theme={"dark"}
await seam.accessGrants.update({
  access_grant_id: grant.access_grant_id,
  ends_at: new Date(endsAt.getTime() + 30 * 60000).toISOString(),
})
const updatedGrant = await seam.accessGrants.get({
  access_grant_id: grant.access_grant_id,
})
console.log(updatedGrant.ends_at)

// Run when the booking is cancelled or when this sandbox test is finished.
await seam.accessGrants.delete({ access_grant_id: grant.access_grant_id })
```

Deletion starts the removal workflow. Track [access method deletion](/docs/api/access_methods/events) and errors before treating physical access as revoked. An offline lock may need to reconnect. A sandbox exercises the API lifecycle; it cannot prove that a real door has accepted or removed a code.

If you created a guest solely for this test, also delete that user identity after its access has been removed. Keep identities that other bookings still use.

## Remote lock and unlock

For a direct remote command, check `can_remotely_lock` or `can_remotely_unlock`, then use [Lock Door](/docs/api/locks/lock_door) or [Unlock Door](/docs/api/locks/unlock_door). These commands return an [action attempt](/docs/core-concepts/action-attempts). They do not grant a guest ongoing access.

## Troubleshooting

| Symptom                            | Check and next action                                                                                                                                     |
| ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Lock does not appear               | Confirm the Yale app and module match the supported connection path. Check the connected account and the lock's connectivity in the Yale app.             |
| Code is pending                    | Inspect the grant, access method and device errors. A successful API request is separate from device provisioning.                                        |
| Code cannot be programmed          | Check keypad support, available code slots and format constraints. Yale integration errors can use an `august_` prefix.                                   |
| Update or removal has not finished | Keep the operation pending, check connectivity, and reconcile from the latest method state. Escalate unresolved errors with the request and resource IDs. |

See the [Yale error reference](/docs/device-and-system-integration-guides/yale-locks/index#troubleshooting) for provider-specific checks. For an application that pushes reservation data and lets Seam manage automations, continue with [Reservation Automations](/docs/capability-guides/reservation-automations).
