Guides/How to add mobile keys to your app

Implementation guide

How to add mobile keys to your app

Mobile keys let your users unlock doors with their phones, from inside your app. Seam provisions the credential on the lock's own system and covers people without your app through a shareable Instant Key link, so one integration serves both.

On this page
Quickstart

Issue a mobile key in 60 seconds

Create a grant, wait for issuance, then deliver the mobile SDK token or Instant Key URL. Run these examples on your server with a supported entrance ID and SEAM_API_KEY; the CLI and cURL examples also require jq.

1// npm install seam
2// Set SEAM_API_KEY and SEAM_ACS_ENTRANCE_ID for a supported entrance.
3import { Seam } from "seam"
4
5const seam = new Seam()
6const entranceId = process.env.SEAM_ACS_ENTRANCE_ID
7if (!entranceId) throw new Error("Set SEAM_ACS_ENTRANCE_ID")
8const startsAt = new Date()
9const endsAt = new Date(startsAt.getTime() + 30 * 24 * 60 * 60 * 1000)
10
11const accessGrant = await seam.accessGrants.create({
12  user_identity: { full_name: "Jane Doe", email_address: "jane@example.com" },
13  acs_entrance_ids: [entranceId],
14  requested_access_methods: [{ mode: "mobile_key" }],
15  starts_at: startsAt.toISOString(),
16  ends_at: endsAt.toISOString(),
17})
18
19// Poll at two-second intervals, at most 30 times.
20let mobileKey
21for (let attempt = 0; attempt < 30; attempt++) {
22  const methods = await seam.accessMethods.list({
23    access_grant_id: accessGrant.access_grant_id,
24  })
25  mobileKey = methods.find((method) => method.mode === "mobile_key")
26  if (mobileKey?.is_issued) break
27  await new Promise((resolve) => setTimeout(resolve, 2000))
28}
29if (!mobileKey?.is_issued) {
30  throw new Error("Access method is not issued yet. Check its errors and retry later.")
31}
32
33const clientSessionToken = mobileKey.client_session_token
34if (!clientSessionToken) throw new Error("Client session token is not available yet")
35// Return this token only to the authenticated member's app.
36// Initialize the iOS or Android Seam mobile SDK with the token.
37
38const instantKeyUrl = mobileKey.instant_key_url
39if (!instantKeyUrl) throw new Error("Instant Key URL is not available yet")
40// Your app sends instantKeyUrl with its own SMS or email provider.
41// Deliver it only to the member who owns this grant.
Fastest path

Build it with your AI agent

Install the Seam plugin and your coding agent picks up three integration skills: Reservation Automations, Access Grants and Access Codes. It then writes the calls the way we would. Paste the prompt below and let it build.

1. Install the plugin

/plugin marketplace add seamapi/seam-plugin
/plugin install seam@seamapi

The 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

Prompt
Using the Seam Access Grants skill, add mobile key unlock to my app. In a sandbox workspace: create a user identity for a member, create an access grant on an entrance with requested_access_methods [{ mode: "mobile_key" }] for a one-month membership window, then list the access methods and show me the client_session_token and the instant_key_url. Wait for is_issued before delivery. Then show how to pass client_session_token to the iOS or Android mobile SDK, and explain when to deliver instant_key_url through my app's own messaging provider.
Use cases

What you can build

  • Tap-to-unlock in your own app

    The Seam mobile SDK holds the credential and unlocks over Bluetooth, under your UI and your brand. Works with the phone offline, which is what stairwells, garages and basements demand.

  • Keys that arrive by text

    Every mobile key carries an Instant Key URL: a browser-based key with no download and no account. Day passes, visitors and the guest who refuses to install anything are all covered.

  • Membership access that manages itself

    The key lives on the grant's window, so a renewal extends it and a cancellation revokes it. Lost phone? Delete the grant and issue a new one; the door hardware never needs a visit.

Walkthrough

