Skip to main content

AccessGrid SDK

A Python SDK for interacting with the AccessGrid.com API. This SDK provides a simple interface for managing NFC key cards and enterprise templates. Full docs at https://www.accessgrid.com/docs

Installation

pip install accessgrid

Quick Start

from accessgrid import AccessGrid

account_id = os.environ.get('ACCOUNT_ID')
secret_key = os.environ.get('SECRET_KEY')

client = AccessGrid(account_id, secret_key)

API Reference

Access Cards

Provision a new card

card = client.access_cards.provision(
    card_template_id="0xd3adb00b5",
    employee_id="123456789",
    card_number="123456",
    site_code="100",
    full_name="Employee name",
    email="employee@yourwebsite.com",
    phone_number="+19547212241",
    classification="full_time",
    department="Engineering",
    location="San Francisco",
    site_name="HQ Building A",
    workstation="4F-207",
    mail_stop="MS-401",
    company_address="123 Main St, San Francisco, CA 94105",
    start_date="2025-01-31T22:46:25.601Z",
    expiration_date="2025-04-30T22:46:25.601Z",
    employee_photo="[image_in_base64_encoded_format]",
    title="Engineering Manager",
    metadata={
        "department": "engineering",
        "badge_type": "contractor"
    }
)

Update a card

card = client.access_cards.update(
    card_id="0xc4rd1d",
    employee_id="987654321",
    full_name="Updated Employee Name",
    classification="contractor",
    department="Marketing",
    location="New York",
    site_name="NYC Office",
    workstation="2F-105",
    mail_stop="MS-200",
    company_address="456 Broadway, New York, NY 10013",
    expiration_date="2025-02-22T21:04:03.664Z",
    employee_photo="[image_in_base64_encoded_format]",
    title="Senior Developer"
)

List NFC keys / Access passes

# List all cards for a template
cards = client.access_cards.list(template_id="0xd3adb00b5")
for card in cards:
    print(card)  # Outputs: AccessCard(name='Employee Name', id='0xc4rd1d', state='active')

# Filter cards by state
active_cards = client.access_cards.list(template_id="0xd3adb00b5", state="active")

Manage card states

# Suspend a card
client.access_cards.suspend(card_id="0xc4rd1d")

# Resume a card
client.access_cards.resume(card_id="0xc4rd1d")

# Unlink a card
client.access_cards.unlink(card_id="0xc4rd1d")

# Delete a card
client.access_cards.delete(card_id="0xc4rd1d")

Enterprise Console

Create a template

template = client.console.create_template(
    name="Employee Access Pass",
    platform="apple",
    use_case="corporate_id",
    protocol="desfire",
    allow_on_multiple_devices=True,
    watch_count=2,
    iphone_count=3,
    background_color="#FFFFFF",
    label_color="#000000",
    label_secondary_color="#333333",
    support_url="https://help.yourcompany.com",
    support_phone_number="+1-555-123-4567",
    support_email="support@yourcompany.com",
    privacy_policy_url="https://yourcompany.com/privacy",
    terms_and_conditions_url="https://yourcompany.com/terms",
    metadata={
        "version": "2.1",
        "approval_status": "approved"
    }
)

Update a template

template = client.console.update_template(
    card_template_id="0xd3adb00b5",
    name="Updated Employee NFC key",
    allow_on_multiple_devices=True,
    watch_count=2,
    iphone_count=3,
    support_url="https://help.yourcompany.com",
    support_phone_number="+1-555-123-4567",
    support_email="support@yourcompany.com",
    privacy_policy_url="https://yourcompany.com/privacy",
    terms_and_conditions_url="https://yourcompany.com/terms"
)

Read a template

template = client.console.read_template(card_template_id="0xd3adb00b5")

Delete a template

client.console.delete_template("0xd3adb00b5")

Publish a template

result = client.console.publish_template(card_template_id="0xd3adb00b5")

print(f"Template {result.id} status: {result.status}")
# status is one of: "publishing" (already in flight), "in-review" (Apple
# queued), or "ready" (Android immediate)

Reveal a SmartTap private key

Fetches the template's SmartTap private key, decrypted client-side. The SDK generates a fresh ephemeral P-256 keypair per call, submits the public half, and decrypts the server's response — you get the plaintext PEM back without touching any crypto.

reveal = client.console.reveal_smart_tap(card_template_id="0xd3adb00b5")

print(f"Key version:  {reveal.key_version}")
print(f"Collector ID: {reveal.collector_id}")
print(f"Fingerprint:  {reveal.fingerprint}")
print(reveal.private_key)  # PEM — store in your reader/collector key vault

The server enforces single-use on pubkey fingerprint and rate-limits to 1 per minute per account. The SDK uses a fresh keypair every call, so single-use is satisfied automatically.

Get event logs

from datetime import datetime, timedelta

