Skip to main content

adspub

PyPI Python CI License: MIT

Machine-readable view of the Google Ad Manager API version list, with a CLI built for both humans and AI agents.

Google only publishes which Ad Manager (formerly DoubleClick for Publishers) API versions are supported on a human-readable page: https://ads.google.com/apis/ads/publisher. Versions rotate several times a year, get marked deprecated, and then disappear. adspub turns that page into JSON, caches it locally, and answers two questions reliably:

  • Which version is the latest?
  • Is the version I am pinned to still active, deprecated, or gone?

adspub demo

Status rules:

Status Meaning
active Listed on the page without a deprecation marker. Safe to use.
deprecated Listed with the "Deprecated" marker. Still callable, migrate soon.
unlisted Not on the page at all. Assumed sunset and no longer callable.

Install

uv tool install adspub        # as a global CLI tool
uvx adspub latest             # or run without installing
pip install adspub            # or into a project

Supports Python 3.11 through 3.15.

Human usage

adspub latest                       # v202608
adspub list                         # table of all versions with status
adspub check v202602                # active, deprecated or unlisted
adspub check v202511 v202602        # several at once; worst status sets the exit code
adspub services v202608             # SOAP services and WSDL/doc links in a version
adspub dump -o catalog.json         # full catalog as JSON
adspub cache info                   # where the cache is and how old
adspub cache clear

Global options go before the command:

adspub --json latest                # JSON output, every command supports it
adspub --refresh list               # ignore the cache and fetch now
adspub --offline check v202602      # never touch the network
adspub --max-age 3600 latest        # reuse the cache for at most one hour

Example:

$ adspub check v202511 v202602 v202608 v202405
deprecated v202511 is deprecated and will be removed; migrate to v202608.
active     v202602 is active but not the latest; v202608 is newer.
active     v202608 is the latest active version.
unlisted   v202405 is not listed and is assumed to be sunset; migrate to v202608.
$ echo $?
20

Caching

Results are cached as a single JSON file for 24 hours by default:

  • Linux: ~/.cache/adspub/catalog.json
  • macOS: ~/Library/Caches/adspub/catalog.json
  • Windows: %LOCALAPPDATA%\adspub\adspub\Cache\catalog.json

Override the location with --cache-dir or the ADSPUB_CACHE_DIR environment variable. If the network is down and a cache exists, the stale cache is used and a warning is printed to stderr. JSON output always reports where the data came from (network, cache or stale-cache) and when it was fetched.

Use in CI

Fail a build when the pinned version is no longer active:

adspub check "$AD_MANAGER_API_VERSION"

Exit code 0 means active, 10 deprecated, 20 unlisted. Use || [ $? -eq 10 ] if you want deprecated to warn rather than fail.

AI agent usage

The CLI is designed so an agent can call it without parsing prose:

  • --json gives structured output on every command.
  • Exit codes encode the answer: 0 active, 10 deprecated, 20 unlisted, 1 runtime error (network or parse), 2 usage error.
  • Output includes a meta block with source and fetched_at so the agent can decide whether to re-run with --refresh.
  • adspub schema prints the JSON Schema of the catalog document.
  • adspub parse page.html parses a saved copy with no network or cache.

Paste this into your agent's instructions file (CLAUDE.md, AGENTS.md, a system prompt, or a tool description):

## Google Ad Manager API versions

Use the `adspub` CLI (install: `uv tool install adspub`, or run `uvx adspub`)
to find out which Ad Manager API versions are valid. Never guess a version.

- Latest version:          `adspub --json latest`
- Check a pinned version:  `adspub --json check v202602`
- All versions:            `adspub --json list`
- Force a fresh fetch:     add `--refresh` before the command

Exit codes for `check`: 0 active, 10 deprecated, 20 unlisted (assume removed).
Read `.results[].status`, `.results[].latest` and `.results[].newer_versions`
from the JSON. If `.meta.source` is `stale-cache`, retry with `--refresh`.

Example JSON from adspub --json check v202511:

