API Reference
Campaigns

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
FieldTypeRequiredDescription
namestringYesCampaign name
statusstringNoactive, 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/campaigns
curl https://agentwallie.com/api/v1/projects/PROJECT_ID/campaigns \
  -H "Authorization: Bearer sk_your_private_key"

Get a Campaign

GET /v1/projects/:id/campaigns/:cid

Returns 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
FieldTypeDescription
namestringNew name
statusstringactive, 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/:cid
curl -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
FieldTypeRequiredDescription
namestringYesPlacement name (e.g., onboarding_complete, app_launch)
typestringNocustom 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/placements
curl 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
FieldTypeDescription
statusstringactive or paused

Delete a Placement

DELETE /v1/projects/:id/campaigns/:cid/placements/:plid

Standard Placements

These built-in placements match common app lifecycle events:

NameTrigger
app_installFirst app launch ever
app_launchEvery app foreground
session_startNew session after background threshold
deepLink_openDeep link opened
transaction_failPurchase attempt failed
transaction_abandonUser dismissed purchase sheet
survey_responseSurvey completed
paywall_declineUser 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
FieldTypeRequiredDescription
namestringYesAudience name
filtersarrayYesArray of filter rules (see below)
entitlement_checkstringNoSkip if user has this entitlement
frequency_capstringNoonce_per_session, once_per_day, N_times_total

Filter Rules

Each filter rule is an object with:

FieldTypeDescription
fieldstringDot-notation path: user.plan, device.platform, user.seed, etc.
operatorstringis, is_not, contains, gt, gte, lt, lte, in, not_in, exists, not_exists
valueanyComparison value
conjunctionstringand 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:

FieldTypeRequiredDescription
experimentobjectNoInline experiment (see below)
experiment.variantsarrayYesArray of { paywall_id, traffic_percentage }
experiment.confidence_thresholdnumberNoSignificance threshold (0-1). Default: 0.95
experiment.auto_promotebooleanNoAuto-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/audiences

Update an Audience

PUT /v1/projects/:id/campaigns/:cid/audiences/:aid

Reorder Audiences

PUT /v1/projects/:id/campaigns/:cid/audiences/reorder

Change the evaluation priority of audiences. Audiences are matched top-to-bottom, so order matters.

FieldTypeRequiredDescription
orderstring[]YesArray 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/:aid

The 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.