Skip to main content

PAI Palooza Advertising API

PAI Palooza is AINative Studio's event advertising platform. Event organizers monetize their event pages by selling ad slots; sponsors purchase ad credits and run targeted campaigns. The API covers the complete advertising stack: sponsor registration, creative upload, campaign management, ad serving, impression/click tracking, and payouts.

Base path: https://api.ainative.studio/api/v1/paipalooza

Authentication: All endpoints require Authorization: Bearer <your_api_key> unless explicitly marked as public.


Sponsors​

Sponsors are companies or individuals that purchase ad credits to run campaigns on event pages.

Create sponsor profile​

POST /api/v1/paipalooza/sponsors

Register as a sponsor. Creates a Stripe customer account and initializes a credit balance of 0.

Request body​

{
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"company_name": "Acme AI Corp",
"industry": "Artificial Intelligence",
"website_url": "https://acmeai.example.com",
"contact_email": "ads@acmeai.example.com"
}
FieldTypeRequiredDescription
user_idstring (UUID)YesMust match the authenticated user's ID
company_namestringYesCompany or advertiser name
industrystringNoIndustry category
website_urlstringNoCompany website
contact_emailstringYesContact email for billing and notifications

Response 201 Created​

{
"id": "sponsor_abc123",
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"company_name": "Acme AI Corp",
"industry": "Artificial Intelligence",
"website_url": "https://acmeai.example.com",
"contact_email": "ads@acmeai.example.com",
"stripe_customer_id": "cus_abc123xyz",
"credit_balance": 0,
"auto_reload_enabled": false,
"auto_reload_threshold": null,
"auto_reload_amount": null,
"created_at": "2026-04-25T14:00:00Z"
}

Get sponsor profile​

GET /api/v1/paipalooza/sponsors/{sponsor_id}

Retrieve sponsor profile including current credit balance.

Path parameters​

ParameterTypeRequiredDescription
sponsor_idstringYesSponsor ID

Response 200 OK​

Returns a SponsorResponse object (same shape as create response).


Update sponsor profile​

PATCH /api/v1/paipalooza/sponsors/{sponsor_id}

Update sponsor information. Only the sponsor owner or an admin can update.

Updatable fields: company_name, industry, website_url, contact_email, auto_reload_enabled, auto_reload_threshold, auto_reload_amount.


Purchase ad credits​

POST /api/v1/paipalooza/sponsors/{sponsor_id}/purchase-credits

Purchase ad credits via Stripe. 1 credit = $1 USD.

The flow:

  1. This endpoint creates a Stripe payment intent and returns a client_secret.
  2. Your frontend completes the payment using Stripe.js.
  3. Credits are automatically added to the sponsor's balance via Stripe webhook.

Request body​

{
"sponsor_id": "sponsor_abc123",
"amount": 500,
"payment_method_id": "pm_stripe_test_method"
}
FieldTypeRequiredDescription
sponsor_idstringYesMust match the path parameter
amountintegerYesNumber of credits to purchase (= USD amount)
payment_method_idstringYesStripe payment method ID

Response 200 OK​

{
"payment_intent_id": "pi_abc123",
"client_secret": "pi_abc123_secret_xyz",
"amount": 500,
"status": "requires_confirmation"
}

Get ad credits balance​

GET /api/v1/paipalooza/sponsors/{sponsor_id}/ad-credits

Get current credit balance and usage summary.

Response 200 OK​

{
"sponsor_id": "sponsor_abc123",
"total_credits_purchased": 1500,
"credits_used": 342,
"remaining_balance": 1158,
"total_usd_spent": 342.00,
"auto_reload_enabled": false,
"auto_reload_threshold": null,
"low_balance_alert": false
}

Get usage breakdown by campaign​

GET /api/v1/paipalooza/sponsors/{sponsor_id}/usage-breakdown

Get per-campaign credit usage for a given time period.

Query parameters​

ParameterTypeDefaultDescription
time_periodstringlast_30_dayslast_7_days, last_30_days, last_90_days, or all_time

Response 200 OK​

{
"sponsor_id": "sponsor_abc123",
"time_period": "last_30_days",
"campaigns": [
{
"campaign_id": "camp_abc123",
"campaign_name": "AI Conference Q1 2026",
"credits_used": 200,
"impressions": 10000,
"clicks": 320,
"ctr": 0.032,
"average_cpm": 20.00
}
]
}

