Granting Access Using Encoded Plastic Key Cards

To issue a plastic key card, identify the user to whom you want to grant access and create a user identity to represent this user. Then, create an Access Grant to specify the entrances and spaces to which you want to grant the user access. The Access Grant creates a card access method. You use the Seam API to encode the access method onto a plastic key card. You can also use the Seam API to scan encoded cards.

This section details the steps in this process and provides accompanying Seam API code samples. See the following instructions:


Create a User Identity

Use the Seam API to create a user_identity. A user identity represents the hotel guest.

Code:

# Create a user identity for your user.
jane_user = seam.user_identities.create(
  full_name = "Jane Doe",
  phone_number = "+15555550100"
)

Output:

UserIdentity(
  user_identity_id='43947360-cdc8-4db6-8b22-e079416d1d8b',
  full_name='Jane Doe',
  phone_number='+15555550100',
  ...
)

Create an Access Grant

To create an Access Grant, specify the user identity, entrance or space IDs, and starting and ending times. Include card as a requested access method.

Code:

seam.access_grants.create(
  # You can specify the ID of an existing user identity or
  # use the user_identity parameter to create a new one.
  user_identity_id=jane_user.user_identity_id,
  # You can specify acs_entrance_ids, space_ids, or both.
  acs_entrance_ids=[
    "48ebfb50-c531-43c5-b9ea-409f26dabbd7",
    "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"
)

Output:

AccessGrant(
  access_grant_id="ef83cca9-5fdf-4ac2-93f3-c21c5a8be54b",
  display_name="My Access Grant",
  user_identity_id="43947360-cdc8-4db6-8b22-e079416d1d8b",
  starts_at="2025-07-13T15:00:00.000Z",
  ends_at="2025-07-16T11:00:00.000Z",
  requested_access_methods=[
    {
      "display_name": "Plastic Card",
      "mode": "card",
      "created_access_method_ids": ["c7d8e9f0-1a2b-3c4d-5e6f-7a8b9c0d1e2f"],
      ...
    }
  ],
  ...
)

Encode the Card

As a final step in creating a plastic key card, use the Seam API to encode the access method onto the plastic card. Your app can serve hotel front desk staff as well as self-serve check-in kiosks with built-in physical encoders.

Encode the access method onto a plastic key card.
Encode the access method onto a plastic key card.

First, list the available card encoders within the access system and identify the encoder that the person encoding the card should use. Then, initiate the encoding action. The Seam API returns an action attempt so that your app can track the status of the encoding. When the encoding completes successfully, the action attempt payload includes information about the encoded card, such as the card number and the date and time at which the card was issued (that is, encoded). If the encoding fails, the action attempt reports any encoding errors.

For more details about card encoding, see Creating and Encoding Card Access Methods.

Code:

# First, get the encoder that you want to use.
encoder = seam.acs.encoders.list(
  acs_system_ids = [hotel_a.acs_system_id]
)[0]

# Then, encode the card.
encoding_action_attempt = seam.access_methods.encode(
  access_method_id = "c7d8e9f0-1a2b-3c4d-5e6f-7a8b9c0d1e2f",
  acs_encoder_id = encoder.acs_encoder_id
)

# To confirm that the encoding succeeded, 
# poll the returned action attempt
# until its status is success.
seam.action_attempts.get(
  action_attempt_id = encoding_action_attempt.action_attempt_id
)

Output:

ActionAttempt(
  status='success',
  action_attempt_id='e49a33f7-9596-4b45-8e66-550b72fea134',
  action_type='ENCODE_ACCESS_METHOD',
  result={
    access_method_id='c7d8e9f0-1a2b-3c4d-5e6f-7a8b9c0d1e2f',
    card_number='1234abc',
    is_issued=True,
    issued_at='2025-07-13T14:00:00.000Z',
    ...
  },
  error=null
)

Scan the Card

You can scan the card to view its data and confirm that it's up to date with the server. The scan result includes the card's properties, such as its card number, serial number, and other useful details. If discrepancies are detected, Seam provides warnings to indicate that the card is out of date and needs re-encoding.

Use the Seam API to scan a plastic card to view its details.
Use the Seam API to scan a plastic card to view its details.

To scan a card, first initiate the scanning process. This scanning action returns an action attempt that you can poll to track the status. When the scan completes, view the card payload within the action attempt. Note any action_attempt.result.warnings. Warning messages show which properties are out of sync.

Pay special attention to the following parts of the returned payload:

  • action_attempt.result.warnings list any properties that Seam has detected are out-of-sync between the card and the encoder.

  • action_attempt.result.acs_credential_on_seam lists the properties of the access method as stored on the access system server.

  • action_attempt.result.acs_credential_on_encoder lists the properties of the access method as stored on the card.

For more details, see Scanning Encoded Cards.

Code:

# Retrieve a list of all available encoders in a hotel, 
# that is, connected to a single acs_system.
seam.acs.encoders.list(
  acs_system_ids = [hotel_a_system_id]
)

# Scan the card using the desired encoder.
scanning_action_attempt = seam.acs.encoders.scan_credential(
  acs_encoder_id = encoder.acs_encoder_id
)

Output:

ActionAttempt(
  status='success',
  action_attempt_id='0243f349-68bf-4323-9e61-4c40eb72eb1e',
  action_type='SCAN_CREDENTIAL',
  result={
    warnings=[
      {
        "warning_code": "acs_credential_on_encoder_out_of_sync",
        "warning_message": "The following properties are out of sync
                            between acs_credential_on_encoder and
                            acs_credential_on_seam: ends_at"
      }
    ],
    acs_credential_on_seam={
      "starts_at": "2025-07-13T15:00:00.000Z",
      "ends_at": "2025-07-16T11:00:00.000Z",  
      "card_number": "1234abc",
      "display_name": "Card 1234abc",
      "access_method": "card",
      ...      
    },
    acs_credential_on_encoder={
      "starts_at": "2025-07-13T15:00:00.000Z",
      "ends_at": "2025-07-15T11:00:00.000Z",
      "card_number": "1234abc",
      ...
    }
  },
  error=null
)

Last updated

Was this helpful?