events = client.console.event_log(
    card_template_id="0xd3adb00b5",
    filters={
        "device": "mobile",  # "mobile" or "watch"
        "start_date": (datetime.now() - timedelta(days=30)).isoformat(),
        "end_date": datetime.now().isoformat(),
        "event_type": "install"
    }
)

iOS In-App Provisioning Preflight

response = client.console.ios_preflight(
    card_template_id="0xt3mp14t3-3x1d",
    access_pass_ex_id="0xp455-3x1d"
)

print(f"Provisioning Credential ID: {response.provisioningCredentialIdentifier}")
print(f"Sharing Instance ID: {response.sharingInstanceIdentifier}")
print(f"Card Template ID: {response.cardTemplateIdentifier}")
print(f"Environment ID: {response.environmentIdentifier}")

List ledger items

from datetime import datetime, timezone, timedelta

start_date = (datetime.now(timezone.utc) - timedelta(days=30)).isoformat()
end_date = datetime.now(timezone.utc).isoformat()

result = client.console.ledger_items(
    page=1,
    per_page=50,
    start_date=start_date,
    end_date=end_date
)

for item in result['ledger_items']:
    print(f"Amount: {item['amount']}, Kind: {item['kind']}, Date: {item['created_at']}")
    if item.get('access_pass'):
        print(f"  Access Pass: {item['access_pass']['ex_id']}")
        if item['access_pass'].get('pass_template'):
            print(f"  Card Template: {item['access_pass']['pass_template']['ex_id']}")

Card Template Pairs

Create a card template pair

Both templates must be published (status: ready) and unpaired. Valid protocol combinations are both SEOS, or Apple DESFire with Google Smart Tap.

pair = client.console.create_pass_template_pair(
    name="Employee Badge Pair",
    apple_card_template_id="0xapplet3mp14t3",
    google_card_template_id="0xgoogl3t3mp14t3"
)

print(f"Created pair: {pair.name} (ID: {pair.id})")

List card template pairs

result = client.console.list_pass_template_pairs(page=1, per_page=50)

for pair in result['card_template_pairs']:
    print(f"{pair.name} (ID: {pair.id})")
    if pair.ios_template:
        print(f"  iOS: {pair.ios_template.id}")
    if pair.android_template:
        print(f"  Android: {pair.android_template.id}")

Landing Pages

List landing pages

landing_pages = client.console.list_landing_pages()

for page in landing_pages:
    print(f"ID: {page.id}, Name: {page.name}, Kind: {page.kind}")
    print(f"  Password Protected: {page.password_protected}")
    if page.logo_url:
        print(f"  Logo URL: {page.logo_url}")

Create a landing page

landing_page = client.console.create_landing_page(
    name="Miami Office Access Pass",
    kind="universal",
    additional_text="Welcome to the Miami Office",
    bg_color="#f1f5f9",
    allow_immediate_download=True
)

print(f"Landing page created: {landing_page.id}")
print(f"Name: {landing_page.name}, Kind: {landing_page.kind}")

Update a landing page

landing_page = client.console.update_landing_page(
    landing_page_id="0xlandingpage1d",
    name="Updated Miami Office Access Pass",
    additional_text="Welcome! Tap below to get your access pass.",
    bg_color="#e2e8f0"
)

print(f"Landing page updated: {landing_page.id}")
print(f"Name: {landing_page.name}")

Credential Profiles

List credential profiles

profiles = client.console.credential_profiles.list()

for profile in profiles:
    print(f"ID: {profile.id}, Name: {profile.name}, AID: {profile.aid}")

Create a credential profile

profile = client.console.credential_profiles.create(
    name='Main Office Profile',
    app_name='KEY-ID-main',
    keys=[
        {'value': 'your_32_char_hex_master_key_here'},
        {'value': 'your_32_char_hex__read_key__here'}
    ]
)

print(f"Profile created: {profile.id}")
print(f"AID: {profile.aid}")

Delete a credential profile

client.console.credential_profiles.delete('cp-1')

Webhooks

Create a webhook

webhook = client.console.webhooks.create(
    name='Production',
    url='https://example.com/webhooks',
    subscribed_events=['ag.access_pass.issued']
)

print(f"Webhook created: {webhook.id}")
print(f"Private key: {webhook.private_key}")

List webhooks

webhooks = client.console.webhooks.list()

for webhook in webhooks:
    print(f"ID: {webhook.id}, Name: {webhook.name}")

Delete a webhook

client.console.webhooks.delete('abc123')

Verify a webhook

result = client.console.webhooks.verify('abc123')

print(f"Webhook {result.id} verified: {result.verified}")
# verified is True when already verified, or False when a verification
# handshake has just been initiated

HID Organizations

Create a HID organization

org = client.console.hid.orgs.create(
    name='My Organization',
    full_address='1 Main St, NY NY',
    phone='+1-555-0000',
    first_name='Ada',
    last_name='Lovelace'
)

print(f"Created org: {org.name} (ID: {org.id})")
print(f"Slug: {org.slug}")