Ad Creatives​

Creatives are the ad assets (video, banner, or native) that run inside campaigns. All creatives start in pending_review status and must be approved before they can serve.

Creative statuses​

StatusMeaning
pending_reviewAwaiting admin approval
approvedActive and available for serving
rejectedRejected by admin; cannot serve

Upload video creative​

POST /api/v1/paipalooza/ad-creatives/video

Upload a video ad. The pipeline transcodes the video to 720p and 1080p, extracts a thumbnail, and generates a VAST 4.2 XML document.

Content-Type: multipart/form-data

Form fields​

FieldTypeRequiredDescription
video_filefileYesMP4, MOV, or WebM; max 500 MB
titlestringYesCreative title (3–200 characters)
call_to_actionstringYesCTA text (e.g., Register Now, Learn More, Watch Now)
destination_urlstringYesClick destination (must be HTTPS)
descriptionstringNoCreative description (max 1000 characters)
duration_secondsintegerNoVideo duration in seconds (5–120); auto-detected if omitted

Response 201 Created​

{
"id": "creative_def456",
"sponsor_id": "sponsor_abc123",
"type": "video",
"status": "pending_review",
"title": "Acme AI — Register Now",
"call_to_action": "Register Now",
"destination_url": "https://acmeai.example.com/register",
"duration_seconds": 30,
"video_url": "https://r2.example.com/videos/creative_def456_original.mp4",
"transcoded_urls": {
"720p": "https://r2.example.com/videos/creative_def456_720p.mp4",
"1080p": "https://r2.example.com/videos/creative_def456_1080p.mp4"
},
"thumbnail_url": "https://r2.example.com/thumbnails/creative_def456.jpg",
"vast_xml_url": "https://api.ainative.studio/api/v1/paipalooza/ad-creatives/creative_def456/vast.xml",
"vast_tracking_urls": {
"impression": "https://api.ainative.studio/api/v1/paipalooza/tracking/impression",
"start": "...",
"complete": "..."
},
"created_at": "2026-04-25T14:00:00Z"
}

Example​

curl -X POST https://api.ainative.studio/api/v1/paipalooza/ad-creatives/video \
-H "Authorization: Bearer $API_KEY" \
-F "video_file=@/path/to/ad.mp4" \
-F "title=Acme AI — Register Now" \
-F "call_to_action=Register Now" \
-F "destination_url=https://acmeai.example.com/register"
with open("/path/to/ad.mp4", "rb") as f:
resp = requests.post(
"https://api.ainative.studio/api/v1/paipalooza/ad-creatives/video",
headers={"Authorization": f"Bearer {api_key}"},
data={
"title": "Acme AI — Register Now",
"call_to_action": "Register Now",
"destination_url": "https://acmeai.example.com/register",
},
files={"video_file": f}
)
creative = resp.json()

Upload banner creative​

POST /api/v1/paipalooza/ad-creatives/banner

Upload a banner image. Dimensions must exactly match the declared IAB standard size.

Content-Type: multipart/form-data

IAB standard sizes​

ad_size valueDimensionsCommon use
300x250300 × 250Medium Rectangle — inline content
728x90728 × 90Leaderboard — top of page
320x50320 × 50Mobile Banner — bottom sticky
160x600160 × 600Wide Skyscraper — sidebar
970x250970 × 250Billboard — homepage takeover

Form fields​

FieldTypeRequiredDescription
image_filefileYesJPG, PNG, or GIF; max 5 MB
titlestringYesCreative title (3–200 characters)
call_to_actionstringYesCTA text
destination_urlstringYesClick destination (HTTPS)
ad_sizestringYesOne of the IAB sizes above
descriptionstringNoCreative description

Response 201 Created​

{
"id": "creative_banner789",
"sponsor_id": "sponsor_abc123",
"type": "banner",
"status": "pending_review",
"title": "Acme AI Leaderboard",
"ad_size": "728x90",
"width": 728,
"height": 90,
"banner_url": "https://r2.example.com/banners/creative_banner789.jpg",
"is_animated": false,
"destination_url": "https://acmeai.example.com/register",
"created_at": "2026-04-25T14:05:00Z"
}

Create native creative​

POST /api/v1/paipalooza/ad-creatives/native

Create a text-based native ad that blends into content feeds. An optional image can be uploaded.

Content-Type: multipart/form-data

