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
statusstringpending_review, approved, or rejected
typestringvideo, 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_idstringYesFilter by sponsor
statusstringNodraft, active, paused, completed, or cancelled
creative_idstringNoFilter to campaigns using this creative
event_typestringNoFilter by event type targeting
start_date_fromdatetimeNoCampaigns starting on or after (ISO 8601)
start_date_todatetimeNoCampaigns starting on or before (ISO 8601)
searchstringNoSearch 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_datedatetimeRequired when time_range=custom
end_datedatetimeRequired 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_idstringScope 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
formatstringFilter 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