Tracking API Usage Quotas for Licensed Basemaps
To stay within a commercial basemap EULA, meter every tile or API request into a durable per-provider, per-period counter and emit escalating warnings as usage crosses configurable percentages of the contractual quota — so an approaching overage is a logged, actionable event rather than a month-end billing surprise. Commercial basemap providers price on request or tile volume and enforce hard ceilings in their agreements; crossing one silently can trigger overage billing, throttling, or a contract-compliance review.
This is one of the most common enforcement points in Commercial EULA Compliance Tracking, and it belongs to the broader discipline described in Geospatial Data Licensing & Compliance Fundamentals: a licensing obligation encoded as an engineering control rather than a manual review. The quota clause in a basemap EULA is a number; the job is to make your infrastructure respect that number automatically.
Automated Python Implementation
The script below is a self-contained quota meter backed by sqlite3. It stores each provider’s quota and warning thresholds, increments a counter keyed by provider and billing period, and returns a status object that tells the caller whether the request is within quota, approaching the limit, or over. It uses an atomic upsert so concurrent request handlers cannot lose increments.
#!/usr/bin/env python3
"""Meter basemap tile/API requests against commercial EULA quotas.
A durable sqlite3 counter, keyed by (provider, period), that warns at
configurable percentages of the contractual quota and blocks at 100%.
"""
import sqlite3
from dataclasses import dataclass
from datetime import date
from typing import List, Optional
DB_PATH = "basemap_quota.db"
@dataclass
class QuotaStatus:
provider: str
period: str
used: int
quota: int
pct: float
level: str # "ok", "warn", "critical", "over"
allowed: bool # may the request proceed under policy
def _connect(db_path: str) -> sqlite3.Connection:
conn = sqlite3.connect(db_path)
conn.execute("PRAGMA journal_mode=WAL") # tolerate concurrent writers
with conn:
conn.execute("""
CREATE TABLE IF NOT EXISTS quota (
provider TEXT NOT NULL,
monthly_quota INTEGER NOT NULL,
warn_pct REAL NOT NULL DEFAULT 0.8,
critical_pct REAL NOT NULL DEFAULT 0.95,
block_over INTEGER NOT NULL DEFAULT 1,
PRIMARY KEY (provider)
)
""")
conn.execute("""
CREATE TABLE IF NOT EXISTS usage (
provider TEXT NOT NULL,
period TEXT NOT NULL,
count INTEGER NOT NULL DEFAULT 0,
PRIMARY KEY (provider, period)
)
""")
return conn
def register_provider(provider: str, monthly_quota: int,
warn_pct: float = 0.8, critical_pct: float = 0.95,
block_over: bool = True, db_path: str = DB_PATH) -> None:
"""Record or update a provider's contractual quota and thresholds."""
conn = _connect(db_path)
with conn:
conn.execute("""
INSERT INTO quota (provider, monthly_quota, warn_pct,
critical_pct, block_over)
VALUES (?, ?, ?, ?, ?)
ON CONFLICT(provider) DO UPDATE SET
monthly_quota=excluded.monthly_quota,
warn_pct=excluded.warn_pct,
critical_pct=excluded.critical_pct,
block_over=excluded.block_over
""", (provider, monthly_quota, warn_pct, critical_pct, int(block_over)))
conn.close()
def _current_period() -> str:
"""Billing period key, e.g. '2026-07' — matches a monthly EULA cycle."""
return date.today().strftime("%Y-%m")
def meter_request(provider: str, count: int = 1,
db_path: str = DB_PATH) -> QuotaStatus:
"""Atomically record `count` requests and return the resulting status."""
period = _current_period()
conn = _connect(db_path)
with conn:
row = conn.execute(
"SELECT monthly_quota, warn_pct, critical_pct, block_over "
"FROM quota WHERE provider = ?", (provider,)
).fetchone()
if row is None:
conn.close()
raise KeyError(f"Provider '{provider}' is not registered")
quota, warn_pct, critical_pct, block_over = row
# Atomic upsert increment — safe under concurrent handlers.
conn.execute("""
INSERT INTO usage (provider, period, count) VALUES (?, ?, ?)
ON CONFLICT(provider, period) DO UPDATE SET
count = count + excluded.count
""", (provider, period, count))
used = conn.execute(
"SELECT count FROM usage WHERE provider = ? AND period = ?",
(provider, period)
).fetchone()[0]
conn.close()
pct = used / quota if quota else 1.0
if pct >= 1.0:
level, allowed = "over", not bool(block_over)
elif pct >= critical_pct:
level, allowed = "critical", True
elif pct >= warn_pct:
level, allowed = "warn", True
else:
level, allowed = "ok", True
return QuotaStatus(provider, period, used, quota, round(pct, 4),
level, allowed)
def report(db_path: str = DB_PATH) -> List[QuotaStatus]:
"""Return the current-period status for every registered provider."""
period = _current_period()
conn = _connect(db_path)
statuses: List[QuotaStatus] = []
rows = conn.execute(
"SELECT provider, monthly_quota, warn_pct, critical_pct FROM quota"
).fetchall()
for provider, quota, warn_pct, critical_pct in rows:
used_row = conn.execute(
"SELECT count FROM usage WHERE provider = ? AND period = ?",
(provider, period)
).fetchone()
used = used_row[0] if used_row else 0
pct = used / quota if quota else 1.0
level = ("over" if pct >= 1.0 else "critical" if pct >= critical_pct
else "warn" if pct >= warn_pct else "ok")
statuses.append(QuotaStatus(provider, period, used, quota,
round(pct, 4), level, level != "over"))
conn.close()
return statuses
if __name__ == "__main__":
register_provider("acme-satellite-basemap", monthly_quota=1_000_000,
warn_pct=0.8, critical_pct=0.95, block_over=True)
status: Optional[QuotaStatus] = None
for _ in range(5):
status = meter_request("acme-satellite-basemap", count=200_000)
assert status is not None
print(f"{status.provider} [{status.period}]: "
f"{status.used}/{status.quota} = {status.pct:.0%} -> {status.level}")
print(f"request allowed under policy: {status.allowed}")
The counter is keyed by (provider, period), so the first request in a new calendar month starts a fresh count automatically while historical rows remain intact for audit. Because the increment is a single atomic INSERT ... ON CONFLICT ... DO UPDATE, parallel tile handlers cannot lose counts under load.
Validation and pipeline integration
Drive the meter with a scripted burst and confirm the threshold transitions fire where expected:
# Fresh run against a throwaway database
rm -f basemap_quota.db
python basemap_quota_meter.py
Lock the threshold logic with pytest, using an isolated temp database so tests never touch production counters:
# tests/test_quota_meter.py
import basemap_quota_meter as m
def test_warn_and_over_transitions(tmp_path):
db = str(tmp_path / "q.db")
m.register_provider("prov", monthly_quota=100, warn_pct=0.8,
critical_pct=0.95, block_over=True, db_path=db)
assert m.meter_request("prov", 50, db_path=db).level == "ok"
assert m.meter_request("prov", 35, db_path=db).level == "warn"
over = m.meter_request("prov", 20, db_path=db)
assert over.level == "over"
assert over.allowed is False # block_over=True denies the request
def test_unregistered_provider_raises(tmp_path):
db = str(tmp_path / "q.db")
try:
m.meter_request("unknown", db_path=db)
assert False, "expected KeyError"
except KeyError:
pass
Add a scheduled reporting job that surfaces every provider approaching its ceiling so procurement can act before month-end:
# .github/workflows/basemap-quota-report.yml
name: Basemap Quota Report
on:
schedule:
- cron: "0 8 * * 1" # Mondays 08:00 UTC
jobs:
report:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Print quota status
run: python -c "import basemap_quota_meter as m; [print(s) for s in m.report()]"
Long-term compliance best practices
- Set the warning threshold well below the ceiling. An 80% warn and 95% critical give operations time to throttle non-essential traffic or contact the vendor before an overage, rather than discovering the breach at 100%.
- Match the counter period to the billing period exactly. If the EULA measures usage per calendar month in a specific timezone, key and reset the counter on that boundary; a mismatched window under- or over-counts near period edges.
- Verify the caching clause before relying on a cache. Reducing quota consumption by caching tiles is only lawful if the EULA permits persistent caching; an unpermitted cache trades a quota problem for a redistribution violation.
- Meter at the point of egress. Count requests where they actually leave your infrastructure to the provider, not at an upstream layer that may retry or fan out, so the counter reflects billable volume.
- Retain historical period rows for audit. Keep past-period usage counts as immutable evidence; during a vendor compliance review they demonstrate that you tracked consumption against the contractual limit.
- Reconcile against the provider’s own figures. Periodically compare the local counter to the provider dashboard; a persistent gap signals uncounted egress paths or clock skew that needs fixing before it becomes a dispute.
Related
- Commercial EULA Compliance Tracking — the parent guide to fingerprinting, clause normalization, and constraint mapping for proprietary datasets
- Mapping Commercial GIS Data Usage Rights — turn EULA clauses, including quota terms, into queryable constraint matrices
- Automating License Checks with Python and OGR — embed compliance gates directly into ingestion pipelines
- Geospatial Data Licensing & Compliance Fundamentals — parent overview of licensing obligations and the commercial risk surface