Form fields​

FieldTypeRequiredConstraints
titlestringYes10–60 characters
descriptionstringYes30–200 characters
call_to_actionstringYesMax 20 characters
destination_urlstringYesHTTPS
sponsor_namestringNoMax 50 characters
sponsor_logo_urlstringNoHTTPS URL
image_filefileNoJPG, PNG, or GIF; max 5 MB

Response 201 Created​

{
"id": "creative_native001",
"sponsor_id": "sponsor_abc123",
"type": "native",
"status": "pending_review",
"title": "Build smarter AI agents",
"description": "AINative Studio gives you the tools to ship AI-native apps in days, not months.",
"call_to_action": "Start Free Trial",
"destination_url": "https://ainative.studio/signup",
"sponsor_name": "AINative Studio",
"image_url": null,
"created_at": "2026-04-25T14:08:00Z"
}

List creatives​

GET /api/v1/paipalooza/ad-creatives

List your creatives with optional filtering.

Query parameters​

ParameterTypeDefaultDescription
statusstring—pending_review, approved, or rejected
typestring—video, banner, or native
skipinteger0Pagination offset
limitinteger20Results per page

Response 200 OK​

{
"creatives": [
{
"id": "creative_def456",
"type": "video",
"status": "approved",
"title": "Acme AI — Register Now"
}
],
"total": 3,
"skip": 0,
"limit": 20
}

Get creative​

GET /api/v1/paipalooza/ad-creatives/{creative_id}

Get full details for a specific creative. You must own the creative.


Update creative metadata​

PUT /api/v1/paipalooza/ad-creatives/{creative_id}

Update title, description, CTA, or destination URL. Only pending_review creatives can be updated; approved or rejected creatives are locked.

Request body​

{
"title": "Acme AI — Join Us Today",
"destination_url": "https://acmeai.example.com/join"
}

Delete creative​

DELETE /api/v1/paipalooza/ad-creatives/{creative_id}

Delete a creative. Only pending_review creatives can be deleted. Returns 204 No Content.


Get VAST 4.2 XML​

GET /api/v1/paipalooza/ad-creatives/{creative_id}/vast.xml

Public endpoint — no auth required. Serves an IAB VAST 4.2 compliant XML document for video ad players. Only works for approved creatives.

Response Content-Type: application/xml

<?xml version="1.0" encoding="UTF-8"?>
<VAST version="4.2">
<Ad id="creative_def456">
<InLine>
<AdTitle>Acme AI — Register Now</AdTitle>
<Creatives>
<Creative>
<Linear>
<Duration>00:00:30</Duration>
<MediaFiles>
<MediaFile type="video/mp4" width="1280" height="720">
https://r2.example.com/videos/creative_def456_720p.mp4
</MediaFile>
</MediaFiles>
<VideoClicks>
<ClickThrough>https://acmeai.example.com/register</ClickThrough>
</VideoClicks>
</Linear>
</Creative>
</Creatives>
</InLine>
</Ad>
</VAST>

Campaigns​

Campaigns tie together a sponsor, one or more approved creatives, a budget, a date range, and optional targeting rules.

Campaign statuses​

StatusDescription
draftNot yet serving; can be edited
activeServing ads; credits are being consumed
pausedTemporarily stopped; budget is still reserved
completedEnd date reached or budget exhausted
cancelledManually cancelled

Create a campaign​

POST /api/v1/paipalooza/campaigns/

Create a new campaign. New campaigns start in draft status.

Request body​

{
"sponsor_id": "sponsor_abc123",
"name": "AI Conference Q1 2026",
"creative_ids": ["creative_def456"],
"budget_credits": 1000,
"start_date": "2026-05-01T00:00:00Z",
"end_date": "2026-06-30T23:59:59Z",
"targeting": {
"event_types": ["conference", "hackathon"],
"topics": ["AI", "machine learning"],
"locations": ["San Francisco", "New York"],
"min_attendees": 50,
"max_attendees": null
}
}
FieldTypeRequiredDescription
sponsor_idstringYesSponsor ID (must own the sponsor account)
namestringYesCampaign name
creative_idsarray[string]YesOne or more approved creative IDs
budget_creditsintegerYesTotal credits to allocate (1 credit = $1)
start_datedatetimeYesCampaign start (must be in the future)
end_datedatetimeYesCampaign end (must be after start)
targetingobjectNoTargeting rules — null means target all events
targeting.event_typesarray[string]NoMatch events by type
targeting.topicsarray[string]NoMatch events by topic via semantic similarity (threshold ≥ 0.7)
targeting.locationsarray[string]NoMatch events by location (case-insensitive)
targeting.min_attendeesintegerNoMinimum attendee threshold
targeting.max_attendeesintegerNoMaximum attendee threshold

