Gorilla Glue #4
Swisher, Diamond
VooDoo Ranger Juicy Haze IPA

I recently needed TSA Pre-check within one week (which happened to be the week of Thanksgiving 2018). Long story short, I used Python's request module to check for a new appointment, the schedule module to do this job every 2 minutes, and then sent a notification to twitter each time a newer appointment was found. Sure enough, a same-day appointment popped up and notified me, so I was able to have my interview within two hours.

Why not create a bot?

This birthed the @EntryGlobal Bot on Twitter - a Bot that checks for available appointments in a given airport. After many twitter API violations, here is how I created the bot:

Note: this tutorial assumes you've already completed the Global Entry Application and ready to schedule an interview

Step 1: Identify the GET request

No thrills here – I use Chrome's network tab (in developer tools) to find the GET request with parameters that match my location. You must visit the scheduler page in order to find the correct GET request. Here is what I get for Atlanta Airport:

Take note of the Request URL that shows as a GET after each time a location is chosen. In my example, I've chosen Atlanta Airport, so a GET request was sent in URL form as https://ttp.cbp.dhs.gov/schedulerapi/slots?orderBy=soonest&limit=1&locationId=5182&minimum=1

notice the query on the schedulerapi with locationId of 5182 –  jot this down for later

Step 2: Prove to yourself that it's gonna work

I like to use iPython while writing code, so how 'bout you fire up an iPython session to make sure our endpoint returns data.

remember to install iPython if it's not already in your environment

In [1]: import requests

In [2]: res = requests.get('https://ttp.cbp.dhs.gov/schedulerapi/slots?orderBy=soonest&limit=1&locationId={}&minimum=1'.format(5181))

In [3]: res.text
Out[3]: u'[ {\n  "locationId" : 5181,\n  "startTimestamp" : "2019-01-31T09:45",\n  "endTimestamp" : "2019-01-31T10:00",\n  "active" : true,\n  "duration" : 15\n} ]'

We're now able to quickly get the next available startTimeStamp (aka appointment) for locationId 5182 without having to use the UI! Now what should we do?

  1. Schedule the check as a frequent task
  2. Establish a notification system with compliant API usage
  3. Deploy as an app

Step 3: Write Some Code!

Here's the fun part. I believe in separating classes/files into what makes sense in my mind.

Let's start by creating a Constants class to define all of our constant variables:

# main.py

class Constants:
    ATL_AIRPORT_ID = 5182
    LOCATION_ID = ATL_AIRPORT_ID
    SCHEDULER_API_ENDPOINT = 'https://ttp.cbp.dhs.gov/schedulerapi/slots?orderBy=soonest&limit=1&locationId={}&minimum=1'.format(
        LOCATION_ID)

Doesn't the ATL_AIRPORT_ID value look familiar? We're hardcoding Atlanta's location ID to use as a parameter later on.

The SCHEDULER_API_ENDPOINT should look familiar as well. It is the same URL that we discovered in step 1. Notice I pass LOCATION_ID here, which serves as my default as more locations are added.


Create Bot

Compare two dates, A and B, where date A is the current scheduled appointment time. Notify twitter when the next available time slot (date B) is sooner than date A.    

The Bot should do at least two things:

  1. Check global entry schedule
  2. Notify me when a newer appointment is available

Let's start by creating a method to check the next available date for interview:

# main.py
import json
import datetime
import requests


class GlobalEntryBot(object):

    def __init__(self):
        pass
    
    def check_global_entry_schedule(self):
        """
        check date for global entry interview
        :param interview_date: string format Y-m-d
        :return:
        """
        res = requests.get(Constants.SCHEDULER_API_ENDPOINT)
        next_available_date_time = json.loads(res.text)[0]['startTimestamp'].split("T")
        next_available_date = datetime.datetime.strptime(next_available_date_time[0], '%Y-%m-%d').date()

check_global_entry_schedule will execute the GET request

res = requests.get(Constants.SCHEDULER_API_ENDPOINT)

Parse out the date from startTimestamp and then convert it to a datetime object.

next_available_date = datetime.datetime.strptime(next_available_date_time[0], '%Y-%m-%d').date()

Now we have the next_available_date for a Global Entry Interview in ATL_AIRPORT_ID!

Take a look at Part 2 for some logic