Complete HID org registration

After creating an organization, complete the registration with credentials from your HID email:

result = client.console.hid.orgs.activate(
    email='admin@example.com',
    password='hid-password-123'
)

print(f"Completed registration for org: {result.name}")
print(f"Status: {result.status}")

List all HID organizations

orgs = client.console.hid.orgs.list()

for org in orgs:
    print(f"Org ID: {org.id}, Name: {org.name}, Slug: {org.slug}")

Configuration

The SDK can be configured with custom options:

client = AccessGrid(
    account_id,
    secret_key
)

Error Handling

The SDK throws errors for various scenarios including:

  • Missing required credentials
  • API request failures
  • Invalid parameters
  • Server errors

Example error handling:

try:
    card = client.access_cards.provision(
        # ... parameters
    )
except AccessGridError as error:
    print(f'Failed to provision card: {str(error)}')

Requirements

  • Python 3.7 or higher
  • Required packages:
    • requests
    • cryptography
    • python-dateutil

Security

The SDK automatically handles:

  • Request signing using HMAC-SHA256
  • Secure payload encoding
  • Authentication headers
  • HTTPS communication

Never expose your secret_key in source code. Always use environment variables or a secure configuration management system.

License

MIT License - See LICENSE file for details.

Feature Matrix

Endpoint Method Supported
POST /v1/key-cards access_cards.issue() Y
GET /v1/key-cards/{id} access_cards.get() Y
PATCH /v1/key-cards/{id} access_cards.update() Y
GET /v1/key-cards access_cards.list() Y
POST /v1/key-cards/{id}/suspend access_cards.suspend() Y
POST /v1/key-cards/{id}/resume access_cards.resume() Y
POST /v1/key-cards/{id}/unlink access_cards.unlink() Y
POST /v1/key-cards/{id}/delete access_cards.delete() Y
POST /v1/console/card-templates console.create_template() Y
PUT /v1/console/card-templates/{id} console.update_template() Y
GET /v1/console/card-templates/{id} console.read_template() Y
DELETE /v1/console/card-templates/{id} console.delete_template() Y
POST /v1/console/card-templates/{id}/publish console.publish_template() Y
POST /v1/console/card-templates/{id}/smart-tap/reveal console.reveal_smart_tap() Y
GET /v1/console/card-templates/{id}/logs console.get_logs() / console.event_log() Y
GET /v1/console/card-template-pairs console.list_pass_template_pairs() Y
POST /v1/console/card-template-pairs console.create_pass_template_pair() Y
POST /v1/console/card-templates/{id}/ios_preflight console.ios_preflight() Y
GET /v1/console/ledger-items console.ledger_items() Y
GET /v1/console/landing-pages console.list_landing_pages() Y
POST /v1/console/landing-pages console.create_landing_page() Y
PUT /v1/console/landing-pages/{id} console.update_landing_page() Y
GET /v1/console/credential-profiles console.credential_profiles.list() Y
POST /v1/console/credential-profiles console.credential_profiles.create() Y
DELETE /v1/console/credential-profiles/{id} console.credential_profiles.delete() Y
GET /v1/console/webhooks console.webhooks.list() Y
POST /v1/console/webhooks console.webhooks.create() Y
DELETE /v1/console/webhooks/{id} console.webhooks.delete() Y
POST /v1/console/webhooks/{id}/verify console.webhooks.verify() Y
POST /v1/console/hid/orgs console.hid.orgs.create() Y
POST /v1/console/hid/orgs/activate console.hid.orgs.activate() Y
GET /v1/console/hid/orgs console.hid.orgs.list() Y

Metadata

Release files for accessgrid 0.6.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for accessgrid 0.6.0
File Size Uploaded Provenance
accessgrid-0.6.0.tar.gz 28.8 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for accessgrid 0.6.0
File Interpreter ABI Platform
accessgrid-0.6.0-py3-none-any.whl Python 3 none any Details

Total release size: 55.0 kB

Release files / accessgrid-0.6.0.tar.gz

Download URL accessgrid-0.6.0.tar.gz
Size 28.8 kB
Tags Source
SHA-256 checksum
How to use checksums
c0ffa02d39247b6e1efc4110ff75ca0f060d2ee4db98d49379c44bd5f85c2fd8
BLAKE2b-256 checksum
How to use checksums
987cf3892c7fa2a63a8c50f6101e85c1b334c6367492a2b06b3c4789f0599f6f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.13

Release files / accessgrid-0.6.0-py3-none-any.whl

Download URL accessgrid-0.6.0-py3-none-any.whl
Size 26.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a2c58432d9f2ad37efe0bdc1e1bee8ae5a507d125aeb180d90a008aa81c0b580
BLAKE2b-256 checksum
How to use checksums
0a5a97e08e72a826d8401cabd2a661453c7c7435403a858cbc539a78a1f213d1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.13

Security for accessgrid 0.6.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page