Response 201 Created​

{
"id": "camp_abc123",
"sponsor_id": "sponsor_abc123",
"name": "AI Conference Q1 2026",
"status": "draft",
"creative_ids": ["creative_def456"],
"budget_credits": 1000,
"spent_credits": 0,
"remaining_credits": 1000,
"start_date": "2026-05-01T00:00:00Z",
"end_date": "2026-06-30T23:59:59Z",
"targeting": {
"event_types": ["conference", "hackathon"],
"topics": ["AI", "machine learning"],
"locations": ["San Francisco", "New York"]
},
"created_at": "2026-04-25T14:00:00Z"
}

Errors​

CodeReason
400Invalid dates, or start date is in the past
402Insufficient credits
403Creative does not belong to this sponsor
404Sponsor or creative not found

Example​

curl -X POST https://api.ainative.studio/api/v1/paipalooza/campaigns/ \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"sponsor_id": "sponsor_abc123",
"name": "AI Conference Q1 2026",
"creative_ids": ["creative_def456"],
"budget_credits": 1000,
"start_date": "2026-05-01T00:00:00Z",
"end_date": "2026-06-30T23:59:59Z"
}'
resp = requests.post(
"https://api.ainative.studio/api/v1/paipalooza/campaigns/",
headers={"Authorization": f"Bearer {api_key}"},
json={
"sponsor_id": "sponsor_abc123",
"name": "AI Conference Q1 2026",
"creative_ids": ["creative_def456"],
"budget_credits": 1000,
"start_date": "2026-05-01T00:00:00Z",
"end_date": "2026-06-30T23:59:59Z",
}
)
campaign = resp.json()

Get campaign​

GET /api/v1/paipalooza/campaigns/{campaign_id}

Retrieve full campaign details including budget tracking.


List campaigns​

GET /api/v1/paipalooza/campaigns/

List campaigns with filtering, sorting, and pagination.

Query parameters​

ParameterTypeRequiredDefaultDescription
sponsor_idstringYes—Filter by sponsor
statusstringNo—draft, active, paused, completed, or cancelled
creative_idstringNo—Filter to campaigns using this creative
event_typestringNo—Filter by event type targeting
start_date_fromdatetimeNo—Campaigns starting on or after (ISO 8601)
start_date_todatetimeNo—Campaigns starting on or before (ISO 8601)
searchstringNo—Search in campaign name
sort_bystringNocreated_atcreated_at, start_date, budget_credits, or name
sort_orderstringNodescasc or desc
offsetintegerNo0Pagination offset
limitintegerNo20Results per page (max 100)

Response 200 OK​

{
"campaigns": [...],
"total": 5,
"limit": 20,
"offset": 0,
"has_more": false
}

Update campaign​

PATCH /api/v1/paipalooza/campaigns/{campaign_id}

Update a draft or paused campaign. Active and completed campaigns cannot be modified. You can increase budget_credits or extend end_date, but cannot shorten the campaign or change the start_date.


Activate campaign​

POST /api/v1/paipalooza/campaigns/{campaign_id}/activate

Transition a draft campaign to active. The campaign will begin serving ads immediately based on its targeting configuration.

Requirements: Campaign must be in draft status; all creatives must still be approved.


Pause campaign​

POST /api/v1/paipalooza/campaigns/{campaign_id}/pause

Stop a running campaign. No new impressions will be served, but the budget remains reserved.

Query parameters​

ParameterTypeRequiredDescription
sponsor_idstringYesSponsor ID for authorization

Resume campaign​

POST /api/v1/paipalooza/campaigns/{campaign_id}/resume

Resume a paused campaign. Requires sufficient credits for the daily budget.

Query parameters​

ParameterTypeRequiredDescription
sponsor_idstringYesSponsor ID for authorization

Preview targeting​

GET /api/v1/paipalooza/campaigns/{campaign_id}/preview-targeting

Before activating, preview which published events match the campaign's targeting criteria.

Query parameters​

