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 clients — line_item, order, placement, ad_unit, custom_targeting, role, user, network, private_auction, private_auction_deal, programmatic_buyer, and report.
  • Correct GAM filter-string building — GAMRestFilters centralizes the quoting rules (quoted strings/dates, bare numbers/booleans) so you never hand-write a malformed filter query param.
  • Automatic pagination — list 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 support — run_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 scope — from_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 interval — ReportJob.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.

Metadata

Release files for pyadmanager 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pyadmanager 0.1.1
File Size Uploaded
pyadmanager-0.1.1.tar.gz 21.0 kB Details

Built distribution (wheel)

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

Total release size: 54.3 kB

Release files / pyadmanager-0.1.1.tar.gz

Download URL pyadmanager-0.1.1.tar.gz
Size 21.0 kB
Tags Source
SHA-256 checksum
How to use checksums
3c95a1a73a9218f9d2d11fab6ae5e935a019fc0cf3becd4b989021a118d18ec3
BLAKE2b-256 checksum
How to use checksums
714e0c2c6473ca5edddcc4f703c7fdb09ab16f51086effbcd12bf538213206cc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 10, 2026.

Transparency log

Release files / pyadmanager-0.1.1-py3-none-any.whl

Download URL pyadmanager-0.1.1-py3-none-any.whl
Size 33.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ec970d355e2c796a0fa68467ae538b96099bcbb79f8ab213d74b38aaaba76d6c
BLAKE2b-256 checksum
How to use checksums
39f75082ee97888c1bcabc7e269aa2ea1912fa1f2bcc2629f52a2e1b7764710d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 10, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

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