Get Started with Aeion Ads
Set up your ad monetization in 5 steps. Create zones, connect 10 ad networks, build waterfall, run direct campaigns with pacing, and monitor real-time revenue—all in under 20 minutes.
Enable Ads Module & Create Your First Zone
| Format | Name | Size | Responsive |
|---|---|---|---|
| `300x250` | Medium Rectangle | 300×250 | No |
| `728x90` | Leaderboard | 728×90 | No |
| `160x600` | Skyscraper | 160×600 | No |
| `300x600` | Wide Skyscraper | 300×600 | No |
| `320x50` | Mobile Leaderboard | 320×50 | Yes |
| `300x50` | Mobile Banner | 300×50 | Yes |
| `native` | Native | Fluid | Yes |
Connect Ad Networks
Go to Ads → Networks → Add Network.
Available Networks: Google AdSense, Meta Audience Network, Amazon Associates, Taboola, Outbrain, Media.net, PropellerAds, Ezoic, Infolinks, BuySellAds
Connect Google AdSense (API):
bash
POST /ads/networks
{
"name": "Google AdSense",
"adapter": "adsense",
"status": "active",
"priority": 1,
"floorEcpm": 0.50,
"timeoutMs": 2000,
"credentials": {
"publisherId": "pub-1234567890123456",
"slotId": "1234567890"
}
}
Network Configuration (API):
bash
POST /ads/networks
{
"name": "Amazon Publisher Services",
"adapter": "amazon",
"status": "active",
"priority": 2,
"floorEcpm": 0.30,
"timeoutMs": 3000,
"credentials": {
"apiKey": "amzn-xxxx",
"adSlotId": "aps-slot-xxx"
}
}
Set Network Waterfall Order (API):
bash
PATCH /ads/zones/{zoneId}
{
"waterfall": [
{ "networkId": "network-xxx", "weight": 1.0 },
{ "networkId": "network-yyy", "weight": 0.8, "minEcpm": 0.50 },
{ "networkId": "network-zzz", "weight": 0.5 }
]
}
Response:
typescript
{
"id": "zone-xxx",
"waterfall": [
{ "networkId": "network-xxx", "weight": 1.0, "order": 1 },
{ "networkId": "network-yyy", "weight": 0.8, "minEcpm": 0.50, "order": 2 },
{ "networkId": "network-zzz", "weight": 0.5, "order": 3 }
]
}
Network Health (API):
bash
GET /ads/adapters/health
Response:
typescript
{
"networks": [
{ "id": "network-xxx", "name": "Google AdSense", "status": "healthy", "fillRate": 92, "avgEcpm": 2.45, "lastChecked": "2026-05-11T09:00:00Z" },
{ "id": "network-yyy", "name": "Amazon APS", "status": "healthy", "fillRate": 78, "avgEcpm": 1.23, "lastChecked": "2026-05-11T09:00:00Z" }
]
}
ads.txt Auto-Generation (API):
bash
GET /ads/ads-txt
Response:
google.com, pub-1234567890123456, DIRECT, f08c47fec1f5a0
amazon.com, pub-1234567890123456, RESELLER, amzn-ssp-advertising
SPA/SSR Support: For Single Page Apps, add <meta name="google-adsense-account" content="pub-1234567890"> to <head>. For SSR, serve from /ads.txt endpoint.
Create a Direct-Sold Campaign
| Model | Rate Unit | Description |
|---|---|---|
| `cpm` | $/1,000 impressions | Cost per thousand impressions |
| `cpc` | $/click | Cost per click |
| `cpa` | $/conversion | Cost per conversion action |
| `flat` | $/day or $/month | Flat-rate guaranteed delivery |
Approve & Launch
Approve Creative (API):
bash
POST /ads/creatives/{creativeId}/approve
{
"reviewNotes": "Looks good" // optional
}
Approve Campaign (API):
bash
POST /ads/campaigns/{campaignId}/approve
Response:
typescript
{
"id": "campaign-xxx",
"status": "active",
"startDate": "2026-05-15",
"endDate": "2026-06-15",
"pacing": "even"
}
Manage Campaign Status (API):
```bash # Pause a running campaign POST /ads/campaigns/{campaignId}/pause
# Resume a paused campaign POST /ads/campaigns/{campaignId}/resume
# Complete a campaign manually POST /ads/campaigns/{campaignId}/complete
# Cancel a campaign (no dedicated action route — update status directly) PATCH /ads/campaigns/{campaignId} { "status": "cancelled" } ```
Status Lifecycle:
draft → scheduled → active → paused → completed
↓
cancelled
Update Campaign Budget (API):
bash
PATCH /ads/campaigns/{campaignId}
{
"budget": 15000,
"dailyBudget": 500
}
Update Line Item Targeting (API):
bash
PATCH /ads/line-items/{lineItemId}
{
"targeting": {
"countries": ["US", "CA", "GB", "AU"],
"devices": ["desktop", "tablet", "mobile"]
},
"frequencyCap": 5
}
Monitor & Optimize
Go to Ads → Analytics.
Get Dashboard Metrics (API):
bash
GET /ads/analytics/dashboard?dateRange=last_30_days
Response:
typescript
{
"totalImpressions": 1245000,
"totalClicks": 18675,
"totalRevenue": 3456.78, // dollars
"ctr": 1.50,
"ecpm": 2.78,
"viewabilityRate": 68.5,
"totalViewable": 852825
}
Get Zone Metrics (API):
bash
GET /ads/analytics/zones?dateRange=last_30_days
Response:
typescript
{
"zones": [
{ "zone": "header-leaderboard", "impressions": 450000, "clicks": 7200, "revenue": 1425.00, "ecpm": 3.17, "ctr": 1.60 },
{ "zone": "tech-blog-sidebar", "impressions": 320000, "clicks": 4800, "revenue": 896.00, "ecpm": 2.80, "ctr": 1.50 }
]
}
Get Network Metrics (API):
bash
GET /ads/analytics/networks?dateRange=last_30_days
Response:
typescript
{
"networks": [
{ "network": "Google AdSense", "impressions": 890000, "clicks": 13400, "revenue": 2345.00, "ecpm": 2.63, "fillRate": 92 },
{ "network": "Amazon APS", "impressions": 210000, "clicks": 3150, "revenue": 462.00, "ecpm": 2.20, "fillRate": 78 }
]
}
Get Campaign Delivery Report (API):
bash
GET /ads/campaigns/{campaignId}/delivery
Response:
typescript
{
"impressions": 45000,
"clicks": 675,
"conversions": 23,
"ctr": 1.50,
"cvr": 3.41,
"spend": 382.50,
"remainingBudget": 9617.50,
"lineItemBreakdown": [
{ "lineItemId": "li-xxx", "name": "Tech Blog - Sidebar", "impressions": 45000, "clicks": 675, "spend": 382.50 }
],
"dailyDelivery": [
{ "date": "2026-05-15", "impressions": 3200, "clicks": 48, "spend": 27.20 },
{ "date": "2026-05-16", "impressions": 4100, "clicks": 62, "spend": 34.85 }
]
}
Get Pacing Analysis (API):
bash
GET /ads/campaigns/{campaignId}/pacing
Response:
typescript
{
"daysElapsed": 5,
"daysRemaining": 25,
"totalDays": 30,
"expectedDelivery": 16.67, // % of budget expected spent
"actualDelivery": 14.80, // % of budget actually spent
"paceStatus": "under_delivering",
"adjustmentNeeded": 187.00 // Need to spend $187 more to get on track
}
Run Waterfall Optimization (AI) (API):
bash
POST /ads/analytics/optimize/waterfall/{zoneId}
Response:
typescript
{
"previousOrder": ["google", "amazon", "taboola"],
"newOrder": ["amazon", "google", "taboola"],
"estimatedRevenueIncrease": 12.5 // % increase from reordering
}
Run A/B Test for Creatives (API):
bash
POST /ads/analytics/optimize/ab-test/{lineItemId}
Response:
typescript
{
"status": "testing",
"creatives": [
{ "creativeId": "creative-xxx", "impressions": 15000, "clicks": 300, "ctr": 2.00, "confidence": 91 },
{ "creativeId": "creative-yyy", "impressions": 14800, "clicks": 222, "ctr": 1.50, "confidence": 88 }
],
"winner": {
"creativeId": "creative-xxx",
"ctr": 2.00,
"improvementPct": 33.3 // 33.3% better CTR than loser
}
}
Auto-pause low-CTR creatives + smart pacing run automatically as part of daily optimization — there's no standalone per-creative or per-campaign endpoint for them. Trigger the full daily pass on demand (it also reorders every active zone's waterfall):
bash
POST /ads/analytics/optimize/run-daily
Response:
typescript
{
"waterfallsOptimized": 4,
"creativesPaused": 2, // low-CTR creatives auto-paused this run
"campaignsPaced": 6 // active campaigns re-evaluated for pacing
}
Auto-pause reasoning (e.g. "CTR 0.08% below 0.1% threshold after 5000 impressions") and per-campaign pacing detail (current vs. target pace, recommended adjustment) show up in the admin's optimization log — Admin → Ads → Optimization.
Quick Reference
Zone API:
```bash # Create zone POST /ads/zones
# List zones GET /ads/zones
# Update waterfall PATCH /ads/zones/{zoneId}
# Network health GET /ads/adapters/health
# ads.txt GET /ads/ads-txt ```
Campaign API:
```bash # Create campaign POST /ads/campaigns
# Approve campaign POST /ads/campaigns/{campaignId}/approve
# Pause/resume/complete POST /ads/campaigns/{campaignId}/pause POST /ads/campaigns/{campaignId}/resume POST /ads/campaigns/{campaignId}/complete
# Update budget, or cancel via status PATCH /ads/campaigns/{campaignId}
# Get delivery report GET /ads/campaigns/{campaignId}/delivery
# Get pacing analysis GET /ads/campaigns/{campaignId}/pacing ```
Line Item API:
```bash # Create line item POST /ads/campaigns/{campaignId}/line-items
# Update targeting PATCH /ads/line-items/{lineItemId} ```
Creative API:
```bash # Upload creative POST /ads/creatives
# Approve/reject POST /ads/creatives/{creativeId}/approve POST /ads/creatives/{creativeId}/reject
# Preview rendered creative GET /ads/creatives/{creativeId}/preview ```
Network API:
```bash # Connect network POST /ads/networks
# List networks GET /ads/networks
# Update config PATCH /ads/networks/{networkId} ```
Analytics API:
```bash # Dashboard metrics GET /ads/analytics/dashboard?dateRange=last_30_days
# Zone metrics GET /ads/analytics/zones
# Network metrics GET /ads/analytics/networks
# Hourly breakdown GET /ads/analytics/hourly?dateRange=today
# Daily trend GET /ads/analytics/daily-trend?dateRange=last_7_days ```
Optimization API:
```bash # Waterfall optimization POST /ads/analytics/optimize/waterfall/{zoneId}
# A/B test POST /ads/analytics/optimize/ab-test/{lineItemId}
# Daily orchestration (waterfall reorder + auto-pause + smart pacing) POST /ads/analytics/optimize/run-daily ```
Advertiser API:
```bash # Create advertiser POST /ads/advertisers
# List advertisers GET /ads/advertisers
# Billing / statement GET /ads/advertisers/{advertiserId}/billing ```
FAQ
Every request checks sources in order: (1) direct-sold campaigns → (2) your connected network waterfall (ranked by real yield) → (3) house ads → (4) fallback HTML. Impression recording happens in the background so it never slows down the ad itself.
Aeion runs a statistically rigorous chi-square significance test on your creatives automatically. A difference is called out once it's statistically significant — no manual math, no exported spreadsheets. Minimum 1,000 impressions before evaluation.
Networks are ranked by real earning potential, not just headline eCPM. A network with a high eCPM but near-zero fill gets penalized, while a network with a lower eCPM but strong fill rate ranks higher — e.g., a $2 eCPM network at 80% fill outranks a $5 eCPM network at 2% fill.
Every impression is scored across multiple signals — VPN/proxy traffic, bot user agents, missing referrers, suspicious click patterns — and blocked automatically before it's ever billed if it crosses a safe risk threshold.
Per-user impression limit over a configurable window. e.g., a cap of 5 with a 24-hour window means a given visitor sees at most 5 impressions of that ad per day. Applies per line item.
Aeion continuously compares how much of your budget you've spent to how much of the flight has elapsed. If you're falling meaningfully behind pace, it recommends a budget increase; if you're running meaningfully ahead, it recommends dialing back.
`300x250`, `728x90`, `160x600`, `300x600`, `320x50`, `300x50`, `native`, custom. Image, video, HTML, and native creative types.
Multiple creatives per line item → weighted random. Higher weight = higher probability of selection. e.g., weights [60, 40] → 60% chance of first creative.
CPM (cost per 1,000 impressions), CPC (cost per click), CPA (cost per conversion), flat (per day/month). Revenue is calculated automatically based on whichever model you choose.
Aeion won't let you launch a new campaign for an advertiser account that's been suspended or closed — checked automatically at campaign creation.
Total impressions, clicks, and revenue, plus CTR, eCPM, and viewability rate — broken down by zone, network, campaign, page, and time (hourly/daily buckets).
Aeion reads your connected network credentials and keeps your ads.txt file automatically up to date in the standard format ad networks expect. SPA via meta tag, SSR via `/ads.txt` endpoint.
Aeion checks the visitor's consent status before serving personalized ads. Consent states: Personalized, Contextual, Limited. Right to erasure anonymizes impression records. Configurable data retention period.
Every impression and conversion is recorded to an append-only history — nothing is edited or deleted after the fact, so your reporting and any advertiser audit trail stay trustworthy.