ParameterTypeDefaultDescription
limitinteger50Max matching events to return (max 100)

Response 200 OK​

{
"campaign_id": "camp_abc123",
"targeting": {
"event_types": ["conference"],
"topics": ["AI"]
},
"matching_events": [
{
"id": "evt_001",
"title": "AI Summit 2026",
"event_type": "conference"
}
],
"total_matched": 12,
"similarity_scores": {
"evt_001": 0.92
}
}

Campaign & Creative Analytics​

Get campaign performance​

GET /api/v1/paipalooza/campaigns/{campaign_id}/performance

Get comprehensive performance metrics for a campaign.

Query parameters​

ParameterTypeDefaultDescription
time_rangestring7d24h, 7d, 30d, or custom
start_datedatetime—Required when time_range=custom
end_datedatetime—Required when time_range=custom
include_creativesbooleantrueInclude per-creative breakdown
include_eventsbooleantrueInclude per-event breakdown

Response 200 OK​

{
"campaign": {
"campaign_id": "camp_abc123",
"impressions": 50000,
"clicks": 1600,
"completions": 8500,
"ctr": 0.032,
"completion_rate": 0.17,
"total_spend": 100.00,
"average_cpm": 2.00,
"average_cpc": 0.063
},
"by_creative": [
{
"creative_id": "creative_def456",
"impressions": 50000,
"clicks": 1600,
"ctr": 0.032
}
],
"by_event": [
{
"event_id": "evt_001",
"impressions": 30000,
"revenue": 60.00,
"fill_rate": 0.85
}
],
"time_range": "7d",
"generated_at": "2026-04-25T15:00:00Z"
}

Export campaign performance as CSV​

GET /api/v1/paipalooza/campaigns/{campaign_id}/performance/export

Export campaign performance as a CSV file. Accepts the same query parameters as the performance endpoint.

Response 200 OK​

{
"filename": "campaign_camp_abc123_7d_2026-04-25.csv",
"content": "type,id,name,impressions,clicks,completions,ctr,completion_rate,spend\n...",
"row_count": 12,
"generated_at": "2026-04-25T15:00:00Z"
}

Get creative performance​

GET /api/v1/paipalooza/campaigns/creative/{creative_id}/performance

Get detailed performance analytics for a specific creative across all campaigns.

Query parameters​

ParameterTypeDefaultDescription
time_rangestring7d24h, 7d, 30d, or custom
campaign_idstring—Scope to a specific campaign
include_dailybooleantrueInclude daily time series
include_by_campaignbooleantrueInclude breakdown by campaign

Compare creatives​

GET /api/v1/paipalooza/campaigns/creatives/compare

Compare up to 10 creatives side-by-side, ranked by CTR.

Query parameters​

ParameterTypeRequiredDescription
creative_idsarray[string]YesList of creative IDs to compare (max 10)
time_rangestringNo24h, 7d, 30d, or custom

Response 200 OK​

{
"creatives": [
{
"creative_id": "creative_def456",
"impressions": 50000,
"clicks": 1600,
"ctr": 0.032,
"rank": 1
},
{
"creative_id": "creative_banner789",
"impressions": 30000,
"clicks": 450,
"ctr": 0.015,
"rank": 2
}
],
"best_performing": "creative_def456",
"total_creatives": 2,
"time_range": "7d",
"generated_at": "2026-04-25T15:00:00Z"
}

Get event performance (organizer view)​

GET /api/v1/paipalooza/campaigns/event/{event_id}/performance

Ad revenue analytics for a specific event — designed for event organizers to see how much their event is earning from ad placements.

Query parameters​

ParameterTypeDefaultDescription
time_rangestring7d24h, 7d, 30d, or custom
include_dailybooleantrueDaily revenue time series
include_sponsorsbooleantrueTop sponsors by spend

Response 200 OK​

{
"event": {
"event_id": "evt_001",
"impressions": 80000,
"unique_impressions": 65000,
"clicks": 2560,
"completions": 12800,
"ctr": 0.032,
"completion_rate": 0.16,
"total_revenue": 160.00,
"average_rpm": 2.00,
"fill_rate": 0.87
},
"daily_revenue": [
{ "date": "2026-04-19", "revenue": 22.40 },
{ "date": "2026-04-20", "revenue": 28.60 }
],
"top_sponsors": [
{ "sponsor_id": "sponsor_abc123", "spend": 100.00 }
],
"time_range": "7d",
"generated_at": "2026-04-25T15:00:00Z"
}

