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

# Using Key Cards

> Learn how to create an Access Grant with a key card access method, then encode or assign the card to your user.

Key cards are plastic cards that unlock doors when presented to a card reader. When you request a `card` access method in an Access Grant, Seam creates a card credential. Depending on your access control system, you either encode the credential onto a physical card using a card encoder or the system assigns the credential to a pre-registered card automatically.

Key cards work with:

* **Access control systems** — Salto KS, Salto Space, ASSA ABLOY Visionline and Vostio, dormakaba, Brivo, and other ACS platforms that support card-based credentials. Specify entrances with `acs_entrance_ids` or use `space_ids`.

***

## Before You Begin

To use key cards, you need:

* A [Seam API key](https://console.seam.co)
* A connected ACS that supports card-based credentials
* A [user identity](/capability-guides/mobile-access/managing-mobile-app-user-accounts-with-user-identities) representing the person who will receive the card
* An entrance that supports card access (`can_unlock_with_card` is `true`)
* For encoding: a compatible card encoder connected to Seam (see [Working with Card Encoders and Scanners](/low-level-apis/access-systems/working-with-card-encoders-and-scanners/index))

***

## Step 1: Verify Entrance Support

List the entrances for your ACS and confirm that `can_unlock_with_card` is `true`.

<CodeGroup>
  ```javascript JavaScript theme={null}
  const entrances = await seam.acs.entrances.list({
    acs_system_id: 'c359cba2-8ef2-47fc-bee0-1c7c2a886339',
  })

  const cardEntrances = entrances.filter(
    (e) => e.can_unlock_with_card
  )
  ```

  ```python Python theme={null}
  entrances = seam.acs.entrances.list(
      acs_system_id="c359cba2-8ef2-47fc-bee0-1c7c2a886339"
  )

  card_entrances = [
      e for e in entrances if e.can_unlock_with_card
  ]
  ```

  ```ruby Ruby theme={null}
  entrances = seam.acs.entrances.list(
    acs_system_id: "c359cba2-8ef2-47fc-bee0-1c7c2a886339"
  )

  card_entrances = entrances.select do |e|
    e.can_unlock_with_card
  end
  ```

  ```php PHP theme={null}
  $entrances = $seam->acs->entrances->list(
    acs_system_id: "c359cba2-8ef2-47fc-bee0-1c7c2a886339"
  );

  $cardEntrances = array_filter(
    $entrances,
    fn($e) => $e->can_unlock_with_card
  );
  ```

  ```csharp C# theme={null}
  var entrances = seam.Acs.Entrances.List(
    acsSystemId: "c359cba2-8ef2-47fc-bee0-1c7c2a886339"
  );

  var cardEntrances = entrances
    .Where(e => e.CanUnlockWithCard)
    .ToList();
  ```

  ```java Java theme={null}
  var entrances = seam.acs().entrances().list(
    AcsEntrancesListRequest.builder()
      .acsSystemId("c359cba2-8ef2-47fc-bee0-1c7c2a886339")
      .build()
  );
  ```

  ```bash cURL theme={null}
  curl -X 'POST' \
    'https://connect.getseam.com/acs/entrances/list' \
    -H "Authorization: Bearer ${SEAM_API_KEY}" \
    -H 'Content-Type: application/json' \
    -d '{
    "acs_system_id": "c359cba2-8ef2-47fc-bee0-1c7c2a886339"
  }'
  ```
</CodeGroup>

***

## Step 2: Create an Access Grant with a Key Card

Create an [Access Grant](/use-cases/granting-access/index) specifying `card` as the requested access method mode.

<CodeGroup>
  ```javascript JavaScript theme={null}
  const accessGrant = await seam.accessGrants.create({
    user_identity_id: '22222222-2222-2222-2222-222222222222',
    acs_entrance_ids: ['f74e4879-5991-4e2f-a368-888983dcfbfc'],
    requested_access_methods: [
      { mode: 'card' }
    ],
    starts_at: '2025-07-13T15:00:00.000Z',
    ends_at: '2025-07-16T11:00:00.000Z',
  })
  ```

  ```python Python theme={null}
  access_grant = seam.access_grants.create(
      user_identity_id="22222222-2222-2222-2222-222222222222",
      acs_entrance_ids=["f74e4879-5991-4e2f-a368-888983dcfbfc"],
      requested_access_methods=[{"mode": "card"}],
      starts_at="2025-07-13T15:00:00.000Z",
      ends_at="2025-07-16T11:00:00.000Z",
  )
  ```

  ```ruby Ruby theme={null}
  access_grant = seam.access_grants.create(
    user_identity_id: "22222222-2222-2222-2222-222222222222",
    acs_entrance_ids: ["f74e4879-5991-4e2f-a368-888983dcfbfc"],
    requested_access_methods: [{ mode: "card" }],
    starts_at: "2025-07-13T15:00:00.000Z",
    ends_at: "2025-07-16T11:00:00.000Z"
  )
  ```

  ```php PHP theme={null}
  $accessGrant = $seam->access_grants->create(
    user_identity_id: "22222222-2222-2222-2222-222222222222",
    acs_entrance_ids: ["f74e4879-5991-4e2f-a368-888983dcfbfc"],
    requested_access_methods: [["mode" => "card"]],
    starts_at: "2025-07-13T15:00:00.000Z",
    ends_at: "2025-07-16T11:00:00.000Z"
  );
  ```

  ```csharp C# theme={null}
  var accessGrant = seam.AccessGrants.Create(
    userIdentityId: "22222222-2222-2222-2222-222222222222",
    acsEntranceIds: new List<string>
    {
      "f74e4879-5991-4e2f-a368-888983dcfbfc"
    },
    requestedAccessMethods: new List<RequestedAccessMethod>
    {
      new RequestedAccessMethod { Mode = "card" }
    },
    startsAt: "2025-07-13T15:00:00.000Z",
    endsAt: "2025-07-16T11:00:00.000Z"
  );
  ```

  ```java Java theme={null}
  var accessGrant = seam.accessGrants().create(
    AccessGrantsCreateRequest.builder()
      .userIdentityId("22222222-2222-2222-2222-222222222222")
      .acsEntranceIds(List.of(
        "f74e4879-5991-4e2f-a368-888983dcfbfc"
      ))
      .requestedAccessMethods(List.of(
        RequestedAccessMethod.builder()
          .mode("card")
          .build()
      ))
      .startsAt("2025-07-13T15:00:00.000Z")
      .endsAt("2025-07-16T11:00:00.000Z")
      .build()
  );
  ```

  ```bash cURL theme={null}
  curl -X 'POST' \
    'https://connect.getseam.com/access_grants/create' \
    -H "Authorization: Bearer ${SEAM_API_KEY}" \
    -H 'Content-Type: application/json' \
    -d '{
    "user_identity_id": "22222222-2222-2222-2222-222222222222",
    "acs_entrance_ids": ["f74e4879-5991-4e2f-a368-888983dcfbfc"],
    "requested_access_methods": [{ "mode": "card" }],
    "starts_at": "2025-07-13T15:00:00.000Z",
    "ends_at": "2025-07-16T11:00:00.000Z"
  }'
  ```
</CodeGroup>

***

## Step 3: Deliver the Key Card

List the access methods for the Access Grant and check the `is_encoding_required` property to determine whether you need to encode the card or whether the system assigns it automatically.

<CodeGroup>
  ```javascript JavaScript theme={null}
  const accessMethods = await seam.accessMethods.list({
    access_grant_id: accessGrant.access_grant_id,
  })

  const card = accessMethods[0]
  console.log(card.is_encoding_required)
  ```

  ```python Python theme={null}
  access_methods = seam.access_methods.list(
      access_grant_id=access_grant.access_grant_id
  )

  card = access_methods[0]
  print(card.is_encoding_required)
  ```

  ```ruby Ruby theme={null}
  access_methods = seam.access_methods.list(
    access_grant_id: access_grant.access_grant_id
  )

  card = access_methods[0]
  puts card.is_encoding_required
  ```

  ```php PHP theme={null}
  $accessMethods = $seam->access_methods->list(
    access_grant_id: $accessGrant->access_grant_id
  );

  $card = $accessMethods[0];
  echo $card->is_encoding_required;
  ```

  ```csharp C# theme={null}
  var accessMethods = seam.AccessMethods.List(
    accessGrantId: accessGrant.AccessGrantId
  );

  var card = accessMethods[0];
  Console.WriteLine(card.IsEncodingRequired);
  ```

  ```java Java theme={null}
  var accessMethods = seam.accessMethods().list(
    AccessMethodsListRequest.builder()
      .accessGrantId(accessGrant.getAccessGrantId())
      .build()
  );
  ```

  ```bash cURL theme={null}
  curl -X 'POST' \
    'https://connect.getseam.com/access_methods/list' \
    -H "Authorization: Bearer ${SEAM_API_KEY}" \
    -H 'Content-Type: application/json' \
    -d '{
    "access_grant_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
  }'
  ```
</CodeGroup>

**Output:**

```json theme={null}
{
  "access_method_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "display_name": "Key Card",
  "mode": "card",
  "is_issued": false,
  "is_encoding_required": true,
  ...
}
```

***

### Encoding Cards

If `is_encoding_required` is `true`, you must encode the credential onto a physical card using a card encoder before handing the card to your user.

Use the Seam API to encode the card:

<CodeGroup>
  ```javascript JavaScript theme={null}
  const actionAttempt = await seam.accessMethods.encode({
    access_method_id: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
    acs_encoder_id: 'encoder-001',
  })
  ```

  ```python Python theme={null}
  action_attempt = seam.access_methods.encode(
      access_method_id="a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      acs_encoder_id="encoder-001",
  )
  ```

  ```ruby Ruby theme={null}
  action_attempt = seam.access_methods.encode(
    access_method_id: "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    acs_encoder_id: "encoder-001"
  )
  ```

  ```php PHP theme={null}
  $actionAttempt = $seam->access_methods->encode(
    access_method_id: "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    acs_encoder_id: "encoder-001"
  );
  ```

  ```csharp C# theme={null}
  var actionAttempt = seam.AccessMethods.Encode(
    accessMethodId: "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    acsEncoderId: "encoder-001"
  );
  ```

  ```java Java theme={null}
  var actionAttempt = seam.accessMethods().encode(
    AccessMethodsEncodeRequest.builder()
      .accessMethodId("a1b2c3d4-e5f6-7890-abcd-ef1234567890")
      .acsEncoderId("encoder-001")
      .build()
  );
  ```

  ```bash cURL theme={null}
  curl -X 'POST' \
    'https://connect.getseam.com/access_methods/encode' \
    -H "Authorization: Bearer ${SEAM_API_KEY}" \
    -H 'Content-Type: application/json' \
    -d '{
    "access_method_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "acs_encoder_id": "encoder-001"
  }'
  ```
</CodeGroup>

Once encoding is complete, the access method's `is_encoding_required` property changes to `false` and `is_issued` changes to `true`. Hand the encoded card to your user.

For the complete card encoding workflow, including listing encoders and scanning cards, see [Working with Card Encoders and Scanners](/low-level-apis/access-systems/working-with-card-encoders-and-scanners/index).

***

### Assigning Cards

If `is_assigning_required` is `true`, you can assign an existing credential to the access method by providing the card number. This is common with systems that use pre-registered cards.

Use the Seam API to input the `card_number` for the access method:

<CodeGroup>
  ```javascript JavaScript theme={null}
  const actionAttempt = await seam.accessMethods.assignCard({
    access_method_id: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
    card_number: 'ABCD1234',
  })
  ```

  ```python Python theme={null}
  action_attempt = seam.access_methods.assign_card(
      access_method_id="a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      card_number="ABCD1234",
  )
  ```

  ```ruby Ruby theme={null}
  action_attempt = seam.access_methods.assign_card(
    access_method_id: "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    card_number: "ABCD1234"
  )
  ```

  ```php PHP theme={null}
  $actionAttempt = $seam->access_methods->assign_card(
    access_method_id: "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    card_number: "ABCD1234"
  );
  ```

  ```csharp C# theme={null}
  var actionAttempt = seam.AccessMethods.AssignCard(
    accessMethodId: "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    cardNumber: "ABCD1234"
  );
  ```

  ```java Java theme={null}
  var actionAttempt = seam.accessMethods().assignCard(
    AccessMethodsAssignCardRequest.builder()
      .accessMethodId("a1b2c3d4-e5f6-7890-abcd-ef1234567890")
      .cardNumber("ABCD1234")
      .build()
  );
  ```

  ```bash cURL theme={null}
  curl -X 'POST' \
    'https://connect.getseam.com/access_methods/assign_card' \
    -H "Authorization: Bearer ${SEAM_API_KEY}" \
    -H 'Content-Type: application/json' \
    -d '{
    "access_method_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "card_number": "ABCD1234"
  }'
  ```
</CodeGroup>

Once a card is assigned, the access method's `is_assignment_required` property changes to `false` and `is_issued` changes to `true`. Hand the assigned card to your user.

***

## Step 4: See Which Doors the Key Card Covers

An access method can cover multiple doors — for example, if the Access Grant includes several entrances or spaces. To see which doors a key card unlocks, call `/access_methods/get_related`.

<CodeGroup>
  ```javascript JavaScript theme={null}
  const related = await seam.accessMethods.getRelated({
    access_method_ids: [accessMethod.access_method_id],
  })

  console.log(related.acs_entrances) // entrances this card unlocks
  ```

  ```python Python theme={null}
  related = seam.access_methods.get_related(
      access_method_ids=[access_method.access_method_id]
  )

  print(related.acs_entrances)  # entrances this card unlocks
  ```

  ```ruby Ruby theme={null}
  related = seam.access_methods.get_related(
    access_method_ids: [access_method.access_method_id]
  )

  puts related.acs_entrances  # entrances this card unlocks
  ```

  ```php PHP theme={null}
  $related = $seam->access_methods->get_related(
    access_method_ids: [$accessMethod->access_method_id]
  );

  echo json_encode($related->acs_entrances);  // entrances this card unlocks
  ```

  ```csharp C# theme={null}
  var related = seam.AccessMethods.GetRelated(
    accessMethodIds: new List<string> { accessMethod.AccessMethodId }
  );

  // related.AcsEntrances — entrances this card unlocks
  ```

  ```java Java theme={null}
  var related = seam.accessMethods().getRelated(
    AccessMethodsGetRelatedRequest.builder()
      .accessMethodIds(List.of(accessMethod.getAccessMethodId()))
      .build()
  );
  ```

  ```bash cURL theme={null}
  curl -X 'POST' \
    'https://connect.getseam.com/access_methods/get_related' \
    -H "Authorization: Bearer ${SEAM_API_KEY}" \
    -H 'Content-Type: application/json' \
    -d '{
    "access_method_ids": ["f47ac10b-58cc-4372-a567-0e02b2c3d479"]
  }'
  ```
</CodeGroup>

***

## Next Steps

* [Working with Card Encoders and Scanners](/low-level-apis/access-systems/working-with-card-encoders-and-scanners/index) — Complete guide to encoding and scanning cards.
* [Creating an Access Grant](/use-cases/granting-access/creating-an-access-grant) — Learn more about specifying devices, entrances, and spaces.
* [Access Methods API Reference](/api/access_methods/object) — See all access method properties and endpoints.
