PlateAPI Python SDK
Python SDK for PlateAPI -- Australian vehicle registration plate lookup.
Install
pip install plateapi
Requires Python 3.8+.
Quick start
from plateapi import PlateAPI
client = PlateAPI("pk_live_your_api_key")
result = client.lookup("ABC123", "VIC")
if result.success:
print(result.vehicle.make)
print(result.vehicle.model)
print(result.vehicle.year)
Plate lookup
result = client.lookup("ABC123", "VIC")
print(result.success) # True if a vehicle was found
print(result.vehicle.make) # "TOYOTA"
print(result.vehicle.model) # "HILUX"
print(result.vehicle.year) # 2015
print(result.vehicle.year_range) # "2015 - 2023"
print(result.vehicle.lowest_year) # 2015
print(result.vehicle.highest_year) # 2023
print(result.vehicle.body) # "UTILITY"
print(result.vehicle.engine) # "2.8L"
print(result.vehicle.description) # "TOYOTA HILUX UTILITY 2.8L"
print(result.duration_ms) # 2451.3
print(result.source) # data source identifier
print(result.request_id) # "req_7f3a9c1b4e..." (include when contacting support)
Valid states: NSW, VIC, QLD, SA, WA, TAS, NT, ACT.
Detailed lookup
Pass detailed=True to get extended vehicle descriptions when available.
result = client.lookup("ABC123", "NSW", detailed=True)
if result.success:
print(result.vehicle.detailed_description)
print(result.vehicle.series)
Multiple matches
Some plates match more than one vehicle record. The best match is in result.vehicle, and any alternatives are in result.alternatives.
result = client.lookup("ABC123", "VIC")
if result.alternatives:
for alt in result.alternatives:
print(f" Also matched: {alt.make} {alt.model} ({alt.year_range})")
Vehicle database
Browse the full vehicle database (32,000+ vehicles, 213 makes). Each call narrows the cascade -- call with no arguments to get all makes, then pass make to get models, and so on through all 7 levels. Paid plans only, no quota consumed.
Returns a VehiclesResult with success, type (the cascade level), data (list of values), total, and duration_ms.
# Step 1: All makes
result = client.vehicles()
print(result.type) # "make"
print(result.data[:5]) # ["ABARTH", "AC", "ALFA ROMEO", ...]
print(result.total) # 213
# Step 2: Models for a make
result = client.vehicles(make="TOYOTA")
print(result.type) # "model"
print(result.data[:5]) # ["86", "ALPHARD", "AURION", ...]
# Step 3: Years for a make + model
result = client.vehicles(make="TOYOTA", model="HILUX")
print(result.type) # "year"
print(result.data[:5]) # [2025, 2024, 2023, ...]
# Step 4: Series for a make + model + year
result = client.vehicles(make="TOYOTA", model="HILUX", year=2020)
print(result.type) # "series"
print(result.data) # ["SR", "SR5", "Rogue", "Rugged", ...]
# Step 5: Engines for a make + model + year + series
result = client.vehicles(make="TOYOTA", model="HILUX", year=2020, series="SR5")
print(result.type) # "engine"
print(result.data) # ["2.8L", "2.4L", ...]
# Step 6: Variants for a make + model + year + series + engine
result = client.vehicles(make="TOYOTA", model="HILUX", year=2020, series="SR5", engine="2.8L")
print(result.type) # "variant"
print(result.data) # ["4x4 Double Cab", "4x4 Extra Cab", ...]
# Step 7: Full vehicle details
result = client.vehicles(
make="TOYOTA", model="HILUX", year=2020, series="SR5",
engine="2.8L", variant="4x4 Double Cab",
)
print(result.type) # "vehicle"
print(result.data) # [{"make": "TOYOTA", "model": "HILUX", ...}]
For vehicles without a series code, pass an empty string:
result = client.vehicles(make="TOYOTA", model="HILUX", year=2020, series="")
Check usage
usage = client.usage()
print(f"{usage.used_this_month}/{usage.monthly_limit} lookups used")
print(f"{usage.remaining} remaining")
print(f"{usage.percent_used}% used")
print(f"Plan: {usage.plan}")
print(f"Rate limit: {usage.rate_limit_per_min}/min")
print(f"Period: {usage.period_start} to {usage.period_end}")
print(f"Days remaining: {usage.days_remaining}")
print(f"Last lookup: {usage.last_lookup_at}")
print(f"Top-up credits: {usage.topup_credits}")
print(f"Cancel at period end: {usage.cancel_at_period_end}")
print(f"Cancel at: {usage.cancel_at}")
Request logs
Retrieve your lookup history with optional filtering and pagination. Useful for auditing, debugging, and building analytics.
# Last 10 lookups
logs = client.logs(limit=10)
for entry in logs.logs:
status = "found" if entry.success else "not found"
print(f"{entry.created_at} | {entry.plate} ({entry.state}) | {status} | {entry.duration_ms}ms")
print(f"Showing {logs.count} of {logs.total} total")
Filtering
# Filter by plate
logs = client.logs(plate="ABC123")
# Only failed lookups
logs = client.logs(success=False)
# Time range (ISO 8601, UTC)
logs = client.logs(
since="2026-07-01T00:00:00",
until="2026-07-31T23:59:59",
)
# Pagination
page1 = client.logs(limit=50, offset=0)
page2 = client.logs(limit=50, offset=50)
Log entry fields
Each LogEntry contains: plate, state, success (1 or 0), error, duration_ms, make, model, year, client_ip, request_id, created_at.
Health check
Check API availability. No authentication required, no quota consumed.
health = client.health()
print(health.status) # "ok"
Rate limits
Rate limit info is included with every lookup response.
result = client.lookup("ABC123", "VIC")
print(result.rate_limit.limit) # monthly lookup allowance
print(result.rate_limit.remaining) # lookups left this period
print(result.rate_limit.plan) # current plan slug
# Warn before quota runs out
if result.rate_limit.remaining is not None and result.rate_limit.remaining < 50:
print(f"Warning: only {result.rate_limit.remaining} lookups remaining")
Error handling
from plateapi import (
PlateAPI,
PlateAPIError,
AuthenticationError,
RateLimitError,
QuotaExceededError,
ServerError,
)
client = PlateAPI("pk_live_your_api_key")
try:
result = client.lookup("ABC123", "VIC")
except AuthenticationError:
print("Invalid API key")
except QuotaExceededError:
print("Monthly quota exceeded -- upgrade at plateapi.com.au")
except RateLimitError as e:
print(f"Rate limited, retry after {e.retry_after}s")
except ServerError as e:
print(f"Server error ({e.status_code}), retry after {e.retry_after}s")
except PlateAPIError as e:
print(f"API error: {e} (status {e.status_code})")
Retry behaviour
The SDK automatically retries on:
- Connection errors
- Timeouts
- 429 rate limit responses (waits for Retry-After header)
- 5xx server errors
Default: 3 retries with exponential backoff and jitter. Configure with:
client = PlateAPI(
"pk_live_your_api_key",
max_retries=5,
timeout=60,
)
Context manager
The SDK uses a requests.Session internally. Use a context manager to close it when done.
with PlateAPI("pk_live_your_api_key") as client:
result = client.lookup("ABC123", "VIC")
print(result.vehicle.make)
Or close manually:
client = PlateAPI("pk_live_your_api_key")
try:
result = client.lookup("ABC123", "VIC")
finally:
client.close()
Sandbox
Use plate TEST123 with any state for testing. Returns a fixed response instantly, no quota consumed.
result = client.lookup("TEST123", "VIC")
assert result.sandbox is True
assert result.success is True
print(result.vehicle.make) # "TOYOTA"
The sandbox also supports detailed=True.
Configuration
client = PlateAPI(
"pk_live_your_api_key",
base_url="https://api.plateapi.com.au", # default
timeout=30, # seconds, default 30
max_retries=3, # default 3
)
Links
Metadata
Release files for plateapi 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| plateapi-0.1.0.tar.gz | 10.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| plateapi-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 19.3 kB
Release files / plateapi-0.1.0.tar.gz
| Download URL | plateapi-0.1.0.tar.gz |
|---|---|
| Size | 10.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3b9c5ac0d47c927b4f5c940612e99703d7fe8b6b7f7a2a14f95acdbe94b3dea4
|
|
BLAKE2b-256 checksum How to use checksums |
c1ea77ad5126aeaa07a29f064b8ff520b7831beb524f84e30246d94bca6fabfa
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.10.12
|
Release files / plateapi-0.1.0-py3-none-any.whl
| Download URL | plateapi-0.1.0-py3-none-any.whl |
|---|---|
| Size | 8.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
81e2983e2c5ead91c58f900ee99927041eb1bda4d1a83140b6a2cc9a030fbc27
|
|
BLAKE2b-256 checksum How to use checksums |
f838b1668c8e9a1cf86454597c154cf60b5f4f51eb94c9577b533a8ed53670d8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.10.12
|