Compare events​

GET /api/v1/paipalooza/campaigns/events/compare

Compare up to 10 events side-by-side, ranked by revenue.

Query parameters​

ParameterTypeRequiredDescription
event_idsarray[string]YesEvent IDs to compare (max 10)
time_rangestringNo24h, 7d, 30d, or custom

Ad Serving​

Serve an ad​

POST /api/v1/paipalooza/ads/serve

Public endpoint — no auth required. Called by the frontend ad widget when an event page loads. Returns the best-matched ad for the given placement, or 204 No Content if no eligible ads are available.

Rate limit: 10,000 requests/minute per IP.

Request body​

{
"event_id": "evt_001",
"placement": "header",
"device_type": "desktop"
}
FieldTypeRequiredDescription
event_idstringYesID of the event page requesting an ad
placementstringYesAd slot: header, sidebar, content, or video
device_typestringYesdesktop, mobile, or tablet

Response 200 OK — ad found​

{
"ad_id": "ad_xyz789abc123",
"creative_id": "creative_def456",
"campaign_id": "camp_abc123",
"creative_type": "video",
"creative_data": {
"title": "AI Conference 2026",
"video_url": "https://r2.example.com/videos/creative_def456_720p.mp4",
"thumbnail_url": "https://r2.example.com/thumbnails/creative_def456.jpg",
"duration_seconds": 30,
"call_to_action": "Register Now",
"destination_url": "https://acmeai.example.com/register"
},
"tracking_urls": {
"impression_url": "https://api.ainative.studio/api/v1/paipalooza/tracking/impression",
"click_url": "https://api.ainative.studio/api/v1/paipalooza/tracking/click",
"completion_url": "https://api.ainative.studio/api/v1/paipalooza/tracking/completion"
}
}

Response 204 No Content​

No eligible ads are available for this placement.

Example​

// Frontend ad widget
const resp = await fetch("https://api.ainative.studio/api/v1/paipalooza/ads/serve", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
event_id: "evt_001",
placement: "header",
device_type: "desktop"
})
});

if (resp.status === 204) {
// No ad available — hide ad slot
return;
}

const ad = await resp.json();
// Render ad using ad.creative_data
// Fire impression beacon to ad.tracking_urls.impression_url

Tracking​

All tracking endpoints are public — no authentication required. They are designed to be called by ad widgets and VAST-compatible video players.

Rate limit: 1,000 requests/minute per IP for all tracking endpoints.

Track impression​

POST /api/v1/paipalooza/tracking/impression

Record that an ad was displayed. Deduplicates within 24 hours per authenticated user.

Credit costs per placement​

PlacementCost per impression
header$0.02
sidebar$0.01
content$0.015
video$0.03
footer$0.005

Request body​

{
"campaign_id": "camp_abc123",
"creative_id": "creative_def456",
"event_id": "evt_001",
"placement": "header",
"user_id": "550e8400-e29b-41d4-a716-446655440000"
}
FieldTypeRequiredDescription
campaign_idstringYesActive campaign ID
creative_idstringYesApproved creative ID assigned to the campaign
event_idstringYesEvent page where the ad was shown
placementstringYesheader, sidebar, content, video, or footer
user_idstring (UUID)NoAuthenticated viewer (for deduplication)

Response 201 Created​

{
"impression_id": "imp_abc123xyz",
"campaign_id": "camp_abc123",
"creative_id": "creative_def456",
"event_id": "evt_001",
"placement": "header",
"credits_deducted": 0.02,
"created_at": "2026-04-25T15:00:00Z"
}

Errors​

CodeReason
400Campaign inactive or creative unapproved
404Campaign, creative, or event not found
409Duplicate impression within 24h for this user

Track click​

POST /api/v1/paipalooza/tracking/click

Record that a user clicked an ad. Must reference a valid impression.

Request body​

{
"impression_id": "imp_abc123xyz",
"campaign_id": "camp_abc123",
"creative_id": "creative_def456",
"destination_url": "https://acmeai.example.com/register"
}
FieldTypeRequiredDescription
impression_idstringYesImpression to associate with this click
campaign_idstringYesCampaign ID
creative_idstringYesCreative ID
destination_urlstringYesClick destination URL

Response 201 Created​

{
"click_id": "clk_def456abc",
"impression_id": "imp_abc123xyz",
"campaign_id": "camp_abc123",
"redirect_url": "https://acmeai.example.com/register",
"time_to_click_seconds": 12,
"created_at": "2026-04-25T15:00:12Z"
}

Notes​

  • time_to_click_seconds: seconds elapsed between impression and click
  • Clicks within 30 seconds earn an engagement quality bonus
  • Duplicate clicks for the same impression are rejected with 409

Track video completion​

POST /api/v1/paipalooza/tracking/completion

Track video ad playback milestones. Only applies to video creatives.

Milestones​

Milestonemilestone valueEngagement score
Ad started00.0
25% watched250.25
50% watched500.50
75% watched750.75
100% watched1001.0

Only 100% completion earns a $0.01 credit bonus.

Request body​

{
"impression_id": "imp_abc123xyz",
"campaign_id": "camp_abc123",
"creative_id": "creative_def456",
"milestone": 100
}
FieldTypeRequiredDescription
impression_idstringYesThe originating impression
campaign_idstringYesCampaign ID
creative_idstringYesMust be a video creative
milestoneintegerYes0, 25, 50, 75, or 100

Response 201 Created​

{
"completion_id": "cmp_ghi789jkl",
"impression_id": "imp_abc123xyz",
"campaign_id": "camp_abc123",
"milestone": 100,
"engagement_score": 1.0,
"credits_bonus": 0.01,
"created_at": "2026-04-25T15:00:30Z"
}

Errors​

CodeReason
400Creative is not video type, or campaign is inactive
409Duplicate milestone for this impression

Content Inventory​

Event organizers define ad slot inventory that sponsors can browse and campaigns can fill.

Create inventory​

POST /api/v1/paipalooza/content-inventory/events/{event_id}/inventory

Organizer auth required. Define available ad slots for an event.

Wait — this endpoint path is constructed from the router prefix. Based on the source, the path is:

POST /api/v1/paipalooza/content-inventory

With event_id as a query parameter.

Query parameters​

ParameterTypeRequiredDescription
event_idstringYesEvent to attach inventory to

Request body​

{
"slot_type": "video_preroll",
"format": "video",
"total_slots": 10,
"floor_price": 5.00,
"suggested_price": 8.00
}
FieldTypeRequiredDescription
slot_typestringYesvideo_preroll, banner_sidebar, email_header, content_native, or audio_preroll
formatstringYesvideo, banner, native, or audio
total_slotsintegerYesNumber of available slots (must be > 0)
floor_pricenumberYesMinimum price per slot (USD, >= 0)
suggested_pricenumberYesRecommended price per slot (>= floor_price)

Response 201 Created​

{
"id": "inv_abc001",
"event_id": "evt_001",
"organizer_id": "organizer_xyz",
"slot_type": "video_preroll",
"format": "video",
"total_slots": 10,
"filled_slots": 0,
"available_slots": 10,
"floor_price": 5.00,
"suggested_price": 8.00,
"created_at": "2026-04-25T14:00:00Z"
}

Get inventory​

GET /api/v1/paipalooza/content-inventory/{inventory_id}

Public endpoint. Get inventory details by ID.


List event inventory​

GET /api/v1/paipalooza/content-inventory/events/{event_id}/inventory

Public endpoint. Browse available ad slots for an event — no auth required so sponsors can discover inventory before registering.

Path parameters​

ParameterTypeRequiredDescription
event_idstringYesEvent ID

Query parameters​

ParameterTypeDefaultDescription
formatstring—Filter by format: video, banner, native, or audio
sort_bystringpriceprice or availability
sort_orderstringascasc or desc
limitinteger25Results per page (1–100)
offsetinteger0Pagination offset

Response 200 OK​

{
"items": [
{
"id": "inv_abc001",
"event_id": "evt_001",
"slot_type": "video_preroll",
"format": "video",
"total_slots": 10,
"filled_slots": 3,
"available_slots": 7,
"floor_price": 5.00,
"suggested_price": 8.00
}
],
"total": 4,
"has_more": false
}

Organizers​

Event organizers register to monetize their events through ad revenue.

Create organizer​

POST /api/v1/paipalooza/organizers

Register as an event organizer. Creates a Stripe Connect Express account and sets default revenue share to 60%.

Request body​

