">
← Guides / NFC Readers
May 16, 2025

How to make an ACS Walletmate open a URL on a smart phone

NFC Readers
Auston Bunsen
Overview
In this guide, we’ll show you how to configure your ACS Wallet Mate 2 reader to emulate an NFC tag that opens a URL automatically when tapped by a smartphone. We'll cover driver installation, connecting to your reader, enabling NFC emulation mode, sending URLs via NDEF, and how to integrate this seamlessly with the AccessGrid platform.

Prerequisites

  • ACS Wallet Mate 2 Reader
  • Python installed (Python 3.x recommended)
  • Basic familiarity with command-line interfaces
Setting up Your ACS Wallet Mate 2 Drivers
Before using your reader, you'll need appropriate drivers:

Windows & macOS:

  • Download drivers from ACS Drivers Page.
  • Follow on-screen instructions to install the drivers.

Linux:

  • Most Linux distributions support the ACS Wallet Mate by default.
  • Ensure PC/SC services are running:
sudo apt-get install libpcsclite1 pcscd pcsc-tools sudo service pcscd restart

Connecting to Your Reader
Install pyscard, the Python smart card library:

pip install pyscard

Create a Python file named walletmate.py and add the following minimal class:

from smartcard.scard import ( SCardTransmit, SCardEstablishContext, SCardListReaders, SCardConnect, SCARD_SCOPE_USER, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T1, SCARD_PCI_T1 ) class ACSWalletMate: def __init__(self, reader_index=0): _, self.context = SCardEstablishContext(SCARD_SCOPE_USER) _, readers = SCardListReaders(self.context, []) if len(readers) == 0: raise Exception("No readers found") self.reader = readers[reader_index] _, self.card, self.protocol = SCardConnect( self.context, self.reader, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T1 ) print(f"Connected to {self.reader}") if __name__ == "__main__": reader = ACSWalletMate(1)

Run it:

python walletmate.py

You should see a message indicating your reader is successfully connected, e.g., `Connected to ACS WalletMate Reader` - something like this:

WalletMate connected via python
WalletMate connected via python


Entering Emulation Mode
Update your `walletmate.py` by adding methods to enter emulation mode:

def send_apdu(self, command): _, response = SCardTransmit(self.card, SCARD_PCI_T1, command) return ''.join(f'{x:02x}' for x in response) def enter_emulation_mode(self): res = self.send_apdu([0xE0, 0x00, 0x00, 0x40, 0x03, 0x02, 0x00, 0x00]) if res != "e100000003020000": raise Exception("Failed emulation mode") print("Emulation mode activated. Reader LED off.") if __name__ == "__main__": reader = ACSWalletMate() reader.enter_emulation_mode()

Please note: Reader index 1 is used because we know it's the slot that can accept the card emulation commands. Slots could be secure elements, or PN532 chips. We went through trial and error so you don't have to, but it may be different on a different operating system.

Now, unplug and replug your WalletMate - it should beep and have a blue LED.

When you run the script again, your reader should enter emulation mode, and its LED should turn off. You can test it by tapping a phone on the Wallet Mate and it prompting you to open "acs.com.hk" which is the default URL for card emulation mode.

WalletMate default URL open
WalletMate default URL open
Sending a URL via NDEF
Extend your existing class with URL-writing capabilities:

def generate_write_apdu_for_url(self, url): prefix_code, stripped_url = 0x04, url.replace("https://", "") uri_payload = [prefix_code] + list(map(ord, stripped_url)) ndef_record = [0xD1, 0x01, len(uri_payload), 0x55] + uri_payload tlv = [0x03, len(ndef_record)] + ndef_record + [0xFE] memory = [0xE1, 0x10, 0xF4, 0x00] + tlv memory += [0x00] * (4 - len(memory) % 4) total_len = len(memory) return [0xE0, 0x00, 0x00, 0x60, 4 + total_len, 0x01, 0x02, 0x00, total_len] + memory def write_ndef_url(self, url): apdu = self.generate_write_apdu_for_url(url) self.send_apdu(apdu) print(f"URL '{url}' written to reader.") if __name__ == "__main__": reader = ACSWalletMate(reader_index=1) reader.enter_emulation_mode() reader.write_ndef_url("https://example.com")

