API Reference
Complete REST API reference for the Scrya in-game advertising platform. All endpoints use JSON request/response bodies and require authentication.
Base URL
https://api.scrya.com/api/ads Authentication
Every request must include a Bearer token in the Authorization header. Obtain your API key from the Scrya dashboard.
Authorization: Bearer YOUR_API_KEY Requests without a valid token receive 401 Unauthorized.
Response Format
All responses are JSON. Successful mutations return the created/updated object. List endpoints return arrays. Errors return:
{
"detail": "Human-readable error message"
} Common status codes: 200 success, 201 created, 204 no content, 400 bad request, 401 unauthorized, 404 not found, 422 validation error, 429 rate limited.
Endpoints
Advertiser Management
Register as an advertiser, manage your profile, and deposit funds for ad spend.
Register as Advertiser
POST /register Create a new advertiser account. Returns the created profile with your advertiser ID.
Request body:
company_name(string, required) — Your company or brand namecontact_email(string, required) — Primary contact emailwebsite(string, optional) — Company website URL
curl -X POST https://api.scrya.com/api/ads/register \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"company_name": "Acme Corp",
"contact_email": "[email protected]",
"website": "https://acme.com"
}' Response (201):
{
"id": "adv_abc123",
"company_name": "Acme Corp",
"contact_email": "[email protected]",
"website": "https://acme.com",
"balance_cents": 0,
"created_at": "2026-03-01T12:00:00Z"
} Get Profile
GET /profile Retrieve the authenticated advertiser's profile, including current balance.
curl https://api.scrya.com/api/ads/profile \
-H "Authorization: Bearer YOUR_API_KEY" Response (200):
{
"id": "adv_abc123",
"company_name": "Acme Corp",
"contact_email": "[email protected]",
"website": "https://acme.com",
"balance_cents": 500000,
"created_at": "2026-03-01T12:00:00Z"
} Update Profile
PATCH /profile Update advertiser profile fields. Only include fields you want to change.
Request body (all optional):
company_name(string) — Updated company namecontact_email(string) — Updated emailwebsite(string) — Updated website URL
curl -X PATCH https://api.scrya.com/api/ads/profile \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"company_name": "Acme Corporation"
}' Response (200): Returns the updated profile object.
Deposit Ad Spend
POST /deposit Add funds to your advertiser balance. Funds are consumed when impressions are served.
Request body:
amount_cents(integer, required) — Amount to deposit in cents (e.g., 100000 = $1,000.00)
curl -X POST https://api.scrya.com/api/ads/deposit \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"amount_cents": 100000
}' Response (200):
{
"balance_cents": 600000,
"deposited_cents": 100000
} Campaigns
Create and manage advertising campaigns. Campaigns hold budget, targeting rules, and creatives.
Create Campaign
POST /campaigns Create a new campaign. Campaigns start in draft status and must be activated separately.
Request body:
name(string, required) — Campaign namebudget_cents(integer, required) — Total budget in centscpm_bid_cents(integer, required) — CPM bid in cents. Range:100-10000($1.00-$100.00 CPM)daily_cap_cents(integer, optional) — Maximum daily spend in centsstart_date(string, optional) — ISO 8601 start dateend_date(string, optional) — ISO 8601 end datepriority(integer, optional) — Priority level0-10(higher = more likely to win ties). Default:5target_categories(array of strings, optional) — Game categories to target (e.g.,["simulation", "strategy"])target_tags(array of strings, optional) — Content tags to target (e.g.,["political", "military"])
curl -X POST https://api.scrya.com/api/ads/campaigns \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Summer 2026 Launch",
"budget_cents": 500000,
"cpm_bid_cents": 250,
"daily_cap_cents": 25000,
"start_date": "2026-06-01T00:00:00Z",
"end_date": "2026-08-31T23:59:59Z",
"priority": 7,
"target_categories": ["simulation", "strategy"],
"target_tags": ["political"]
}' Response (201):
{
"id": "camp_abc123",
"name": "Summer 2026 Launch",
"status": "draft",
"budget_cents": 500000,
"spent_cents": 0,
"cpm_bid_cents": 250,
"daily_cap_cents": 25000,
"start_date": "2026-06-01T00:00:00Z",
"end_date": "2026-08-31T23:59:59Z",
"priority": 7,
"target_categories": ["simulation", "strategy"],
"target_tags": ["political"],
"created_at": "2026-03-01T12:00:00Z"
} List Campaigns
GET /campaigns List all campaigns for the authenticated advertiser. Returns an array sorted by creation date (newest first).
curl https://api.scrya.com/api/ads/campaigns \
-H "Authorization: Bearer YOUR_API_KEY" Response (200): Array of campaign objects.
Get Campaign Detail
GET /campaigns/{id} Get full details for a single campaign, including spend totals and status.
curl https://api.scrya.com/api/ads/campaigns/camp_abc123 \
-H "Authorization: Bearer YOUR_API_KEY" Response (200): Full campaign object.
Update Campaign
PATCH /campaigns/{id} Update campaign fields. Only include fields you want to change. Cannot change budget below current spend.
Request body (all optional):
name(string)budget_cents(integer)cpm_bid_cents(integer, 100-10000)daily_cap_cents(integer)start_date(string)end_date(string)priority(integer, 0-10)target_categories(array of strings)target_tags(array of strings)
curl -X PATCH https://api.scrya.com/api/ads/campaigns/camp_abc123 \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"budget_cents": 750000,
"cpm_bid_cents": 300
}' Response (200): Updated campaign object.
Activate Campaign
POST /campaigns/{id}/activate Activate a draft or paused campaign. The campaign must have at least one creative and sufficient advertiser balance. Activated campaigns begin serving immediately (or at start_date if set).
curl -X POST https://api.scrya.com/api/ads/campaigns/camp_abc123/activate \
-H "Authorization: Bearer YOUR_API_KEY" Response (200):
{
"id": "camp_abc123",
"status": "active",
...
} Pause Campaign
POST /campaigns/{id}/pause Pause an active campaign. Stops all ad serving immediately. Can be reactivated later.
curl -X POST https://api.scrya.com/api/ads/campaigns/camp_abc123/pause \
-H "Authorization: Bearer YOUR_API_KEY" Response (200): Campaign object with "status": "paused".
Geo Targeting
Add geographic targeting rules to campaigns. Supports country, state, city, and radius-based targeting. Multiple rules combine with OR logic (ad serves if any rule matches). Use include: false to exclude regions.
Add Geo Target
POST /campaigns/{id}/geo-targets Request body:
target_type(string, required) — One of:country,state,city,radiuscountry_code(string, required for country/state/city) — ISO 3166-1 alpha-2 code (e.g.,"US")state_code(string, required for state) — State/province code (e.g.,"CA")city_name(string, required for city) — City namelat(number, required for radius) — Latitude of center pointlng(number, required for radius) — Longitude of center pointradius_km(number, required for radius) — Radius in kilometersinclude(boolean, optional) —trueto include (default),falseto exclude
# Target the entire US
curl -X POST https://api.scrya.com/api/ads/campaigns/camp_abc123/geo-targets \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"target_type": "country",
"country_code": "US",
"include": true
}'
# Target a 50km radius around San Francisco
curl -X POST https://api.scrya.com/api/ads/campaigns/camp_abc123/geo-targets \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"target_type": "radius",
"lat": 37.7749,
"lng": -122.4194,
"radius_km": 50,
"include": true
}' Response (201):
{
"id": "geo_xyz789",
"campaign_id": "camp_abc123",
"target_type": "country",
"country_code": "US",
"include": true,
"created_at": "2026-03-01T12:00:00Z"
} List Geo Targets
GET /campaigns/{id}/geo-targets List all geographic targeting rules for a campaign.
curl https://api.scrya.com/api/ads/campaigns/camp_abc123/geo-targets \
-H "Authorization: Bearer YOUR_API_KEY" Response (200): Array of geo target objects.
Remove Geo Target
DELETE /campaigns/{id}/geo-targets/{tid} Remove a geographic targeting rule.
curl -X DELETE https://api.scrya.com/api/ads/campaigns/camp_abc123/geo-targets/geo_xyz789 \
-H "Authorization: Bearer YOUR_API_KEY" Response (204): No content.
Blocklist
Block your ads from appearing alongside specific content. Blocklist rules prevent matching when the game context contains the blocked value.
Add Blocklist Rule
POST /campaigns/{id}/blocklist Request body:
rule_type(string, required) — One of:keyword,theme,category,action,game_idvalue(string, required) — The value to block
# Block ads from appearing in violent contexts
curl -X POST https://api.scrya.com/api/ads/campaigns/camp_abc123/blocklist \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"rule_type": "keyword",
"value": "violence"
}'
# Block a specific game
curl -X POST https://api.scrya.com/api/ads/campaigns/camp_abc123/blocklist \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"rule_type": "game_id",
"value": "game_xyz"
}' Response (201):
{
"id": "blk_abc789",
"campaign_id": "camp_abc123",
"rule_type": "keyword",
"value": "violence",
"created_at": "2026-03-01T12:00:00Z"
} List Blocklist Rules
GET /campaigns/{id}/blocklist List all blocklist rules for a campaign.
curl https://api.scrya.com/api/ads/campaigns/camp_abc123/blocklist \
-H "Authorization: Bearer YOUR_API_KEY" Response (200): Array of blocklist rule objects.
Remove Blocklist Rule
DELETE /campaigns/{id}/blocklist/{rid} Remove a blocklist rule.
curl -X DELETE https://api.scrya.com/api/ads/campaigns/camp_abc123/blocklist/blk_abc789 \
-H "Authorization: Bearer YOUR_API_KEY" Response (204): No content.
Creatives
Creatives are the ad content that gets woven into game narratives. Each creative has a type that determines how it integrates: narrative hooks appear as dialogue or narration, product mentions reference your brand naturally, location brands influence settings, and character references tie to NPCs.
Create Creative
POST /campaigns/{id}/creatives Request body:
creative_type(string, required) — One of:narrative_hook,product_mention,location_brand,character_referencebrand_name(string, required) — Brand name to displayproduct_name(string, optional) — Specific product nametagline(string, optional) — Brand taglinenarrative_hook(string, required for narrative_hook type) — Primary narrative text injected into the gamealt_hooks(array of strings, optional) — Alternative hooks for variety (system rotates automatically)tone(string, optional) — One of:positive,neutral,humorous,dramatic. Default:neutralmax_uses_per_game(integer, optional) — Maximum times this creative can appear in a single game session. Range:1-20. Default:3
curl -X POST https://api.scrya.com/api/ads/campaigns/camp_abc123/creatives \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"creative_type": "narrative_hook",
"brand_name": "Acme Corp",
"product_name": "Acme Shield",
"tagline": "Protection you can trust",
"narrative_hook": "A familiar logo on the briefing folder catches your eye — Acme Shield, the defense contractor everyone in Washington seems to know.",
"alt_hooks": [
"The advisor slides an Acme Shield dossier across the table.",
"On the news ticker: Acme Shield wins another Pentagon contract."
],
"tone": "neutral",
"max_uses_per_game": 5
}' Response (201):
{
"id": "crt_def456",
"campaign_id": "camp_abc123",
"creative_type": "narrative_hook",
"brand_name": "Acme Corp",
"product_name": "Acme Shield",
"tagline": "Protection you can trust",
"narrative_hook": "A familiar logo on the briefing folder catches your eye — Acme Shield, the defense contractor everyone in Washington seems to know.",
"alt_hooks": [
"The advisor slides an Acme Shield dossier across the table.",
"On the news ticker: Acme Shield wins another Pentagon contract."
],
"tone": "neutral",
"max_uses_per_game": 5,
"impressions": 0,
"created_at": "2026-03-01T12:00:00Z"
} List Creatives
GET /campaigns/{id}/creatives List all creatives for a campaign.
curl https://api.scrya.com/api/ads/campaigns/camp_abc123/creatives \
-H "Authorization: Bearer YOUR_API_KEY" Response (200): Array of creative objects.
Update Creative
PATCH /creatives/{id} Update creative fields. Only include fields you want to change.
Request body (all optional):
brand_name(string)product_name(string)tagline(string)narrative_hook(string)alt_hooks(array of strings)tone(string)max_uses_per_game(integer, 1-20)
curl -X PATCH https://api.scrya.com/api/ads/creatives/crt_def456 \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"narrative_hook": "An Acme Shield briefcase sits on the Resolute desk, its logo catching the light.",
"tone": "dramatic"
}' Response (200): Updated creative object.
Delete Creative
DELETE /creatives/{id} Permanently delete a creative. Cannot delete the last creative on an active campaign.
curl -X DELETE https://api.scrya.com/api/ads/creatives/crt_def456 \
-H "Authorization: Bearer YOUR_API_KEY" Response (204): No content.
Affinities
Affinities control how the ad matching pipeline biases visual and narrative elements when your ad is selected. They influence the game's rendering pipeline — lighting, camera angles, effects, and more — to create subtle brand alignment without breaking immersion. See Affinity Targeting for details on each type.
List Affinities
GET /campaigns/{id}/affinities List all affinities for a campaign.
curl https://api.scrya.com/api/ads/campaigns/camp_abc123/affinities \
-H "Authorization: Bearer YOUR_API_KEY" Response (200): Array of affinity objects.
Add Affinity
POST /campaigns/{id}/affinities Request body:
affinity_type(string, required) — One of:action,location,theme,mood,category,lighting,effects,cameraaffinity_value(string, required) — The target value (e.g.,"warm golden hour"for lighting,"wide establishing"for camera)weight(number, required) — Influence strength from0.1(subtle) to3.0(strong). Default:1.0
curl -X POST https://api.scrya.com/api/ads/campaigns/camp_abc123/affinities \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"affinity_type": "lighting",
"affinity_value": "warm golden hour",
"weight": 1.5
}' Response (201):
{
"id": "aff_lmn456",
"campaign_id": "camp_abc123",
"affinity_type": "lighting",
"affinity_value": "warm golden hour",
"weight": 1.5,
"created_at": "2026-03-01T12:00:00Z"
} Remove Affinity
DELETE /campaigns/{id}/affinities/{aid} Remove a single affinity.
curl -X DELETE https://api.scrya.com/api/ads/campaigns/camp_abc123/affinities/aff_lmn456 \
-H "Authorization: Bearer YOUR_API_KEY" Response (204): No content.
Bulk Replace Affinities
PUT /campaigns/{id}/affinities/bulk Replace all affinities for a campaign in a single call. Existing affinities are deleted and replaced with the provided list. Maximum 50 affinities per campaign.
Request body:
affinities(array, required) — Array of affinity objects, each withaffinity_type,affinity_value, andweight
curl -X PUT https://api.scrya.com/api/ads/campaigns/camp_abc123/affinities/bulk \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"affinities": [
{"affinity_type": "lighting", "affinity_value": "warm golden hour", "weight": 1.5},
{"affinity_type": "mood", "affinity_value": "tense", "weight": 1.2},
{"affinity_type": "camera", "affinity_value": "close-up", "weight": 0.8},
{"affinity_type": "effects", "affinity_value": "film grain, cinematic widescreen", "weight": 1.0}
]
}' Response (200): Array of the newly created affinity objects.
Analytics
Retrieve campaign performance data. All analytics endpoints return data for the authenticated advertiser's campaigns only.
Campaign Stats
GET /campaigns/{id}/stats Get aggregate statistics for a campaign.
curl https://api.scrya.com/api/ads/campaigns/camp_abc123/stats \
-H "Authorization: Bearer YOUR_API_KEY" Response (200):
{
"campaign_id": "camp_abc123",
"impressions": 15230,
"unique_users": 8421,
"unique_games": 12,
"spent_cents": 38075,
"budget_cents": 500000,
"effective_cpm_cents": 250,
"avg_affinity_score": 0.73,
"top_creative_id": "crt_def456",
"top_game_id": "presidential_dilemma"
} Daily Time-Series
GET /campaigns/{id}/analytics/daily Get daily impression and spend data as a time series.
Query parameters:
days(integer, optional) — Number of days to return. Range:1-365. Default:30
curl "https://api.scrya.com/api/ads/campaigns/camp_abc123/analytics/daily?days=7" \
-H "Authorization: Bearer YOUR_API_KEY" Response (200):
{
"campaign_id": "camp_abc123",
"days": [
{
"date": "2026-02-28",
"impressions": 2150,
"unique_users": 1203,
"spent_cents": 5375,
"avg_affinity_score": 0.71
},
{
"date": "2026-02-27",
"impressions": 1980,
"unique_users": 1105,
"spent_cents": 4950,
"avg_affinity_score": 0.74
}
]
} Per-Creative Breakdown
GET /campaigns/{id}/analytics/creatives Get performance broken down by individual creative.
curl https://api.scrya.com/api/ads/campaigns/camp_abc123/analytics/creatives \
-H "Authorization: Bearer YOUR_API_KEY" Response (200):
{
"campaign_id": "camp_abc123",
"creatives": [
{
"creative_id": "crt_def456",
"creative_type": "narrative_hook",
"brand_name": "Acme Corp",
"impressions": 9500,
"unique_users": 5200,
"spent_cents": 23750,
"avg_affinity_score": 0.78
},
{
"creative_id": "crt_ghi789",
"creative_type": "product_mention",
"brand_name": "Acme Corp",
"impressions": 5730,
"unique_users": 3221,
"spent_cents": 14325,
"avg_affinity_score": 0.65
}
]
} Per-Country Breakdown
GET /campaigns/{id}/analytics/geo Get performance broken down by country.
curl https://api.scrya.com/api/ads/campaigns/camp_abc123/analytics/geo \
-H "Authorization: Bearer YOUR_API_KEY" Response (200):
{
"campaign_id": "camp_abc123",
"countries": [
{
"country_code": "US",
"impressions": 10500,
"unique_users": 5800,
"spent_cents": 26250
},
{
"country_code": "GB",
"impressions": 2100,
"unique_users": 1150,
"spent_cents": 5250
},
{
"country_code": "DE",
"impressions": 1430,
"unique_users": 780,
"spent_cents": 3575
}
]
} Affinity Effectiveness
GET /campaigns/{id}/analytics/affinities See how each affinity is performing. Shows match rate (how often the affinity contributed to ad selection) and average score contribution.
curl https://api.scrya.com/api/ads/campaigns/camp_abc123/analytics/affinities \
-H "Authorization: Bearer YOUR_API_KEY" Response (200):
{
"campaign_id": "camp_abc123",
"affinities": [
{
"affinity_id": "aff_lmn456",
"affinity_type": "lighting",
"affinity_value": "warm golden hour",
"weight": 1.5,
"match_rate": 0.42,
"avg_score_contribution": 0.31,
"impressions_influenced": 6397
},
{
"affinity_id": "aff_opq789",
"affinity_type": "mood",
"affinity_value": "tense",
"weight": 1.2,
"match_rate": 0.68,
"avg_score_contribution": 0.22,
"impressions_influenced": 10356
}
]
} Budget Pacing
GET /campaigns/{id}/analytics/pacing Get budget pacing information showing spend rate, projected exhaustion date, and daily cap utilization.
curl https://api.scrya.com/api/ads/campaigns/camp_abc123/analytics/pacing \
-H "Authorization: Bearer YOUR_API_KEY" Response (200):
{
"campaign_id": "camp_abc123",
"budget_cents": 500000,
"spent_cents": 38075,
"remaining_cents": 461925,
"daily_cap_cents": 25000,
"today_spent_cents": 12400,
"today_remaining_cents": 12600,
"avg_daily_spend_cents": 5439,
"projected_exhaustion_date": "2026-05-25",
"days_remaining": 85,
"pacing_status": "under_pacing",
"utilization_pct": 49.6
} Placements (Developer)
Game developers use placement endpoints to register their games for ad serving, configure ad types, set revenue share, and control which advertisers and categories are allowed.
Enable Placements
POST /placements/{game_id} Register a game for ad placements. The game_id is your unique identifier for the game.
Request body:
creator_id(string, required) — Your developer/creator user IDplacement_types(array of strings, required) — Accepted creative types (e.g.,["narrative_hook", "product_mention", "location_brand"])revenue_share_pct(number, required) — Revenue share percentage for the developer. Range:0-100max_ads_per_session(integer, optional) — Maximum ads per game session. Range:1-50. Default:10blocked_advertisers(array of strings, optional) — Advertiser IDs to block from this gameblocked_categories(array of strings, optional) — Ad categories to block (e.g.,["gambling", "alcohol"])
curl -X POST https://api.scrya.com/api/ads/placements/my_game_id \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"creator_id": "dev_user_123",
"placement_types": ["narrative_hook", "product_mention"],
"revenue_share_pct": 70,
"max_ads_per_session": 5,
"blocked_categories": ["gambling"]
}' Response (201):
{
"game_id": "my_game_id",
"creator_id": "dev_user_123",
"placement_types": ["narrative_hook", "product_mention"],
"revenue_share_pct": 70,
"max_ads_per_session": 5,
"blocked_advertisers": [],
"blocked_categories": ["gambling"],
"is_active": true,
"created_at": "2026-03-01T12:00:00Z"
} Get Placement
GET /placements/{game_id} Get the current placement configuration for a game.
curl https://api.scrya.com/api/ads/placements/my_game_id \
-H "Authorization: Bearer YOUR_API_KEY" Response (200): Placement object.
Update Placement
PATCH /placements/{game_id} Update placement configuration. Only include fields you want to change.
Request body (all optional):
placement_types(array of strings)revenue_share_pct(number, 0-100)max_ads_per_session(integer, 1-50)blocked_advertisers(array of strings)blocked_categories(array of strings)
curl -X PATCH https://api.scrya.com/api/ads/placements/my_game_id \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"max_ads_per_session": 8,
"blocked_categories": ["gambling", "alcohol"]
}' Response (200): Updated placement object.
Disable Placements
DELETE /placements/{game_id} Disable ad placements for a game. Stops all ad serving immediately. The configuration is preserved and can be re-enabled by calling POST again.
curl -X DELETE https://api.scrya.com/api/ads/placements/my_game_id \
-H "Authorization: Bearer YOUR_API_KEY" Response (204): No content.
Revenue
Track ad spend (for advertisers) and earnings (for game developers).
Advertiser Spend
GET /revenue Get total spend summary for the authenticated advertiser across all campaigns.
curl https://api.scrya.com/api/ads/revenue \
-H "Authorization: Bearer YOUR_API_KEY" Response (200):
{
"total_spent_cents": 152300,
"total_impressions": 60920,
"active_campaigns": 3,
"balance_cents": 347700,
"campaigns": [
{
"campaign_id": "camp_abc123",
"name": "Summer 2026 Launch",
"spent_cents": 38075,
"impressions": 15230,
"status": "active"
}
]
} Creator Total Earnings
GET /creator-revenue Get total earnings across all games for the authenticated developer.
curl https://api.scrya.com/api/ads/creator-revenue \
-H "Authorization: Bearer YOUR_API_KEY" Response (200):
{
"total_earned_cents": 106610,
"total_impressions": 60920,
"games_count": 2,
"games": [
{
"game_id": "my_game_id",
"earned_cents": 85000,
"impressions": 48500,
"revenue_share_pct": 70
},
{
"game_id": "my_other_game",
"earned_cents": 21610,
"impressions": 12420,
"revenue_share_pct": 70
}
]
} Per-Game Earnings
GET /creator-revenue/{game_id} Get detailed earnings for a specific game.
curl https://api.scrya.com/api/ads/creator-revenue/my_game_id \
-H "Authorization: Bearer YOUR_API_KEY" Response (200):
{
"game_id": "my_game_id",
"earned_cents": 85000,
"impressions": 48500,
"revenue_share_pct": 70,
"top_advertisers": [
{"advertiser_id": "adv_abc123", "impressions": 15230, "earned_cents": 26653},
{"advertiser_id": "adv_xyz456", "impressions": 12100, "earned_cents": 21175}
],
"daily": [
{"date": "2026-02-28", "impressions": 2150, "earned_cents": 3763},
{"date": "2026-02-27", "impressions": 1980, "earned_cents": 3465}
]
} Simulator
Preview how your campaign's affinities would bias the rendering pipeline for a given scene context. Useful for testing and tuning affinities before activating a campaign.
Simulate Pipeline Bias
POST /campaigns/{id}/simulate Preview the pipeline bias your campaign would produce for a given narrative context.
Request body:
narrative_function(string, optional) — Scene narrative context (e.g.,"The president reviews classified documents")mood(string, optional) — Scene mood (e.g.,"tense","hopeful","dramatic")
curl -X POST https://api.scrya.com/api/ads/campaigns/camp_abc123/simulate \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"narrative_function": "The president reviews classified documents in the Oval Office",
"mood": "tense"
}' Response (200):
{
"campaign_id": "camp_abc123",
"matched_creative": {
"id": "crt_def456",
"narrative_hook": "A familiar logo on the briefing folder catches your eye — Acme Shield, the defense contractor everyone in Washington seems to know.",
"creative_type": "narrative_hook"
},
"biased_pipeline": {
"lighting": "warm golden hour",
"effects": "film grain, cinematic widescreen",
"camera": "close-up",
"mood": "tense"
},
"affinity_scores": {
"lighting": 0.63,
"mood": 0.82,
"camera": 0.24,
"effects": 0.41
},
"total_score": 0.73
} Get Simulation Options
GET /campaigns/{id}/simulate/options Get available options for the simulation endpoint, including valid mood values, narrative function examples, and the campaign's current affinity configuration.
curl https://api.scrya.com/api/ads/campaigns/camp_abc123/simulate/options \
-H "Authorization: Bearer YOUR_API_KEY" Response (200):
{
"moods": ["tense", "hopeful", "dramatic", "calm", "chaotic", "mysterious", "humorous", "melancholic"],
"narrative_examples": [
"The president addresses the nation from the Oval Office",
"A secret meeting in the Pentagon basement",
"Campaign rally in a small Midwestern town",
"Trade negotiations with foreign diplomats"
],
"current_affinities": [
{"affinity_type": "lighting", "affinity_value": "warm golden hour", "weight": 1.5},
{"affinity_type": "mood", "affinity_value": "tense", "weight": 1.2}
]
} Ad Matching
The core integration endpoints. Call /match when generating a scene to find the best ad, then call /impressions after the player sees the ad-influenced content. See the Quickstart for a complete walkthrough.
Find Best Ad
POST /match Find the best matching ad for a given game context. The matching pipeline evaluates all active campaigns against the provided context, applying geo targeting, blocklist rules, affinity scoring, and budget constraints. Returns the winning creative with pipeline bias values, or 204 No Content if no ads match.
Request body:
game_id(string, required) — Your registered game IDuser_id(string, required) — Current player's user ID (for frequency capping)player_geo(object, optional) — Player geographic datacountry_code(string) — ISO 3166-1 alpha-2 codestate_code(string) — State/province codecity_name(string) — City namelat(number) — Latitudelng(number) — Longitude
game_context(object, required) — Current scene contexttheme_id(string) — Active game themecategory(string) — Game categorynarrative(string) — Current narrative text or scene descriptionmood_tags(array of strings) — Current mood tagslocation(string) — Current game locationactions(array of strings) — Available player actions
session_id(string, optional) — Game session ID (for per-session frequency capping)
curl -X POST https://api.scrya.com/api/ads/match \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"game_id": "my_game_id",
"user_id": "player_123",
"player_geo": {
"country_code": "US",
"state_code": "CA"
},
"game_context": {
"theme_id": "1",
"category": "simulation",
"narrative": "The president faces a difficult decision about defense spending",
"mood_tags": ["tense", "dramatic"],
"location": "oval_office",
"actions": ["approve_budget", "reject_budget", "defer"]
},
"session_id": "sess_abc"
}' Response (200):
{
"campaign_id": "camp_abc123",
"creative_id": "crt_def456",
"narrative_hook": "A familiar logo on the briefing folder catches your eye — Acme Shield, the defense contractor everyone in Washington seems to know.",
"creative_type": "narrative_hook",
"brand_name": "Acme Corp",
"product_name": "Acme Shield",
"tagline": "Protection you can trust",
"tone": "neutral",
"biased_pipeline": {
"lighting": "warm golden hour",
"effects": "film grain, cinematic widescreen",
"camera": "close-up",
"mood": "tense"
},
"affinity_score": 0.73,
"cpm_bid_cents": 250
} Response (204): No content. No matching ads found — proceed with normal scene generation.
Record Impression
POST /impressions Record that a player saw ad-influenced content. This triggers billing (the advertiser is charged and the developer earns their revenue share). Call this after the player has actually seen the narrative hook or ad-influenced scene.
Request body:
campaign_id(string, required) — Campaign ID from the match responsecreative_id(string, required) — Creative ID from the match responsegame_id(string, required) — Your game ID
curl -X POST https://api.scrya.com/api/ads/impressions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"campaign_id": "camp_abc123",
"creative_id": "crt_def456",
"game_id": "my_game_id"
}' Response (201):
{
"impression_id": "imp_uvw123",
"campaign_id": "camp_abc123",
"creative_id": "crt_def456",
"game_id": "my_game_id",
"charged_cents": 0.25,
"recorded_at": "2026-03-01T12:05:00Z"
} Rate Limits
API requests are rate-limited per API key:
- Match endpoint: 1,000 requests/minute (designed for real-time game integration)
- Impressions endpoint: 1,000 requests/minute
- Management endpoints: 100 requests/minute (campaigns, creatives, targeting)
- Analytics endpoints: 60 requests/minute
Rate limit headers are included in every response:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 997
X-RateLimit-Reset: 1709294460 When rate limited, you receive 429 Too Many Requests with a Retry-After header in seconds.
Error Reference
All errors return a JSON body with a detail field:
{
"detail": "Campaign budget_cents cannot be less than current spent_cents (38075)"
} | Status | Meaning | Common Causes |
|---|---|---|
400 | Bad Request | Invalid field value, missing required field |
401 | Unauthorized | Missing or invalid API key |
403 | Forbidden | Accessing another advertiser's resource |
404 | Not Found | Campaign, creative, or placement does not exist |
409 | Conflict | Duplicate registration, campaign already active |
422 | Validation Error | cpm_bid_cents out of range, invalid affinity_type, too many affinities |
429 | Rate Limited | Too many requests, check Retry-After header |
500 | Server Error | Internal error, contact support |
What's Next
- Quickstart Guide -- 5-minute integration walkthrough
- How Ad Matching Works -- the 6-step matching pipeline explained
- Affinity Targeting -- deep dive into all 8 affinity types
- Analytics Guide -- interpreting your campaign data
- Unity SDK Guide -- C# integration examples
- Unreal SDK Guide -- C++ integration examples
- Web SDK Guide -- JavaScript integration examples