Public · REST · v1

Your revenue,
in JSON.
on demand.

The WeForAds Publisher Revenue API v1 gives you programmatic access to daily revenue, eCPM, impressions, and per-site breakdown — the same numbers your dashboard shows, pipeable into your warehouse, BI tool, or Slack bot.

# Get today's revenue, in one line. curl -H "Authorization: Bearer weforads_pk_xxx" \ https://api.weforads.com/api/v1/publisher/revenue/today
01 · Overview

A simple read-only API.

The WeForAds Publisher Revenue API v1 gives you programmatic access to the same revenue, eCPM, impression, and per-site numbers you already see in the publisher dashboard. It is designed for one job: getting your data out of WeForAds and into wherever you keep the rest of your business numbers — a warehouse, a BI tool, a finance spreadsheet, a Slack bot.

Every endpoint is HTTP GET, returns JSON, and is authenticated with a single bearer token. There is no SDK to install, no OAuth dance, no webhooks to configure. If you can curl, you can use it.

Base URL

Base URLhttps
https://api.weforads.com/api/v1

Conventions

  • All responses are application/json; charset=utf-8.
  • All monetary amounts are returned as decimal strings in USD (e.g. "12.4738") to avoid floating-point loss. Always parse as decimal, never as float.
  • All timestamps and dates are UTC. Date-only fields use YYYY-MM-DD. Timestamps use ISO 8601 (2026-06-02T14:23:11Z).
  • "Today" means the current UTC calendar day. If your finance day is in a different timezone, slice your own ranges with the date-range endpoint.
  • Revenue numbers refresh approximately every 60 minutes (programmatic) and every 4 hours (Direct Deals). Same cadence as the dashboard.
02 · Authentication

One header. Bearer token.

Every request must include an Authorization header with a bearer token. Generate your key from Publisher Dashboard → API Access — keys begin with the prefix weforads_pk_.

Request headerhttp
Authorization: Bearer weforads_pk_a8f4c6b2e7d1...

Key scope

  • One key authorizes one publisher account. All sites on that account are visible to the key.
  • Keys are read-only on the revenue endpoints — they cannot change settings or trigger payouts.
  • You can issue up to 5 active keys per account. Revoke unused keys; they cannot be recovered after revocation.
  • Team members (per the publisher_members table) do not automatically inherit the owner's keys. Each team member generates their own.

Security guidance

  • Never embed an API key in client-side JavaScript, mobile apps, or anything a browser can read. Treat it like a database password.
  • Prefer environment variables or a secrets manager. Rotate quarterly.
  • If a key leaks, revoke it immediately from the API Access page. We do not bill, debit, or settle against API activity, so a leaked key cannot move money — but it can expose your revenue numbers.
03 · Rate limits

60 per minute. 1,000 per day.

Limits are applied per API key, not per IP. The two windows are independent — you can exhaust the per-minute window without touching the daily window, and vice versa.

WindowLimitReset
Per minute60 requestsSliding 60s
Per day1,000 requests00:00 UTC

Response headers

Every successful response includes three rate-limit headers so you can self-throttle without polling:

Response headershttp
X-RateLimit-Limit:      60
X-RateLimit-Remaining:  57
X-RateLimit-Reset:      1717340580   # unix seconds

If you exceed a limit you'll receive an HTTP 429 Too Many Requests response with a Retry-After header indicating how many seconds to wait. The body will be {"error":"rate_limited",...} — see the error codes section.

Need more? The revenue numbers themselves only refresh ~hourly, so polling more than once per minute is rarely useful. If you have a genuine batch use case, email [email protected].

04 · Endpoints

Two endpoints. That's all.

Today and range. Everything else you might want — yesterday, MTD, last 7 days, a custom finance month — is just a date-range slice.

GET /api/v1/publisher/revenue/today

Returns today's revenue, eCPM, and impressions, summed across all of your sites. Convenience wrapper around the range endpoint with start = end = today (UTC).

Parameters

None.

Example response