{
  "ok": false,
  "exit_code": 10,
  "latest": "v202608",
  "results": [
    {
      "version": "v202511",
      "status": "deprecated",
      "is_latest": false,
      "latest": "v202608",
      "newer_versions": ["v202602", "v202605", "v202608"],
      "message": "v202511 is deprecated and will be removed; migrate to v202608."
    }
  ],
  "meta": {
    "source": "cache",
    "fetched_at": "2026-10-09T09:47:14.401329+00:00",
    "cache_age_seconds": 0.7,
    "source_url": "https://ads.google.com/apis/ads/publisher",
    "warning": null
  }
}

As a tool for a Claude agent

A minimal tool definition that wraps the CLI:

{
  "name": "ad_manager_api_version_check",
  "description": "Check whether a Google Ad Manager API version (vYYYYMM) is active, deprecated or unlisted, and get the latest version. Runs `adspub --json check <version>`.",
  "input_schema": {
    "type": "object",
    "properties": {
      "version": { "type": "string", "description": "Version such as v202602" }
    },
    "required": ["version"]
  }
}

The tool handler runs adspub --json check <version> and returns stdout verbatim.

Python API

Everything is async. The CLI is a thin layer over these functions.

import asyncio

from adspub import load_catalog


async def main() -> None:
    result = await load_catalog()             # cache-aware; fetches when stale
    catalog = result.catalog
    print(result.source)                      # network | cache | stale-cache
    print(catalog.latest.version)             # v202608
    print([v.version for v in catalog.deprecated])

    check = catalog.check("v202511")
    print(check.status, check.newer_versions, check.message)


asyncio.run(main())

Other entry points:

from adspub import fetch_catalog, parse_catalog

catalog = await fetch_catalog()                           # no cache
catalog = parse_catalog(html, source_url="https://...")  # from a string

load_catalog accepts refresh, offline, max_age (seconds), cache_dir, allow_stale, timeout, and an optional httpx.AsyncClient for connection reuse or testing with httpx.MockTransport.

All models are Pydantic v2 (Catalog, ApiVersion, Service, VersionCheck), so model_dump_json() and model_json_schema() work as expected.

Development

git clone https://github.com/eivl/adspub && cd adspub
uv sync                      # creates .venv with dev dependencies
uv run pre-commit install    # ruff, mypy, uv lock check on commit
uv run pytest                # tests
uv run pytest --cov          # with coverage
uv run ruff check . && uv run ruff format . && uv run mypy
uv run --python 3.11 pytest  # any supported interpreter

The demo GIF in this README is rendered from demo/demo.tape with VHS: run vhs demo/demo.tape locally, or trigger the "Render demo" workflow, which commits the updated GIF.

Tests never touch the network. The parser is tested against tests/fixtures/publisher.html, a saved copy of the real page. A weekly GitHub Actions job parses the live page and warns when the fixture falls behind.

Releasing

Releases publish to PyPI via GitHub Actions trusted publishing when a v* tag is pushed:

uv version --bump minor
git commit -am "Release v$(uv version --short)"
git tag "v$(uv version --short)"
git push && git push --tags

One-time setup: on PyPI, add a trusted publisher for this repository with workflow publish.yml and environment pypi, and create a pypi environment in the GitHub repository settings.

License

MIT

Metadata

Release files for adspub 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 adspub 0.1.0
File Size Uploaded
adspub-0.1.0.tar.gz 15.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for adspub 0.1.0
File Interpreter ABI Platform
adspub-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 34.8 kB

Release files / adspub-0.1.0.tar.gz

Download URL adspub-0.1.0.tar.gz
Size 15.9 kB
Tags Source
SHA-256 checksum
How to use checksums
fe30c0a35ebb035cb23fa174abf071620f653c4a28ef9aedaa95f6090b43e4ce
BLAKE2b-256 checksum
How to use checksums
7d61f70d1eb7a549c8eda9b33586308c79def4a1580b41c6a4aeb4dd6e4c1fef
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.0

Release files / adspub-0.1.0-py3-none-any.whl

Download URL adspub-0.1.0-py3-none-any.whl
Size 19.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
adf3aaf52e7683595152b7a97f53a21ee8c8876d61a5ec839fa7d29778cae4b9
BLAKE2b-256 checksum
How to use checksums
e1dd1de808fb33c950260b3a77b4fd555a5380c5f99a28e848d4034ffb1a5981
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.0

Release history Release notifications | RSS feed

0.1.1

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