Skip to main content

pyadmanager

A simple, modern Python REST client for the Google Ad Manager API.

PyPI version Python versions License: MIT Build status

Overview / Why pyadmanager?

pyadmanager is a developer-friendly way to read data out of Google Ad Manager: typed, autocomplete-able filter builders, automatic pagination and retries, and one GAMClient entry point — no code generation, no WSDL, no hand-built query strings.

For comparison, Google offers two official clients:

  • googleads — the legacy SOAP API client. Powerful, but heavyweight and tied to SOAP's older, more ceremonious request/response model.
  • google-ads-admanager — the official REST API (v1) client, code-generated from the API's protobuf definitions. Complete, but as with most generated clients, it prioritizes full API coverage over an ergonomic, idiomatic-Python feel.

pyadmanager targets that same REST API but is hand-written for ergonomics: it trades full write-API coverage (it's read-only today — see Roadmap) for a small, typed surface that's easy to read, autocomplete, and reason about. If you just need to pull line items, run a report, or look up custom targeting keys through the Ad Manager REST API (v1), it does that without you needing to hand-roll requests calls or re-derive GAM's filter-query grammar (field = "value" for strings, bare true/false for booleans, RFC-3339 strings for dates) yourself.

pyadmanager wraps that REST API in a thin, typed client:

  • One GAMClient entry point, one resource client per GAM resource (.line_item, .report, .order, ...), each built lazily and cached.
  • Typed list filter keyword arguments per resource so your editor autocompletes valid filter fields and Literal enum values (e.g. LineItemType), and pyright catches typos before you hit the API.
  • Pagination, retries (with exponential backoff on 429/500/502/503/504), and GAM's filter-string quoting rules handled for you.
  • Read-only today. Every resource client currently only implements list/get, even for resources where the REST API supports writes. create/update/delete support is on the roadmap — if you need write access right now, this isn't yet the library for you.

It's aimed at ad-ops engineers and backend developers who need to read Ad Manager data (line items, orders, reports, inventory) into Python — for dashboards, ETL pipelines, or one-off scripts — without pulling in the full googleads SOAP stack.

Features

  • Typed, per-resource clientsline_item, order, placement, ad_unit, custom_targeting, role, user, network, private_auction, private_auction_deal, programmatic_buyer, and report.
  • Correct GAM filter-string buildingGAMRestFilters centralizes the quoting rules (quoted strings/dates, bare numbers/booleans) so you never hand-write a malformed filter query param.
  • Automatic paginationlist methods page through nextPageToken and return the fully collected list.
  • Built-in retry with backoff — transient errors (429/500/502/503/504, connection/timeout errors) are retried automatically.
  • Async report supportrun_report() kicks off a GAM report job and returns a ReportJob you can poll and pull rows from, optionally parsed straight into a polars.DataFrame.
  • Cross-resource id resolution — pass a bare order_id/key_id/parent_ad_unit_id int and it's resolved into the correct GAM resource path for you.

Installation

Requires Python 3.13+.

pip install pyadmanager

To use ReportJob.fetch_rows_as_dataframe() / parse_report_rows(), install the optional polars extra:

pip install "pyadmanager[polars]"

Without the extra, everything else works normally — parse_report_rows just raises a clear ImportError if you call it without polars installed.

Quick Start (The 80/20 Example)

from pyadmanager import GAMClient

client = GAMClient.from_service_account_file(
    network_code="123456789",
    filename="creds.json",
    readonly=True,  # requests the read-only OAuth scope
)

# List every non-archived line item for a given order
line_items = client.line_item.list(order_id=98765, archived=False)

for item in line_items:
    print(item["displayName"], item["status"])

Detailed Usage & Code Examples

Basic Example

from pyadmanager import GAMClient

client = GAMClient.from_service_account_file(
    network_code="123456789",
    filename="creds.json",
)

# Fetch a single line item by numeric id
line_item = client.line_item.get(line_item_id=112233)
print(line_item["name"], line_item["lineItemType"])

# List active custom targeting keys
keys = client.custom_targeting.list_keys(status="ACTIVE")
for key in keys:
    print(key["displayName"])

Advanced Example

from datetime import datetime, timedelta, timezone

from pyadmanager import GAMClient
from pyadmanager.filters import GAMRestFilters

client = GAMClient.from_service_account_file(
    network_code="123456789",
    filename="creds.json",
)

# Filter using a (value, filter_type) tuple to build CONTAINS/GT_EQ-style clauses
one_week_ago = datetime.now(timezone.utc) - timedelta(days=7)

delivering_line_items = client.line_item.list(
    display_name=("Q3", "CONTAINS"),  # displayName = "*Q3*"
    status=["DELIVERING", "READY"],  # (status = "DELIVERING" OR status = "READY")
    start_time=(one_week_ago, "GT_EQ"),  # startTime >= "2026-..."
    page_size=500,  # tune the page size (default 1000)
)

# Run a saved report and pull results straight into a polars DataFrame
# (requires: pip install "pyadmanager[polars]")
job = client.report.run_report(report_id=445566)
df = job.fetch_rows_as_dataframe()  # polls until GAM finishes computing rows
print(df.head())

# Handle report failures explicitly instead of letting fetch_rows_as_dataframe raise
try:
    job.wait_till_complete(sleep=5.0)
except ValueError as exc:
    print("report job failed:", exc)
else:
    rows = job.fetch_rows()  # raw pages, if you'd rather parse them yourself

API Overview / Key Reference

Class / Method Inputs Output Description
GAMClient.from_service_account_file(network_code, filename, readonly=False, **kwargs) GAM network code, path to a service-account JSON key, optional readonly flag GAMClient Builds credentials from a key file on disk and returns a ready-to-use client.
GAMClient.from_service_account_info(network_code, info, readonly=False, **kwargs) GAM network code, service-account key as a dict GAMClient Same as above, for key material loaded from a secrets manager rather than a file.
GAMClient.<resource> resource client (e.g. LineItemClient) Lazily built, cached per-resource client sharing the parent's network code and session.
<Resource>Client.list(**filters, page_size=1000) typed filter kwargs per resource list[dict] Pages through every matching result via nextPageToken.
<Resource>Client.get(id) numeric resource id dict Fetches a single resource by id.
ReportClient.run_report(report_id) numeric report id ReportJob Starts async generation of a saved report's rows.
ReportJob.wait_till_complete(sleep=2.5) poll interval (seconds) None Blocks until the report job is done; raises ValueError on job failure.
ReportJob.fetch_rows(sleep=2.5) poll interval (seconds) list[dict] Polls to completion if needed, then returns raw report result pages.
ReportJob.fetch_rows_as_dataframe(sleep=2.5) poll interval (seconds) polars.DataFrame Same as fetch_rows, parsed into a DataFrame (requires the polars extra).
GAMRestFilters.text_filter/number_filter/boolean_filter/date_filter/id_based_filter field name, value (or (value, FILTER_TYPE) tuple) str Low-level building blocks for GAM's filter-query grammar — used internally by every resource's list method.

Configuration & Customization

  • Auth scopefrom_service_account_file/from_service_account_info default to the full https://www.googleapis.com/auth/admanager scope; pass readonly=True for https://www.googleapis.com/auth/admanager.readonly, or an explicit scopes=[...] kwarg to override either default.
  • Extra credential kwargs — any additional keyword arguments passed to the from_service_account_* constructors are forwarded directly to google.oauth2.service_account.Credentials.
  • Page size — every list method accepts page_size (default 1000) to tune how many results are fetched per underlying HTTP request; pagination across pages happens automatically regardless of this value.
  • Report poll intervalReportJob.wait_till_complete/fetch_rows/fetch_rows_as_dataframe accept a sleep argument (default 2.5 seconds) controlling how often the async report job's status is polled.
  • Logging — the library logs via the standard logging module (logging.getLogger("pyadmanager...")); enable DEBUG logging to see outgoing request URLs/params and report-job poll iterations, or INFO for lifecycle events like credential loading and report job completion.

Roadmap

  • Write support (create/update/delete) for resources where the underlying REST API supports it (e.g. orders, lineItems, placements, adUnits). The library is read-only today; this is the main planned expansion of scope.
  • New resource coverage, following the existing services/<resource>.py pattern as GAM's REST API surface grows.

Have a resource or write operation you need sooner? Open an issue — it helps prioritize the roadmap.

Contributing

Contributions are welcome! To get set up locally:

uv sync --extra polars   # install all deps, including the optional polars extra
uv run pytest            # run the test suite
uv run ruff check .      # lint
uv run pyright src tests # type check

Please open an issue before starting on a larger change, especially write support (see Roadmap) so the approach can be agreed on before you invest the time. Bug reports and PRs for new read-only resources are especially appreciated — see services/ for the pattern each resource client follows.

License

MIT — see LICENSE for details.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyadmanager-0.1.1.tar.gz (21.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pyadmanager-0.1.1-py3-none-any.whl (33.3 kB view details)

Uploaded Python 3

File details

Details for the file pyadmanager-0.1.1.tar.gz.

File metadata

  • Download URL: pyadmanager-0.1.1.tar.gz
  • Upload date:
  • Size: 21.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for pyadmanager-0.1.1.tar.gz
Algorithm Hash digest
SHA256 3c95a1a73a9218f9d2d11fab6ae5e935a019fc0cf3becd4b989021a118d18ec3
MD5 8700759de00f6456a4a6d2cac6dc987a
BLAKE2b-256 714e0c2c6473ca5edddcc4f703c7fdb09ab16f51086effbcd12bf538213206cc

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyadmanager-0.1.1.tar.gz:

Publisher: release.yaml on shani-suthar/pyadmanager

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyadmanager-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: pyadmanager-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 33.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for pyadmanager-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 ec970d355e2c796a0fa68467ae538b96099bcbb79f8ab213d74b38aaaba76d6c
MD5 8a7b7ac974ed5cceb8e1e328fe410419
BLAKE2b-256 39f75082ee97888c1bcabc7e269aa2ea1912fa1f2bcc2629f52a2e1b7764710d

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyadmanager-0.1.1-py3-none-any.whl:

Publisher: release.yaml on shani-suthar/pyadmanager

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page