How it works

  1. Confirm the door can take a mobile key

    List the entrances for your connected access system and check can_unlock_with_mobile_key. Select a supported entrance and set SEAM_ACS_ENTRANCE_ID to its ID. The step examples use the client and imports from the quickstart.

    1// Set SEAM_ACS_SYSTEM_ID to your connected access system.
    2const entrances = await seam.acs.entrances.list({
    3  acs_system_id: process.env.SEAM_ACS_SYSTEM_ID,
    4})
    5const supportedEntrances = entrances.filter((entrance) => entrance.can_unlock_with_mobile_key)
    6console.log(supportedEntrances.map((entrance) => entrance.acs_entrance_id))
  2. Create an Access Grant with a mobile key

    Name the person, the doors and the window, and ask for mode mobile_key. This example creates a user identity inline; use user_identity_id for an existing member. The quickstart supplies the dates and selected entrance. Swap acs_entrance_ids for space_ids to cover a group of doors at once.

    1const accessGrant = await seam.accessGrants.create({
    2  user_identity: { full_name: "Jane Doe", email_address: "jane@example.com" },
    3  acs_entrance_ids: [entranceId],
    4  requested_access_methods: [{ mode: "mobile_key" }],
    5  starts_at: startsAt.toISOString(),
    6  ends_at: endsAt.toISOString(),
    7})
  3. Hand the key to your app

    Wait until the mobile access method is issued, then read client_session_token. Return it only to the authenticated member's app and initialize the iOS or Android SDK with that token. A session ID is not a token. The linked mobile SDK guide covers native initialization, activation, permissions, and unlocking.

    1// Poll at two-second intervals, at most 30 times.
    2let mobileKey
    3for (let attempt = 0; attempt < 30; attempt++) {
    4  const methods = await seam.accessMethods.list({
    5    access_grant_id: accessGrant.access_grant_id,
    6  })
    7  mobileKey = methods.find((method) => method.mode === "mobile_key")
    8  if (mobileKey?.is_issued) break
    9  await new Promise((resolve) => setTimeout(resolve, 2000))
    10}
    11if (!mobileKey?.is_issued) {
    12  throw new Error("Access method is not issued yet. Check its errors and retry later.")
    13}
    14
    15const clientSessionToken = mobileKey.client_session_token
    16if (!clientSessionToken) throw new Error("Client session token is not available yet")
    17// Return this token only to the authenticated member's app.
    18// Initialize the iOS or Android Seam mobile SDK with the token.
  4. Cover everyone else with the Instant Key

    The issued access method also carries an instant_key_url. Your app can deliver it through its own SMS or email provider; messaging is an application integration, not a Seam SDK call. It grants access on the same schedule, so deliver it only to the person who owns the grant.

    1const instantKeyUrl = mobileKey.instant_key_url
    2if (!instantKeyUrl) throw new Error("Instant Key URL is not available yet")
    3// Your app sends instantKeyUrl with its own SMS or email provider.
    4// Deliver it only to the member who owns this grant.
FAQ

Frequently asked questions

Do my users need to install an app?

Not always. With your own app, the Seam mobile SDK holds the credential and unlocks over Bluetooth. Without one, text the instant_key_url that comes with every mobile key.

Does a mobile key work when the phone has no signal?

Yes, on systems that provision the credential to the phone. The key unlocks over Bluetooth with both the phone and the lock offline, which is why mobile keys suit stairwells and garages.

Which platforms does the mobile SDK support?

iOS and Android. Both take a client session token, hold the credentials, and expose the scan-and-unlock flow; your app owns everything the user sees.

How do I revoke a mobile key?

Delete the grant, or let it expire at ends_at. Seam removes the credential on the underlying system, so a lost phone is one API call instead of a locksmith.

Can one person have a mobile key and a PIN code?

Yes. Request both modes in one Access Grant, or add an access method to an existing grant later. They share the grant's schedule and doors, so a dead battery on the phone is not a lockout.

How is this different from each lock vendor's own mobile SDK?

Vendor SDKs are per brand: a different credential model, provisioning flow and revocation rule each time. Seam issues mobile keys through one Access Grants call and one mobile SDK across every system it supports.

Pricing

Ready to Scale With You

Seam lets developers and businesses connect apps to real-world IoT devices. The free trial is built for small teams to build and test, while enterprise pricing scales with the biggest device fleets out there.
Best Enterprise Solution

Custom Subscription for Your Business

Access tailored solutions, paying a fixed monthly rate that scales as you grow.
Enhanced Security
Beta Features Access
Dedicated Support Channel
Volume Discounts
No Usage Limits
Trusted by Over 1,000 Companies
Start Now

Try It for Free

Start with a free trial and explore the full API and related features.

Have questions? Talk to our team.

Chat with us to learn how Seam can power your access automation.
—“Discovering Seam was one of these Aha moments in the business. I couldn’t believe what I was seeing. I mean, it was exactly what we were looking for: a simple API that we could integrate and have access to all these devices in a matter of seconds.”
François Gouelo
CEO, Enso Connect
Company
How many devices you need to connect?
Name
Email
How did you find us?
Comment
We usually answer within 24 hours.
One API for All Devices
Global Infrastructure for Controlling the Physical World
Seam makes controlling IoT devices seamless and programmable. Our teams operate globally,
enabling businesses of all sizes.
Smart Locks
Access Systems
Knowledge
Lock Capabilities
Thermostats
Sensors
© 2026 Seam Labs, Inc.