Campaigns
Campaigns connect placements (event triggers) to audiences (user segments) and determine which paywall a user sees. When the SDK calls register(placement:), the campaign system evaluates which audience matches and which paywall to render.
Campaign CRUD
Create a Campaign
POST /v1/projects/:id/campaigns| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Campaign name |
status | string | No | active, inactive, or archived. Defaults to active. |
curl -X POST https://agentwallie.com/api/v1/projects/PROJECT_ID/campaigns \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk_your_private_key" \
-d '{"name": "Onboarding Flow", "status": "active"}'Response 201 Created
{
"id": "camp_abc123",
"name": "Onboarding Flow",
"status": "active",
"projectId": "PROJECT_ID",
"createdAt": "2025-03-15T10:00:00.000Z"
}List Campaigns
GET /v1/projects/:id/campaignscurl https://agentwallie.com/api/v1/projects/PROJECT_ID/campaigns \
-H "Authorization: Bearer sk_your_private_key"Get a Campaign
GET /v1/projects/:id/campaigns/:cidReturns the campaign with its placements and audiences.
curl https://agentwallie.com/api/v1/projects/PROJECT_ID/campaigns/camp_abc123 \
-H "Authorization: Bearer sk_your_private_key"Update a Campaign
PUT /v1/projects/:id/campaigns/:cid| Field | Type | Description |
|---|---|---|
name | string | New name |
status | string | active, inactive, or archived |
curl -X PUT https://agentwallie.com/api/v1/projects/PROJECT_ID/campaigns/camp_abc123 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk_your_private_key" \
-d '{"status": "inactive"}'Delete a Campaign
DELETE /v1/projects/:id/campaigns/:cidcurl -X DELETE https://agentwallie.com/api/v1/projects/PROJECT_ID/campaigns/camp_abc123 \
-H "Authorization: Bearer sk_your_private_key"Placements
Placements are event names that trigger campaign evaluation. When the SDK calls register(placement: "feature_gate"), the system checks all campaigns that have a feature_gate placement.
Create a Placement
POST /v1/projects/:id/campaigns/:cid/placements| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Placement name (e.g., onboarding_complete, app_launch) |
type | string | No | custom or standard. Defaults to custom. |
curl -X POST https://agentwallie.com/api/v1/projects/PROJECT_ID/campaigns/camp_abc123/placements \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk_your_private_key" \
-d '{"name": "feature_gate", "type": "custom"}'List Placements
GET /v1/projects/:id/campaigns/:cid/placementscurl https://agentwallie.com/api/v1/projects/PROJECT_ID/campaigns/camp_abc123/placements \
-H "Authorization: Bearer sk_your_private_key"Update a Placement
PUT /v1/projects/:id/campaigns/:cid/placements/:plid| Field | Type | Description |
|---|---|---|
status | string | active or paused |
Delete a Placement
DELETE /v1/projects/:id/campaigns/:cid/placements/:plidStandard Placements
These built-in placements match common app lifecycle events:
| Name | Trigger |
|---|---|
app_install | First app launch ever |
app_launch | Every app foreground |
session_start | New session after background threshold |
deepLink_open | Deep link opened |
transaction_fail | Purchase attempt failed |
transaction_abandon | User dismissed purchase sheet |
survey_response | Survey completed |
paywall_decline | User closed paywall without purchasing |
Audiences
Audiences are user segments within a campaign. They are evaluated top-to-bottom (by priority order). The first matching audience determines which paywall is shown.
Create an Audience
POST /v1/projects/:id/campaigns/:cid/audiences| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Audience name |
filters | array | Yes | Array of filter rules (see below) |
entitlement_check | string | No | Skip if user has this entitlement |
frequency_cap | string | No | once_per_session, once_per_day, N_times_total |
Filter Rules
Each filter rule is an object with:
| Field | Type | Description |
|---|---|---|
field | string | Dot-notation path: user.plan, device.platform, user.seed, etc. |
operator | string | is, is_not, contains, gt, gte, lt, lte, in, not_in, exists, not_exists |
value | any | Comparison value |
conjunction | string | and or or (for chaining with the previous rule) |
You can optionally include an experiment object to atomically create an A/B test with the audience:
| Field | Type | Required | Description |
|---|---|---|---|
experiment | object | No | Inline experiment (see below) |
experiment.variants | array | Yes | Array of { paywall_id, traffic_percentage } |
experiment.confidence_threshold | number | No | Significance threshold (0-1). Default: 0.95 |
experiment.auto_promote | boolean | No | Auto-promote winner. Default: false |
curl -X POST https://agentwallie.com/api/v1/projects/PROJECT_ID/campaigns/camp_abc123/audiences \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk_your_private_key" \
-d '{
"name": "Power Users on iOS",
"filters": [
{ "field": "device.platform", "operator": "is", "value": "ios" },
{ "field": "device.session_count", "operator": "gte", "value": 5, "conjunction": "and" },
{ "field": "user.subscription_status", "operator": "is", "value": "free", "conjunction": "and" }
],
"frequency_cap": "once_per_session",
"experiment": {
"variants": [
{ "paywall_id": "pw_original", "traffic_percentage": 50 },
{ "paywall_id": "pw_new_design", "traffic_percentage": 50 }
],
"confidence_threshold": 0.95,
"auto_promote": true
}
}'All API fields use snake_case. The experiment object uses paywall_id, traffic_percentage, confidence_threshold, and auto_promote.
List Audiences
GET /v1/projects/:id/campaigns/:cid/audiencesUpdate an Audience
PUT /v1/projects/:id/campaigns/:cid/audiences/:aidReorder Audiences
PUT /v1/projects/:id/campaigns/:cid/audiences/reorderChange the evaluation priority of audiences. Audiences are matched top-to-bottom, so order matters.
| Field | Type | Required | Description |
|---|---|---|---|
order | string[] | Yes | Array of audience IDs in desired priority order |
curl -X PUT https://agentwallie.com/api/v1/projects/PROJECT_ID/campaigns/camp_abc123/audiences/reorder \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk_your_private_key" \
-d '{"order": ["aud_power_users", "aud_new_users", "aud_everyone"]}'Delete an Audience
DELETE /v1/projects/:id/campaigns/:cid/audiences/:aidThe user.seed field is a random number (0-99) assigned to each user once. Use it for cross-campaign cohort splitting -- for example, user.seed lte 49 targets 50% of users.