Running this script will enable your smartphone to open the specified URL when tapped on the reader.

Integrating with AccessGrid NFC Keys
So we've done the basics, but when would we need this? Let's say you're doing a check-in for a hotel and you want to get the guest their mobile hotel key - how would you do it? You could use our Twilio integration and send it via text message, but then you have to collect the guests phone number and store it safely. You could do it via email, but then the same problem exists. Why not "give" it to them in person - using this exact method.

Here's how to integrate an NFC credential into your ACS Wallet Mate. We'll start by installing the AccessGrid python package:

pip install accessgrid

Provision your NFC credential using AccessGrid by updating your `walletmate.py` file - this is what it should look like now:

from accessgrid import AccessGrid from smartcard.scard import ( SCardTransmit, SCardEstablishContext, SCardListReaders, SCardConnect, SCARD_SCOPE_USER, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T1, SCARD_PCI_T1 ) class ACSWalletMate: def __init__(self, reader_index=0): _, self.context = SCardEstablishContext(SCARD_SCOPE_USER) _, readers = SCardListReaders(self.context, []) if len(readers) == 0: raise Exception("No readers found") self.reader = readers[reader_index] _, self.card, self.protocol = SCardConnect( self.context, self.reader, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T1 ) print(f"Connected to {self.reader}") def send_apdu(self, command): _, response = SCardTransmit(self.card, SCARD_PCI_T1, command) return ''.join(f'{x:02x}' for x in response) def enter_emulation_mode(self): res = self.send_apdu([0xE0, 0x00, 0x00, 0x40, 0x03, 0x02, 0x00, 0x00]) if res != "e100000003020000": raise Exception("Failed emulation mode") print("Emulation mode activated. Reader LED off.") def generate_write_apdu_for_url(self, url): prefix_code, stripped_url = 0x04, url.replace("https://", "") uri_payload = [prefix_code] + list(map(ord, stripped_url)) ndef_record = [0xD1, 0x01, len(uri_payload), 0x55] + uri_payload tlv = [0x03, len(ndef_record)] + ndef_record + [0xFE] memory = [0xE1, 0x10, 0xF4, 0x00] + tlv memory += [0x00] * (4 - len(memory) % 4) total_len = len(memory) return [0xE0, 0x00, 0x00, 0x60, 4 + total_len, 0x01, 0x02, 0x00, total_len] + memory def write_ndef_url(self, url): apdu = self.generate_write_apdu_for_url(url) self.send_apdu(apdu) print(f"URL '{url}' written to reader.") client = AccessGrid("account_id", "secret_key") card = client.access_cards.provision( card_template_id="template_id", employee_id="12345", card_number="67890", site_code="01", full_name="Alice Smith", email="[email protected]", phone_number="+1234567890", classification="Employee", title="Engineer", start_date="2025-01-01T00:00:00Z", expiration_date="2026-01-01T00:00:00Z" ) # Now integrate with your Wallet Mate reader: if __name__ == "__main__": reader = ACSWalletMate(reader_index=1) reader.enter_emulation_mode() reader.write_ndef_url(card.url) print("Tap your smartphone on the reader to open the URL securely provisioned by AccessGrid.")

With this integration, your ACS Wallet Mate seamlessly uses credentials generated by AccessGrid, enhancing security and management simplicity.

Conclusion
In this guide, we showed how to turn the ACS Wallet Mate 2 into an NFC tag that opens a URL on any smartphone. From driver setup to dynamic APDU generation, we walked through each step to help you get a working, testable implementation. By integrating with AccessGrid, you gain a powerful way to issue mobile credentials securely and instantly. This setup is ideal for real-world use cases like hotel check-ins, event access, and more.

For feedback, improvements, or deeper exploration into modern credentialing, please reach out via Intercom in the bottom right. Let’s build the future of access control together!
© AccessGrid 2024
Privacy
Terms