Python API - JaiminBrahmbhatt/Global-Entry-Appointment-Scanner GitHub Wiki

Python API

Use global-entry-scanner as a library in your own Python scripts without the CLI.


Basic usage

from global_entry_scanner import Scanner
from global_entry_scanner.notifications import (
    ConsoleNotifier,
    DiscordNotifier,
    EmailNotifier,
    SlackNotifier,
    SMSNotifier,
)

scanner = Scanner(location_ids=[5001, 5140])        # Austin, Dallas
scanner.add_notifier(ConsoleNotifier())
scanner.add_notifier(DiscordNotifier(webhook_url="https://discord.com/api/webhooks/..."))
scanner.start()                                      # blocking; Ctrl+C to stop

Scanner

Scanner(
    location_ids: list[int],
    check_interval: int = 900,
    error_interval: int = 60,
    limit: int = 5,
)
Parameter Default Description
location_ids (required) List of enrollment center IDs to monitor
check_interval 900 Seconds between polls when healthy
error_interval 60 Seconds between polls after an error
limit 5 Max appointment slots to fetch per location

Methods

scanner.start()

Blocking poll loop. Validates all notifiers first, then loops forever. Ctrl+C to stop.

scanner.check_once() -> list[ScanResult]

Run a single scan pass across all configured locations. Returns immediately. Useful for scripts and cron jobs.

results = scanner.check_once()
for r in results:
    print(f"{r.city}: {len(r.new_appointments)} new slot(s)")
    if r.error:
        print(f"  Error: {r.error}")

scanner.add_notifier(notifier)

Register a notifier. Call multiple times to add multiple channels.

scanner.fetch_locations() -> dict[int, Location]

Fetch all enrollment centers. Cached for 15 days in-process.

scanner.fetch_appointments(location_id: int) -> list[Appointment]

Fetch available slots for a single location. Returns [] on 404.


Notifiers

ConsoleNotifier

No arguments. Prints to stdout.

ConsoleNotifier()

EmailNotifier

EmailNotifier(from_email="[email protected]", to_email="[email protected]", password="app-password")

DiscordNotifier

DiscordNotifier(webhook_url="https://discord.com/api/webhooks/...")

SlackNotifier

SlackNotifier(webhook_url="https://hooks.slack.com/services/...")

SMSNotifier

SMSNotifier(
    account_sid="ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    auth_token="your_auth_token",
    to_number="+12125551234",
    from_number="+12125550000",
)

Writing a custom notifier

Any object with send(subject: str, message: str) -> None and validate() -> None qualifies. No base class or imports from this package needed:

class PushoverNotifier:
    def validate(self) -> None:
        pass  # optionally raise ValueError if credentials are missing

    def send(self, subject: str, message: str) -> None:
        import requests
        requests.post("https://api.pushover.net/1/messages.json", data={
            "token": "your_app_token",
            "user": "your_user_key",
            "title": subject,
            "message": message,
        })

scanner.add_notifier(PushoverNotifier())

Data models

Location

@dataclass(frozen=True)
class Location:
    id: int
    name: str
    city: str
    state: str
    timezone: str

Appointment

@dataclass(frozen=True)
class Appointment:
    location_id: int
    start: datetime
    end: datetime
    active: bool

ScanResult

@dataclass
class ScanResult:
    location_id: int
    city: str
    new_appointments: list[Appointment]
    error: str | None = None

One-shot check (no loop)

from global_entry_scanner import Scanner

scanner = Scanner(location_ids=[5001])
results = scanner.check_once()

for r in results:
    for appt in r.new_appointments:
        print(f"Slot at {r.city}: {appt.start}")