Skip to content

Add geo and publisher breakdown reports to the advertiser API - #1237

Draft
ericholscher wants to merge 6 commits into
mainfrom
claude/magical-meitner-1o1ucz
Draft

Add geo and publisher breakdown reports to the advertiser API#1237
ericholscher wants to merge 6 commits into
mainfrom
claude/magical-meitner-1o1ucz

Conversation

@ericholscher

@ericholscher ericholscher commented Jun 22, 2026

Copy link
Copy Markdown
Member

HS: Had an advertiser ask for MCP access on a call, and I mentioned we could give reports via the API. I looked into the API reporting, and it's pretty minimal, so had the AI throw together a quick port of the existing easy reports to port over.

Summary

Advertisers can already see geo and publisher breakdowns of their ad performance in the dashboard, but the API only exposed the daily/flight/ad report. This adds two new read-only endpoints to the advertiser API so advertisers can pull that same granular data programmatically.

New endpoints on AdvertiserViewSet:

Endpoint Breakdown Backing report class
GET /api/v1/advertisers/{slug}/geo_report/ by country AdvertiserGeoReport
GET /api/v1/advertisers/{slug}/publisher_report/ by publisher AdvertiserPublisherReport

Each returns { "total": {...}, "results": [...] } with views, clicks, cost, ctr, and ecpm per row. The publisher report emits a machine-readable publisher slug plus a publisher_name.

Implementation notes

  • Reuses existing report classes only — no new report classes were added. Both endpoints sit on the already-existing AdvertiserGeoReport and AdvertiserPublisherReport.
  • Adds a shared _breakdown_report helper that builds the advertiser-scoped queryset, runs the report, and serializes rows into JSON-safe dicts (the report's internal index can be a Publisher model instance, which isn't directly serializable).
  • Factors the duplicated start_date/end_date parsing out of the existing report action into a _date_range helper, now shared by all three report actions.
  • All endpoints honor the same advertiser access scoping and start_date/end_date filtering as the existing report endpoint.
  • The API reference docs render from the AdvertiserViewSet docstring (autoclass), so the new endpoints are documented there.

Not included

Keyword, topic, and domain breakdowns are rendered from Metabase in the dashboard rather than from these report classes, so they're out of scope here. Keyword in particular has no advertiser-appropriate report class to reuse (the existing PublisherKeywordReport computes publisher revenue, not advertiser cost), so it would require new code.

Testing

  • New tests: test_advertiser_geo_report, test_advertiser_publisher_report, plus access-control coverage for both endpoints.
  • Full adserver.tests.test_api and adserver.tests.test_reports suites pass; ruff check/ruff format clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_01A75FWNN8ep1FfSP76811cS


Generated by Claude Code

claude added 5 commits June 22, 2026 17:19
Add geo, publisher, and keyword breakdown report endpoints to the
advertiser API to match the granular reports already available to
advertisers in the dashboard.

New endpoints on the advertiser API:
 * /api/v1/advertisers/{slug}/geo_report/ - performance by country
 * /api/v1/advertisers/{slug}/publisher_report/ - performance by publisher
 * /api/v1/advertisers/{slug}/keyword_report/ - performance by keyword

These reuse the existing AdvertiserGeoReport and AdvertiserPublisherReport
classes and add a new AdvertiserKeywordReport. All endpoints honor the same
advertiser access scoping and start_date/end_date filtering as the existing
report endpoint.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A75FWNN8ep1FfSP76811cS
Drop the new AdvertiserKeywordReport class and the keyword_report endpoint
so the breakdown API only relies on existing report infrastructure. The geo
and publisher endpoints reuse the existing AdvertiserGeoReport and
AdvertiserPublisherReport classes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A75FWNN8ep1FfSP76811cS
Mirror the BaseReportView.fieldnames convention used by the dashboard CSV
exports instead of hand-rolling per-dimension serialization. Breakdown rows
are now projected through a shared report_fields list and labeled by the
generic "index" field, dropping the Publisher special-case.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A75FWNN8ep1FfSP76811cS
Add BaseReport.serialize(fields) which projects results/total onto a column
list as JSON-serializable rows. Both the advertiser breakdown API and the
dashboard CSV exports now use it, removing the duplicated projection logic
and the API-specific row serializer.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A75FWNN8ep1FfSP76811cS
@davidfischer

Copy link
Copy Markdown
Collaborator

This looks pretty good. Happy these are relatively easy to add!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants