Skip to main content

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)

Source distribution for plateapi 0.1.0
File Size Uploaded
plateapi-0.1.0.tar.gz 10.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for plateapi 0.1.0
File Interpreter ABI Platform
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

Release history Release notifications | RSS feed

0.2.0

2 release files

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page