{
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"organization_name": "AI Events LLC",
"contact_email": "hello@aievents.example.com",
"contact_phone": "+14155551234"
}
FieldTypeRequiredDescription
user_idstring (UUID)YesMust match authenticated user
organization_namestringYesOrganization name
contact_emailstringYesUsed for Stripe Connect verification
contact_phonestringNoContact phone number

Response 201 Created​

{
"id": "organizer_xyz",
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"organization_name": "AI Events LLC",
"contact_email": "hello@aievents.example.com",
"stripe_connect_account_id": "acct_abc123",
"revenue_share_percentage": 60,
"status": "pending",
"total_revenue_earned": 0.00,
"total_payouts": 0.00,
"created_at": "2026-04-25T14:00:00Z"
}

Errors​

CodeReason
400User already has an organizer account
403user_id does not match authenticated user

Get organizer​

GET /api/v1/paipalooza/organizers/{organizer_id}

Get organizer profile. Accessible only by the organizer themselves or an admin.


Update organizer​

PATCH /api/v1/paipalooza/organizers/{organizer_id}

Update organization_name, contact_email, or contact_phone. Revenue share percentage can only be changed by an admin.


Get organizer revenue​

GET /api/v1/paipalooza/organizers/{organizer_id}/revenue

View revenue metrics and payout status for an organizer.

Query parameters​

ParameterTypeDefaultDescription
daysinteger7Time range in days (1–365)

Response 200 OK​

{
"organizer_id": "organizer_xyz",
"total_revenue_earned": 1500.00,
"total_payouts": 1000.00,
"pending_balance": 500.00,
"payout_eligible": true,
"payout_threshold": 100.00,
"revenue_by_event": [
{
"event_id": "evt_001",
"event_title": "AI Summit 2026",
"revenue": 800.00
}
],
"period_impressions": 400000,
"period_revenue": 350.00,
"period_days": 7
}

Payouts​

Organizers receive 60% of ad revenue (configurable per organizer). Payouts require a minimum pending balance of $100 and a valid Stripe Connect account.

Check payout eligibility​

GET /api/v1/paipalooza/payouts/eligibility/{organizer_id}

Check whether an organizer is eligible for a payout.

Response 200 OK​

{
"organizer_id": "organizer_xyz",
"pending_balance": 500.00,
"payout_threshold": 100.00,
"eligible": true,
"reason": null
}

If not eligible:

{
"organizer_id": "organizer_xyz",
"pending_balance": 42.00,
"payout_threshold": 100.00,
"eligible": false,
"reason": "Pending balance $42.00 is below the $100.00 threshold"
}

Get payout history​

GET /api/v1/paipalooza/payouts/history/{organizer_id}

Retrieve payout history, sorted most recent first.

Query parameters​

ParameterTypeDefaultDescription
limitinteger100Maximum records to return (max 1000)

Response 200 OK​

[
{
"payout_id": "pay_abc001",
"amount": 500.00,
"status": "completed",
"stripe_payout_id": "po_stripe_123",
"created_at": "2026-04-20T10:00:00Z",
"completed_at": "2026-04-22T08:00:00Z",
"failure_reason": null
}
]

Process pending payouts (Admin only)​

POST /api/v1/paipalooza/payouts/process

Admin only. Batch process all eligible organizer payouts. Intended to be called by a scheduled job.

Response 200 OK​

{
"total_checked": 25,
"eligible_count": 8,
"successful_payouts": 7,
"failed_payouts": 1,
"total_amount_paid": 4200.00,
"errors": [
"Organizer organizer_zzz: Stripe Connect account not verified"
]
}

Manual payout (Admin only)​

POST /api/v1/paipalooza/payouts/manual

Admin only. Trigger a payout for a specific organizer, optionally bypassing the $100 minimum threshold.

Request body​

{
"organizer_id": "organizer_xyz",
"override_threshold": false
}
FieldTypeRequiredDescription
organizer_idstringYesOrganizer to pay out
override_thresholdbooleanNoIf true, bypass the $100 minimum balance requirement

Response 201 Created​

{
"payout_id": "pay_abc002",
"organizer_id": "organizer_xyz",
"stripe_payout_id": "po_stripe_456",
"amount": 500.00,
"status": "completed",
"created_at": "2026-04-25T15:00:00Z",
"completed_at": "2026-04-25T15:00:05Z"
}

Errors​

CodeReason
400Organizer has no pending balance
403Admin privileges required