200 OKjson
{
  "date": "2026-06-02",
  "timezone": "UTC",
  "revenue_usd": "412.8341",
  "impressions": 1284032,
  "ecpm_usd": "0.3215",
  "sources": {
    "programmatic_usd": "398.2104",
    "direct_deals_usd": "14.6237"
  },
  "sites": [
    { "site_id": 244, "domain": "example.com",    "revenue_usd": "301.4422", "impressions": 951204 },
    { "site_id": 311, "domain": "example.net",    "revenue_usd": "111.3919", "impressions": 332828 }
  ],
  "as_of": "2026-06-02T14:23:11Z"
}
GET /api/v1/publisher/revenue

Returns daily revenue rows for an inclusive UTC date range. Use this for yesterday, MTD, last 30 days, or your own custom finance window. Maximum range: 92 days per call.

Query parameters

NameTypeRequiredDescription
startdaterequiredYYYY-MM-DD. Inclusive. Earliest supported: 2024-01-01.
enddaterequiredYYYY-MM-DD. Inclusive. Must be ≥ start and within 92 days of it.
site_idintegeroptionalFilter to one site. Omit for account-wide totals.
granularityenumoptionalday (default) or total (one summed row).

Example request

Requesthttp
GET /api/v1/publisher/revenue?start=2026-05-01&end=2026-05-31 HTTP/1.1
Host: api.weforads.com
Authorization: Bearer weforads_pk_xxx

Example response

200 OKjson
{
  "range": { "start": "2026-05-01", "end": "2026-05-31" },
  "granularity": "day",
  "timezone": "UTC",
  "totals": {
    "revenue_usd": "11842.3104",
    "impressions": 38214771,
    "ecpm_usd": "0.3099"
  },
  "days": [
    { "date": "2026-05-01", "revenue_usd": "382.4109", "impressions": 1248122, "ecpm_usd": "0.3064" },
    { "date": "2026-05-02", "revenue_usd": "401.1283", "impressions": 1291844, "ecpm_usd": "0.3105" }
    // ... 29 more rows
  ]
}
05 · Code examples

Three lines. Three languages.

Pulling today's revenue from a shell script, a Python data pipeline, or a Node service. The shapes are identical because the API does not care.

# Today's revenue, account-wide
curl -H "Authorization: Bearer weforads_pk_xxx" \
     https://api.weforads.com/api/v1/publisher/revenue/today

# May 2026, day-by-day, JSON pretty-printed
curl -sH "Authorization: Bearer weforads_pk_xxx" \
  "https://api.weforads.com/api/v1/publisher/revenue?start=2026-05-01&end=2026-05-31" \
  | jq .
import os, requests
from decimal import Decimal

API_KEY = os.environ["WEFORADS_API_KEY"]
BASE    = "https://api.weforads.com/api/v1"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}

# Today's revenue
resp = requests.get(f"{BASE}/publisher/revenue/today", headers=HEADERS, timeout=10)
resp.raise_for_status()
data = resp.json()

rev = Decimal(data["revenue_usd"])         # parse as decimal, not float
imps = data["impressions"]
print(f"Today: ${rev:.2f} on {imps:,} impressions")

# Date range
resp = requests.get(
    f"{BASE}/publisher/revenue",
    headers=HEADERS,
    params={"start": "2026-05-01", "end": "2026-05-31"},
    timeout=10,
)
for day in resp.json()["days"]:
    print(day["date"], day["revenue_usd"])
// Works in Node 18+ and modern browsers via server-side proxy.
// NEVER ship the bearer token to a browser directly.

const API_KEY = process.env.WEFORADS_API_KEY;
const BASE    = "https://api.weforads.com/api/v1";

async function getToday() {
  const res = await fetch(`${BASE}/publisher/revenue/today`, {
    headers: { "Authorization": `Bearer ${API_KEY}` },
  });
  if (!res.ok) throw new Error(`API ${res.status}: ${await res.text()}`);
  return res.json();
}

async function getRange(start, end) {
  const qs  = new URLSearchParams({ start, end });
  const res = await fetch(`${BASE}/publisher/revenue?${qs}`, {
    headers: { "Authorization": `Bearer ${API_KEY}` },
  });
  return res.json();
}

const today = await getToday();
console.log(`Today: $${today.revenue_usd} (${today.impressions.toLocaleString()} imps)`);

