Skip to content

Commit ac4a81f

Browse files
bokelleyclaude
andauthored
feat: Add CPA pricing model (#1015)
* feat: Add CPA pricing model for outcome-based campaigns Adds Cost Per Acquisition (CPA) as a pricing model, enabling advertisers to pay per conversion event. The billable event type is determined by the package's optimization_goal.event_type, which ties to event sources configured via sync_event_sources. This single model covers CPO (event_type=purchase), CPL (event_type=lead), and CPI (event_type=app_install) use cases without separate pricing models. Closes #1006 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: Add event_type to CPA pricing option The pricing option should declare which event triggers billing independently of the package's optimization_goal. A seller offering "$5 per purchase" is a pricing concern, not an optimization concern. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: Add optional event_source_id to CPA pricing Allows sellers to offer different CPA rates for different event sources (e.g., $5/purchase from website pixel vs $3/purchase from in-store attribution). When omitted, any event of the specified event_type counts toward billing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: Make CPA fixed-price only, remove auction fields CPA is a fixed-price agreement between seller and buyer — there's no auction on the cost per acquisition. Removed floor_price and price_guidance, made fixed_price required. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: Address review feedback on CPA pricing option - Use allOf wrapper for event_type $ref (draft-07 ignores sibling keywords alongside $ref) - Use exclusiveMinimum: 0 for fixed_price (zero CPA is meaningless) - Add custom_event_name field for event_type: "custom" - Fix changeset text (was claiming "auction modes" support) - Add docs note on refund handling (commercial term, not protocol) - Add docs example showing pricing/optimization independence Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent a859fd1 commit ac4a81f

6 files changed

Lines changed: 132 additions & 2 deletions

File tree

.changeset/add-cpa-pricing.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
"adcontextprotocol": minor
3+
---
4+
5+
Add CPA (Cost Per Acquisition) pricing model for outcome-based campaigns.
6+
7+
CPA enables advertisers to pay per conversion event (purchase, lead, signup, etc.) rather than per impression or click. The pricing option declares which `event_type` triggers billing, independent of any optimization goal.
8+
9+
This single model covers use cases previously described as CPO (Cost Per Order), CPL (Cost Per Lead), and CPI (Cost Per Install) — differentiated by event type rather than separate pricing models.
10+
11+
New schema:
12+
- `cpa-option.json`: CPA pricing option (fixed price per conversion event)
13+
14+
Updated schemas:
15+
- `pricing-model.json`: Added `cpa` enum value
16+
- `pricing-option.json`: Added cpa-option to discriminated union
17+
- `index.json`: Added cpa-option to registry

docs/media-buy/advanced-topics/pricing-models.mdx

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: Pricing Models
3-
description: Comprehensive guide to AdCP's flexible pricing models including CPM, CPCV, CPP, CPC, and DOOH support
4-
keywords: [pricing models, CPM, CPCV, CPP, CPC, CPV, GRP, video pricing, DOOH, share of voice, measurement]
3+
description: Comprehensive guide to AdCP's flexible pricing models including CPM, CPCV, CPP, CPC, CPA, and DOOH support
4+
keywords: [pricing models, CPM, CPCV, CPP, CPC, CPA, CPV, GRP, video pricing, DOOH, share of voice, measurement, conversions]
55
---
66

77

@@ -237,6 +237,61 @@ Buyers should verify the measurement provider meets their campaign requirements
237237

238238
---
239239

240+
### CPA (Cost Per Acquisition)
241+
**Cost per conversion event** - Advertiser pays when a defined conversion occurs.
242+
243+
**Use Cases**: Retail media (pay per order), lead generation, app install campaigns, commerce media
244+
245+
**Example**:
246+
```json
247+
{
248+
"$schema": "https://adcontextprotocol.org/schemas/v2/pricing-options/cpa-option.json",
249+
"pricing_option_id": "cpa_usd_purchase",
250+
"pricing_model": "cpa",
251+
"event_type": "purchase",
252+
"fixed_price": 5.00,
253+
"currency": "USD"
254+
}
255+
```
256+
257+
**Billing**: Charged a fixed price when the specified `event_type` fires. The pricing option declares what event triggers billing — this is independent of `optimization_goal`, which controls delivery optimization.
258+
259+
**Parameters**:
260+
- `event_type` (required): The conversion event that triggers billing. Uses the standard event type enum (e.g., `purchase`, `lead`, `app_install`, `add_to_cart`, `subscribe`).
261+
- `event_source_id` (optional): When present, only events from this specific source count toward billing. Must match an event source configured via `sync_event_sources`. When omitted, any event of the specified `event_type` counts.
262+
263+
**Example** (different rates by event source):
264+
```json
265+
{
266+
"pricing_options": [
267+
{
268+
"pricing_option_id": "cpa_online_purchase",
269+
"pricing_model": "cpa",
270+
"event_type": "purchase",
271+
"event_source_id": "website_pixel",
272+
"fixed_price": 5.00,
273+
"currency": "USD"
274+
},
275+
{
276+
"pricing_option_id": "cpa_instore_purchase",
277+
"pricing_model": "cpa",
278+
"event_type": "purchase",
279+
"event_source_id": "instore_attribution",
280+
"fixed_price": 3.00,
281+
"currency": "USD"
282+
}
283+
]
284+
}
285+
```
286+
287+
**Pricing vs. optimization**: The CPA pricing option's `event_type` (what triggers billing) is independent of the package's `optimization_goal` (what the platform optimizes delivery toward). For example, a package can use CPA pricing on `lead` events while setting `optimization_goal.event_type: "purchase"` with `target_roas: 4.0` — billing fires on leads, but delivery is optimized for downstream purchase ROAS.
288+
289+
**Refunds and adjustments**: Refund handling and conversion adjustment policies are commercial terms between buyer and seller. The protocol does not govern clawbacks or billing credits for refunded conversions.
290+
291+
**Note**: CPA replaces the need for separate "CPO" (Cost Per Order) or "CPL" (Cost Per Lead) pricing models. A seller can offer multiple CPA options with different event types, event sources, and prices on the same product.
292+
293+
---
294+
240295
### Flat Rate
241296
**Fixed cost** - Single payment regardless of delivery volume.
242297

@@ -402,6 +457,7 @@ Different pricing models report different primary metrics:
402457
| CPV | views | impressions, quartile_data, spend |
403458
| CPP | grps | reach, frequency, spend |
404459
| CPC | clicks | impressions, ctr, spend |
460+
| CPA | conversions | conversion_value, cost_per_acquisition, roas, spend |
405461
| Flat Rate | N/A | impressions, reach, frequency |
406462

407463
## Example: Multi-Model CTV Product

static/schemas/source/core/pricing-option.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
{
2323
"$ref": "/schemas/pricing-options/cpp-option.json"
2424
},
25+
{
26+
"$ref": "/schemas/pricing-options/cpa-option.json"
27+
},
2528
{
2629
"$ref": "/schemas/pricing-options/flat-rate-option.json"
2730
}

static/schemas/source/enums/pricing-model.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"cpcv",
1212
"cpv",
1313
"cpp",
14+
"cpa",
1415
"flat_rate"
1516
],
1617
"enumDescriptions": {
@@ -20,6 +21,7 @@
2021
"cpcv": "Cost Per Completed View - cost per 100% video/audio completion",
2122
"cpv": "Cost Per View - cost per view at publisher-defined threshold (e.g., 50% completion)",
2223
"cpp": "Cost Per Point - cost per Gross Rating Point or Target Rating Point (TV/audio)",
24+
"cpa": "Cost Per Acquisition - cost per conversion event (purchase, lead, signup, etc.)",
2325
"flat_rate": "Flat Rate - fixed cost regardless of delivery volume (sponsorships, takeovers)"
2426
}
2527
}

