This tool queries the TTP CBP system for Global Entry interview appointments within a specified date range, filters them by state, and then exports the data in CSV by default or posts summaries to Slack if enabled in .jeff. It can run once or repeatedly at a defined interval, preserving the full JSON data of each location if desired.
- Parallel fetching for multiple dates
- Configurable states, date range, concurrency, retry logic via
.jeff - Rate-limiting to avoid API overload
- CSV export (default) with:
- Search date
- Location data (ID, name, phone, etc.)
- Full raw JSON of the returned object
- Slack integration (set
enable_slack = truein.jeff) - One-shot or continuous operation based on
fetch_interval_minutes(looping vs. single run)
- Docker and Docker Compose
- Optional Slack credentials if you want Slack output
- A
.jeffconfig file at the project root
Create a .jeff file in your project root. Example:
{
"enable_slack": false,
"slack_token": "xoxb-...",
"slack_channel_id": "C01234567",
"fetch_interval_minutes": 0,
"search_states": [
"AL","AK","AZ","AR","CA","CO","CT","DE","FL","GA",
"HI","ID","IL","IN","IA","KS","KY","LA","ME","MD",
"MA","MI","MN","MS","MO","MT","NE","NV","NH","NJ",
"NM","NY","NC","ND","OH","OK","OR","PA","RI","SC",
"SD","TN","TX","UT","VT","VA","WA","WV","WI","WY"
],
"date_range": {
"start": "2025-01-01",
"end": "2025-02-23"
},
"api_rate_limit_seconds": 1.0,
"max_concurrent_fetches": 5,
"max_retries": 3
}enable_slacktrue→ Post to Slackfalse→ Writeappointments.csv
fetch_interval_minutes0→ Run once and exit> 0→ Repeatedly fetch every N minutes
search_states: 2-letter codes for states to filterdate_range: Start/end inYYYY-MM-DDapi_rate_limit_seconds: Delay between requestsmax_concurrent_fetchesandmax_retries
- Build & Run
make build make run
- Logs
make logs
- Stop
make stop
When enable_slack = false, a CSV file (appointments.csv) is generated, showing Date, ID, Name, State, City, Address, PostalCode, Phone, RawJSON. This captures all details returned by the TTP API.
With enable_slack = true, it will post a Slack message summarizing the first few locations, rather than exporting CSV.
- Multi-stage build for smaller final images
- Mounts
.jeffread-only so local changes appear in-container - Restart unless stopped to keep going if
fetch_interval_minutes > 0
flowchart TB
A[Start Application] --> B[Load .jeff Config]
B --> C[Initialize Reqwest Client and Slack Token]
C --> D[Check fetch_interval_minutes]
D -- "0" --> E[Run Once, Fetch Appointments]
D -- "Non-Zero" --> F[Loop Forever]
E --> G[Fetch for Each Date in Range]
F --> G
G --> H[Filter by States]
H --> I[Convert to CSV Rows / Slack Data]
I --> J{enable_slack?}
J -- "No" --> K[Write to CSV (includes raw JSON)]
J -- "Yes" --> L[Post Slack Summary]
K --> M[End or Sleep]
L --> M[End or Sleep]
M -- "Loop" --> N[Wait fetch_interval_minutes]
N --> G
M -- "Once" --> O[Stop]
- A→B→C→D: Reads config, sets up HTTP/Slack.
- E/F: Single run vs loop.
- G→H: Fetch & filter.
- H→I: Prepare CSV or Slack.
- J → Slack or CSV.
- M → End or sleep for next cycle.