Search and monitor traffic citations across 309 automated court portals in Texas and Georgia with a single request.
The same engine that powers globalticketpay.com β exposed for developers, fleets, and legal-tech integrations. π Search a driver across 291 Texas courts plus 18 live Georgia courts (Atlanta, Fulton, DeKalb, Savannah, Columbus, Athens, and more) in one call, get back normalized citation data (charge, fine, due date, court, status), and run warrant-style sweeps.
π Read the full documentation β globalticketpay.com/developers
π Get an API key: access is currently invite-only. Create an account at globalticketpay.com/developers and request access; once approved you can generate a key from your dashboard.
| π Base URL | https://www.globalticketpay.com/api/v1 |
| β Status | Live in production |
| π Auth | API key (bearer token) |
| π¦ Format | JSON, with a consistent response envelope |
| π OpenAPI spec | openapi.json (also served live at /api/v1/openapi.json) |
βΉοΈ This repository is the public documentation and example clients for the API. The product source lives in a private repository.
- πΊοΈ Coverage
- β‘ Quickstart
- π Authentication
- π Rate limits and quotas
- π¦ Response format
β οΈ Errors- π£οΈ Endpoints
- π» Code examples
- β Best practices
- π Versioning
The lookup engine automates the same court portals a driver would search by hand β it does not hold a private database. Coverage grows as new courts are wired in; the live, authoritative list is always /api/v1/jurisdictions.
| State | Courts | Highlights |
|---|---|---|
| Texas (TX) | 291 | Bexar County / San Antonio metro (deepest), Harris County / Houston, Tarrant, Travis / Austin, El Paso County, plus municipal & JP courts across the state. ~84% of major-metro TX population by tracked cities. |
| Georgia (GA) | 18 (expanding) | Live now: Atlanta Municipal, Fulton State Court traffic, DeKalb, Rockdale, Roswell, Dunwoody, Cumming, Locust Grove, Chatham/Savannah, Columbus, Athens-Clarke, Glynn/Brunswick, Spalding/Griffin, Rome, Douglas, Lyons, Hahira, and Bainbridge. Cobb, Gwinnett, Clayton, Augusta, and Macon-Bibb are on the rollout list. |
Because Georgia is new, the engine is honest about it: a request into a court that is not yet automated returns success: false with a clear message rather than a silent zero. Sweep "all" to hit every currently-supported court in both states, or scope to a state with /jurisdictions?state=GA.
Every data endpoint authenticates with an API key sent as a bearer token. Access is currently invite-only β create an account at globalticketpay.com/developers and request access; keys are enabled per approved account.
curl -X POST https://www.globalticketpay.com/api/v1/lookup \
-H "Authorization: Bearer gtp_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"jurisdictions": ["bexar", "shavano"],
"driver_license": "12345678",
"state": "TX"
}'A Georgia lookup is the same shape β just pass state: "GA" and Georgia jurisdiction ids (for example atlanta, fultongastatecourttraffic):
curl -X POST https://www.globalticketpay.com/api/v1/lookup \
-H "Authorization: Bearer gtp_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"jurisdictions": ["atlanta", "fultongastatecourttraffic"],
"driver_license": "060027360",
"state": "GA"
}'Pass your key in the Authorization header on every data request:
Authorization: Bearer gtp_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Notes:
- πͺͺ Keys are issued per account. Sign in to create, view, and revoke them.
- ποΈ Keys are shown in full only once at creation. Store them in a secrets manager.
- π― Keys carry scopes:
lookup,warrant, andjurisdictions. - π‘οΈ Keep keys server side. Never ship a key in client side or mobile app code.
Public, read-only endpoints (/, /status, /jurisdictions, /jurisdictions/{id}, /openapi.json) do not require a key.
Standard keys allow 60 requests per minute and 10,000 requests per month. Every authenticated response includes your current limits as headers:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 58
X-Quota-Limit: 10000
X-Quota-Remaining: 9871
Exceeding either limit returns HTTP 429 with a Retry-After header. Back off and retry after the indicated number of seconds.
Every response uses a consistent envelope with a request_id for tracing and support.
β Success:
{
"ok": true,
"request_id": "req_8f3c...",
"data": { },
"meta": { }
}β Error:
{
"ok": false,
"request_id": "req_8f3c...",
"error": {
"code": "validation_error",
"message": "Invalid request parameters.",
"details": { }
}
}Always branch on the machine readable error.code, not on the HTTP status text or the message wording.
| HTTP | error.code | Meaning |
|---|---|---|
| 400 | bad_request |
Malformed request, for example invalid JSON. |
| 401 | unauthorized |
Missing or invalid API key. |
| 403 | forbidden |
Key lacks the required scope, is revoked, or expired. |
| 404 | not_found |
Unknown route or jurisdiction id. |
| 405 | method_not_allowed |
Wrong HTTP method for the endpoint. |
| 422 | validation_error |
Body failed validation. See error.details.issues. |
| 429 | rate_limit_exceeded |
Per minute rate limit hit. Honor Retry-After. |
| 429 | monthly_quota_exceeded |
Monthly quota exhausted for the key. |
| 502 | upstream_unavailable |
Lookup engine unreachable. Retry with backoff. |
| 504 | upstream_timeout |
Lookup engine took too long. Retry or narrow jurisdictions. |
| 500 | internal_error |
Unexpected server error. Safe to retry once. |
| Method | Path | Auth | Purpose |
|---|---|---|---|
| GET | /api/v1 |
π’ public | Discovery root and endpoint index |
| GET | /api/v1/status |
π’ public | API and engine health |
| GET | /api/v1/jurisdictions |
π’ public | List supported courts, filterable |
| GET | /api/v1/jurisdictions/{id} |
π’ public | Single jurisdiction detail |
| POST | /api/v1/lookup |
π key (lookup) |
Search citations across jurisdictions |
| POST | /api/v1/warrant-check |
π key (warrant) |
Warrant style sweep |
| GET | /api/v1/usage |
π key | Caller key limits and consumption |
| GET | /api/v1/openapi.json |
π’ public | OpenAPI 3.1 spec |
Search open citations across one or more jurisdictions by driver license and state. Optional name and date of birth improve matching in courts that disambiguate by them. Pass "jurisdictions": "all" to sweep every supported court in one request. The engine bounds total latency with per court timeouts, so a full sweep usually returns in about 10 to 30 seconds.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
jurisdictions |
string[] or "all" |
yes | Jurisdiction ids to search, or "all". Each id must exist in /jurisdictions. |
driver_license |
string |
yes | 3 to 32 characters, letters, digits, and hyphens. |
state |
string |
yes | Two letter US state code β currently TX (291 courts) or GA (18 courts live; expanding). Must match the state of every jurisdiction id in jurisdictions. |
first_name |
string |
no | Improves matching where supported. |
last_name |
string |
no | Improves matching where supported. |
date_of_birth |
string |
no | Format YYYY-MM-DD. |
Response (trimmed):
{
"ok": true,
"request_id": "req_8f3c...",
"data": {
"query": {
"jurisdictions": ["bexar", "shavano"],
"state": "TX",
"driver_license_last4": "5678"
},
"summary": {
"total_tickets": 1,
"jurisdictions_searched": 2,
"jurisdictions_with_results": 1,
"success_count": 2,
"engine_latency_ms": 9800
},
"results": [
{
"jurisdiction_id": "bexar",
"jurisdiction_name": "Bexar County",
"searched": true,
"success": true,
"ticket_count": 1,
"tickets": [
{
"citation_number": "C123456",
"violation": "SPEEDING 10-15 OVER",
"fine_amount": 218.0,
"currency": "USD",
"due_date": "2026-07-01",
"status": "OPEN",
"defendant_name": "J. DOE",
"court_name": "Bexar County JP 1",
"source": "fetch-http"
}
]
}
]
}
}Ticket fields:
| Field | Type | Description |
|---|---|---|
citation_number |
string or null |
Court citation or case number. |
violation |
string or null |
Offense description as the court reports it. |
fine_amount |
number or null |
Amount due in USD. null when the court does not expose it. |
currency |
string |
Always USD. |
due_date |
string or null |
Due or appearance date as reported. |
status |
string or null |
Court status, for example OPEN, when available. |
defendant_name |
string or null |
Defendant name as reported by the court. |
court_name |
string or null |
Human readable court name. |
source |
string or null |
How the row was retrieved. |
A jurisdiction with success: true and an empty tickets array means searched, nothing found.
Warrant mode sweep tuned for outstanding matter detection. Same request body as /lookup. Adds two fields on top of the standard lookup payload:
| Field | Type | Description |
|---|---|---|
warrant_indicator |
boolean |
true if any searched jurisdiction returned a matching record. |
jurisdictions_with_matches |
string[] |
Ids of jurisdictions that returned records. |
A returned record indicates a citation or matter on file, not a confirmed warrant. Treat results as leads to verify with the court.
List supported court portals. Public. Filters: region, state, search. Pagination: limit (1 to 500, default 100) and offset.
curl "https://www.globalticketpay.com/api/v1/jurisdictions?region=Houston%20Metro&limit=2"Detail for a single jurisdiction. Returns 404 with code not_found for an unknown id.
Your key tier, scopes, limits, and current consumption.
API and lookup engine health plus the live jurisdiction count (court portals wired across all supported states β currently TX + GA).
See the examples directory for runnable clients.
π¨ JavaScript (Node 18 or newer, or the browser server side only):
const res = await fetch("https://www.globalticketpay.com/api/v1/lookup", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.GTP_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
jurisdictions: "all",
driver_license: "12345678",
state: "TX", // or "GA" with Georgia jurisdiction ids (atlanta, fultongastatecourttraffic)
}),
});
const body = await res.json();
if (!body.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
console.log(body.data.summary.total_tickets, "tickets");π Python (requests):
import os, requests
r = requests.post(
"https://www.globalticketpay.com/api/v1/lookup",
headers={"Authorization": f"Bearer {os.environ['GTP_API_KEY']}"},
json={"jurisdictions": ["bexar", "shavano"],
"driver_license": "12345678", "state": "TX"}, # swap for state="GA", jurisdictions=["atlanta", ...]
timeout=60,
)
data = r.json()
if not data["ok"]:
raise RuntimeError(data["error"]["code"])
print(data["data"]["summary"]["total_tickets"], "tickets")- π‘οΈ Keep keys server side. Treat a key like a password.
- β±οΈ Use a 60 second client timeout for
/lookupand/warrant-check. Live court scans are slower than typical REST calls. - π Retry transient errors with backoff. Retry 502, 504, and 500 once or twice. Never retry 422 without changing the request.
- π¦ Respect
Retry-Afteron 429. Watch theX-RateLimitandX-Quotaheaders to stay under limits. - π― Scope your sweeps. Prefer a targeted
jurisdictionslist over"all"when you know the county. It is faster and cheaper on your quota. - βοΈ Only query data you are authorized to access. You must have a permissible purpose under applicable law for each lookup.
The API is versioned in the path (/api/v1). New fields are added without bumping the version, so parse responses leniently and ignore unknown fields. Breaking changes ship under a new version with advance notice. Error code values are stable contracts. Build your logic on them.
What's new: Coverage expanded to 309 automated court portals β 291 Texas courts plus 18 live Georgia courts (Atlanta, Fulton, DeKalb, Chatham/Savannah, Columbus, Athens-Clarke, and more). More Georgia courts are rolling out; poll
/jurisdictions?state=GAto pick them up automatically. Jurisdiction ids are stable, so adding a court never breaks existing requests.
Questions, higher limits, or partnership interest: π globalticketpay.com/developers or βοΈ globalticketpay.com/contact.