Tip: for shell pipelines, pair the API with jq for filtering and datamash or awk for arithmetic. Decimal precision survives both.

06 · Error codes

When things don't.

Every error response uses the same shape: an HTTP status code plus a JSON body with error (a stable machine-readable slug) and message (human-readable). Log the slug, show the message.

Error envelopejson
{
  "error": "invalid_api_key",
  "message": "The API key is missing, malformed, or revoked.",
  "request_id": "req_2026060214a8f4"
}
HTTPSlugCause
400invalid_datesstart or end is missing, malformed, in the future, or end < start.
400range_too_largeDate range exceeds 92 days. Slice into smaller windows.
400invalid_site_idsite_id is not an integer, or does not belong to your account.
401invalid_api_keyMissing, malformed, or revoked bearer token. Re-issue from the API Access page.
403key_disabledKey was disabled by an account admin. Check the API Access page for status.
404not_foundEndpoint path is wrong, or the resource (e.g. specific site) doesn't exist.
429rate_limitedPer-minute or per-day window exhausted. See Retry-After header.
500internal_errorSomething on our side broke. The request_id is the fastest way for us to find it — include it in any support email.
503unavailableBrief upstream outage or maintenance window. Safe to retry with exponential backoff.

Retry policy

  • 4xx errors (except 429) are not retryable. Fix the request.
  • 429: wait the number of seconds in Retry-After, then resume. Do not hammer.
  • 500 / 503: retry with exponential backoff (e.g. 1s, 2s, 4s, 8s). Give up after 4 attempts and surface the error.
07 · Versioning

Versions in the URL.

The version is part of the base path (/api/v1). When we publish a backwards-incompatible change we will mint /api/v2 alongside it and run both in parallel for at least 12 months. We will not silently break v1.

What counts as breaking

  • Removing a field from a response.
  • Changing a field's type (e.g. number → string, decimal-string → float).
  • Changing a field's semantic meaning (e.g. UTC date → account-timezone date).
  • Changing the shape of the error envelope or renaming an error slug.
  • Tightening required parameters or rate limits without a deprecation window.

What does not count as breaking

  • Adding new fields to a response (your parser should ignore unknown keys).
  • Adding new optional query parameters.
  • Adding new endpoints.
  • Adding new error slugs for failure modes that previously returned 500.

We announce deprecations via email to the account owner and post them in the changelog below. Subscribe a generic alias (apis@yourdomain) to avoid surprises during team turnover.

08 · Changelog

What's shipped.

v1.0.0
2026-06-02
Initial public release. GET /publisher/revenue/today and GET /publisher/revenue live with bearer-token auth, per-key rate limiting (60/min · 1,000/day), and the stable error envelope documented above. Direct Deals revenue is included in sources.direct_deals_usd.
v0.9 (beta)
2026-05-15
Closed beta. Schema frozen. Decimal-string format for monetary fields locked in after partner feedback — early-beta float responses are no longer served.

Want to be told when something changes? Make sure your account owner email is current — that is where deprecation notices and security advisories go.

Ready to integrate?

Generate your first key in 20 seconds.

Keys are issued instantly. No approval queue, no sales call.

Get an API key → Email the team

Developer API FAQ

Common questions about the WeForAds Publisher Revenue API.

What is the WeForAds Developer API?
The WeForAds Publisher Revenue API (v1) gives approved publishers programmatic access to their earnings data — daily revenue, eCPM, impressions, and a per-site breakdown — returned as JSON over a REST interface.
How do I authenticate with the API?
The API uses bearer-token authentication: generate an API key in your WeForAds dashboard and pass it in the Authorization header as a Bearer token on every request.
What data can I retrieve?
Your daily revenue, eCPM, impressions, and per-site revenue breakdown. Responses are JSON and mirror the figures shown in your publisher dashboard.
What languages are the code samples in?
The reference includes ready-to-use examples in curl, Python, and JavaScript.
How do I get an API key?
Approved publishers create and manage API keys from the WeForAds dashboard, and can revoke a key at any time.
Can I filter revenue by site?
Yes. Requests accept optional site_id or domain parameters, and the revenue endpoints can return a per-site breakdown.