static/schemas/source/index.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,10 @@
537537
"$ref": "/schemas/pricing-options/cpp-option.json",
538538
"description": "Cost Per Point (CPP) pricing for TV/audio with demographic measurement - supports fixed rate and auction modes"
539539
},
540+
"cpa-option": {
541+
"$ref": "/schemas/pricing-options/cpa-option.json",
542+
"description": "Cost Per Acquisition (CPA) pricing for performance campaigns - fixed price per conversion event"
543+
},
540544
"flat-rate-option": {
541545
"$ref": "/schemas/pricing-options/flat-rate-option.json",
542546
"description": "Flat rate pricing for DOOH and sponsorships - supports fixed rate and auction modes"
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"$id": "/schemas/pricing-options/cpa-option.json",
4+
"title": "CPA Pricing Option",
5+
"description": "Cost Per Acquisition pricing. Advertiser pays a fixed price when a specified conversion event occurs. The event_type field declares which event triggers billing (e.g., purchase, lead, app_install).",
6+
"type": "object",
7+
"properties": {
8+
"pricing_option_id": {
9+
"type": "string",
10+
"description": "Unique identifier for this pricing option within the product"
11+
},
12+
"pricing_model": {
13+
"type": "string",
14+
"const": "cpa",
15+
"description": "Cost per acquisition (conversion event)"
16+
},
17+
"event_type": {
18+
"allOf": [{ "$ref": "/schemas/enums/event-type.json" }],
19+
"description": "The conversion event type that triggers billing (e.g., purchase, lead, app_install)"
20+
},
21+
"custom_event_name": {
22+
"type": "string",
23+
"description": "Name of the custom event when event_type is 'custom'. Required when event_type is 'custom', ignored otherwise."
24+
},
25+
"event_source_id": {
26+
"type": "string",
27+
"description": "When present, only events from this specific event source count toward billing. Allows different CPA rates for different sources (e.g., online vs in-store purchases). Must match an event source configured via sync_event_sources."
28+
},
29+
"currency": {
30+
"type": "string",
31+
"description": "ISO 4217 currency code",
32+
"pattern": "^[A-Z]{3}$",
33+
"examples": ["USD", "EUR", "GBP", "JPY"]
34+
},
35+
"fixed_price": {
36+
"type": "number",
37+
"description": "Fixed price per acquisition in the specified currency",
38+
"exclusiveMinimum": 0
39+
},
40+
"min_spend_per_package": {
41+
"type": "number",
42+
"description": "Minimum spend requirement per package using this pricing option, in the specified currency",
43+
"minimum": 0
44+
}
45+
},
46+
"required": ["pricing_option_id", "pricing_model", "event_type", "currency", "fixed_price"],
47+
"additionalProperties": true
48+
}

0 commit comments

Comments
 (0)