Campaigns

The Campaigns app groups the promotions, mailings, journeys, forms and pages of one marketing effort under a campaign with a window, a goal and a budget, and records what it achieved.

This page is the API reference for developers reading or writing campaigns, their assets, tasks, budgets and attribution.

The Campaigns app holds the campaigns of a shop. A campaign is a named marketing effort with a window, a goal and an owner. Promotions, mailings, journeys, forms and pages are attached to it, and the app shows everything dated on one calendar. It also records what each campaign achieved: touches, attribution facts that credit an order to a campaign, and the budget and ad spend booked against it.

Objects

ObjectWhat it holds
Campaigncode (unique per tenant), name, description, status (draft, active, completed or archived), effective_state (draft, planned, running, ended or archived, kept by the app), starts_at, ends_at, goal_metric, goal_value, currency, owner_id, utm_campaign, and the six trash fields.
AssetOne row per promotion, mailing, journey, form, page, page library item or ad campaign link that a campaign holds: the app, the entity, the id, a label and whether the asset carries the campaign. The owning app keeps the asset itself.
Taskcampaign_id, title, assignee, due_at, done_at and notes.
TouchOne recorded contact between a campaign and a buyer before an order, or an outcome of one (a redeemed promotion, a new subscription or a new lead), with its kind, ref, contact_id and market.
Attribution factOne order, or part of an order, credited to a campaign through one or more touches, with the flag is_first_touch. Read-only.
Budget linecampaign_id, line, planned, spent, currency and notes. A line that the ads app books day by day is fed from ad spend.
Spend dayOne day of ad spend on one platform, booked into the campaign's budget line for that platform.

Base path: https://api.revenexx.com/v1/campaigns.

Scopes

A key calls these routes with the capability key of each route. The App's manifest names one per operation, in the form campaigns.<group>.<operation>, and the API keys page explains that a key holds capability keys or a namespace such as campaigns.*. The groups are campaigns, assets, tasks, attribution, touches, budgets, spend, calendar and vocabularies. The scope names are listed in the tables below. A call that needs a scope the key does not hold is refused with 403.

Campaigns

OperationScopeWhat it does
GET /v1/campaigns/campaignscampaigns.campaigns.listLists the campaigns of the tenant. The trash is left out unless trashed asks for it.
POST /v1/campaigns/campaignscampaigns.campaigns.createWrites a campaign down.
GET /v1/campaigns/campaigns/{id}campaigns.campaigns.getReads one campaign.
PUT /v1/campaigns/campaigns/{id}campaigns.campaigns.updateCorrects a campaign.
DELETE /v1/campaigns/campaigns/{id}campaigns.campaigns.deleteMoves a campaign into the trash. A second DELETE on the same campaign deletes it for good, unless a blocker holds it (see below).
POST /v1/campaigns/campaigns/{id}/restorecampaigns.campaigns.restoreTakes a campaign back out of the trash.
POST /v1/campaigns/campaigns/trash/emptycampaigns.campaigns.empty-trashDeletes every trashed campaign that nothing blocks, for good. The answer lists deleted and blocked (each blocked one with its reason); a blocked campaign stays in the trash.
POST /v1/campaigns/campaigns/trash/purgecampaigns.campaigns.purgeDeletes the campaigns that have been in the trash longer than the tenant's trash retention. It is the nightly purge, callable by hand.
POST /v1/campaigns/campaigns/{id}/attachcampaigns.campaigns.attachAttaches one asset to the campaign.
POST /v1/campaigns/campaigns/{id}/detachcampaigns.campaigns.detachReleases one asset from the campaign.
GET /v1/campaigns/campaigns/{id}/performancecampaigns.campaigns.performanceReads what the campaign achieved against its goal, under one attribution model.
POST /v1/campaigns/campaigns/{id}/linkscampaigns.campaigns.linksBuilds a URL tagged with the campaign's UTM values, and writes the UTM value into the campaign when it has none yet.
  • POST /v1/campaigns/campaigns body: required code and name. Optional: description, status, starts_at, ends_at, goal_metric, goal_value, currency, owner_id, utm_campaign, tags, metadata, external_id, external_refs, source_data and source_synced_at. The app sets effective_state itself. A value sent for it is dropped.
  • Create and update 400 rules (PUT is checked the same way, on the merged campaign): goal_metric is one of revenue, orders, redemptions, leads, subscriptions or clicks; goal_value is a number above zero and needs a goal_metric; ends_at is not before starts_at; utm_campaign starts with a lower-case letter or digit and then holds only lower-case letters, digits, hyphens, dots and underscores; tags is a list of strings.
  • PUT /v1/campaigns/campaigns/{id} body: the same fields as the create, all optional.
  • Figures on a campaign: read-only, mirrored from the figures of the performance route under the tenant's default attribution model (a model passed to the performance route does not change them). A value sent for them on a create or update is dropped.
    • orders_count (integer): orders credited under the tenant's attribution model.
    • revenue (number): revenue credited under the tenant's attribution model, returns netted out.
    • roas (number or null): revenue divided by spend; null while nothing was spent.
    • goal_percent (number or null): how far the campaign got towards its goal, 0 to 100 and beyond; null without a goal.
  • Filters on GET /v1/campaigns/campaigns: effective_state (for example running, for what runs now), utm_campaign (to find the campaign a tracked landing page names), and exact matches on id, code, name, description, status, owner_id, goal_metric, currency, orders_count and external_id. trashed is exclude (the default), only or include. limit takes 1 to 200 (default 50), with offset and order (a column, optionally .asc or .desc).
  • Create and update errors: 409 with code_taken when another campaign has the code, utm_taken when the utm_campaign value belongs to another campaign, and 409 with in_trash when the value belongs to a campaign in the trash (restore that one instead).
  • Writes to a trashed campaign: PUT, attach, detach and links answer 409 with in_trash and name the restore route. A body that sends a trash column such as deleted_at or purge_at is 400: those are set by deleting and restoring.
  • DELETE errors: 404 when no campaign has the id. A campaign with attribution facts or touches is not moved to the trash: 409 with trash_blocked and the blocker campaign_in_use in details.blockers. Archive it instead. A campaign that still holds assets goes into the trash, but the second DELETE refuses it with 409 delete_blocked and the blocker campaign_has_assets until they are detached. Deleting for good is refused with 403 for a storefront contact.
  • Trash empty and purge: a call from a storefront contact is 403 with purge_not_allowed. A campaign that a blocker still holds stays in the trash, and the answer names its reason. The purge takes the campaigns that have been in the trash longer than the tenant's trash retention, which is 90 days unless the tenant set another value. When the retention cannot be read, the purge deletes nothing and answers skipped.
  • restore: clears the trash marks and leaves the campaign's other fields as they were. A campaign that is not in the trash is 409 with not_in_trash.
  • attach body: name one asset with one of promotion_id, mailing_id, journey_id, form_id, page_id, library_item_id or ad_campaign_link_id, or with the three fields asset_app, asset_entity and asset_id. asset_entity is optional and defaults from the app (ads gives ad_campaign_links). label is optional. Attaching an asset that is already attached to this campaign answers the existing row.
  • What attach does: a promotion, mailing, journey or form is claimed by writing the campaign's id into its own campaign_ref. A page, a page library item or an ad campaign link is recorded here only.
  • attach errors: 400 with unknown_asset_kind when the app and entity are not something a campaign can hold. 404 when the owning app has no such asset. 409 with asset_claimed when another campaign holds the asset, and campaign_archived when the campaign is archived. 502 with asset_app_unavailable when the owning app does not answer or refuses the write; then nothing is attached. A new attachment answers 201, an existing one 200.
  • detach errors: 404 when the campaign or the asset is unknown. 502 with asset_app_unavailable when the owning app does not answer. The asset stays attached in that case.
  • performance query: model, either first_touch or last_touch. Without it, the tenant's default model applies. A campaign is credited under one model at a time. The answer holds revenue and orders under that model, with returns netted out, redemptions, clicks, impressions, subscriptions and leads, the goal progress, the budget planned and spent with return on ad spend, and per attached asset its revenue, orders, clicks and redemptions. 400 when model is another value, 404 when no campaign has the id. A campaign in the trash can still be read.
  • links body: required url and medium. Optional: source, content and term. The app adds utm_source (the default comes from the app settings), utm_medium and utm_campaign, and optionally utm_content and utm_term. UTM values that the URL already carries are replaced. A campaign without a UTM value gets its code slug the first time.
  • links errors: 409 with utm_campaign_missing when the campaign has no UTM value and its code gives none, or when it has no UTM value and its code slug already belongs to another campaign. Set utm_campaign first.

Assets

OperationScopeWhat it does
GET /v1/campaigns/assetscampaigns.assets.listLists the assets that campaigns hold.
GET /v1/campaigns/assets/{id}campaigns.assets.getReads one asset row.
POST /v1/campaigns/assets/{id}/detachcampaigns.assets.detachReleases the asset that an asset row names. The same as detaching from the campaign, addressed by the asset row.
  • Filters on GET /v1/campaigns/assets: campaign_id for one campaign, or asset_app with asset_id for the campaign that holds one asset. Also asset_entity, label, claim and added_by.
  • Writes: an asset row is created only by attach on a campaign. Both detach routes, the campaign's and the asset row's, remove it.
  • Detach: clears the campaign_ref on the asset, if it still names this campaign, and removes the asset row.

Tasks

OperationScopeWhat it does
GET /v1/campaigns/taskscampaigns.tasks.listLists the campaign tasks.
POST /v1/campaigns/taskscampaigns.tasks.createAdds a task to a campaign.
GET /v1/campaigns/tasks/{id}campaigns.tasks.getReads one task.
PUT /v1/campaigns/tasks/{id}campaigns.tasks.updateCorrects a task.
DELETE /v1/campaigns/tasks/{id}campaigns.tasks.deleteDeletes a task.
POST /v1/campaigns/tasks/{id}/completecampaigns.tasks.completeTicks a task off.
POST /v1/campaigns/tasks/{id}/reopencampaigns.tasks.reopenOpens a task again.
  • POST /v1/campaigns/tasks body: required campaign_id and title. Optional: assignee, due_at, done_at and notes.
  • Filters on GET /v1/campaigns/tasks: campaign_id, title, notes and assignee, each an exact match.
  • complete: stamps done_at with the current time. A task that is already done keeps its first stamp.
  • Calendar: the due dates of tasks appear on the calendar.

Attribution

OperationScopeWhat it does
GET /v1/campaigns/attribution-factscampaigns.attribution.listLists the attribution facts, the ledger of credited orders.
GET /v1/campaigns/attribution-facts/{id}campaigns.attribution.getReads one attribution fact.
POST /v1/campaigns/attribution/sweepcampaigns.attribution.sweepRecords what the orders and redemptions of the last two days owe campaigns.
  • Read-only: no caller writes a fact directly. Facts are written from orders, redemptions and touches, and the sweep records the ones they owe.
  • Filters on GET /v1/campaigns/attribution-facts: campaign_id, order_id, order_number, contact_id, organization_id, currency, market, touch_kind, touch_ref and is_first_touch. limit, offset and order page and sort the list.
  • Returns: a return raises the fact's amount_returned; amount stays. A fact is never deleted.
  • sweep: the hourly schedule, callable by hand. It reads the committed redemptions of attached promotions and the orders placed in the last 48 hours from their own apps, and records facts under the same keys that the event handlers use. It also moves each campaign's effective_state when its window opens or closes.

Touches

OperationScopeWhat it does
GET /v1/campaigns/touchescampaigns.touches.listLists the recorded touches.
POST /v1/campaigns/touchescampaigns.touches.ingestRecords on-site impressions and clicks and ad clicks from the storefront.
GET /v1/campaigns/touches/{id}campaigns.touches.getReads one touch.
  • POST /v1/campaigns/touches body: touches, a list of one to 500 items. Each item has kind (onsite_impression, onsite_click or ad_click) and campaign_id, and optionally at, contact_id, session_key, market, key and ref. Each item is judged on its own. The answer counts recorded and duplicates and names each rejected item by index and reason.
  • Per-item reasons: an item that is not accepted is named in rejected with one of unknown_kind, unknown_campaign, invalid_time or invalid_contact. An item with a key that is already recorded is counted as a duplicate.
  • Filters on GET /v1/campaigns/touches: campaign_id, kind, contact_id, ref, order_id, market, session_key and touch_key.
  • Read-only apart from the ingest: a touch is never edited.

Budgets

OperationScopeWhat it does
GET /v1/campaigns/budgetscampaigns.budgets.listLists the budget lines.
POST /v1/campaigns/budgetscampaigns.budgets.createAdds a budget line.
GET /v1/campaigns/budgets/{id}campaigns.budgets.getReads one budget line.
PUT /v1/campaigns/budgets/{id}campaigns.budgets.updateCorrects a budget line.
DELETE /v1/campaigns/budgets/{id}campaigns.budgets.deleteDeletes a budget line.
  • POST /v1/campaigns/budgets body: required campaign_id and line. Optional: currency, planned, spent and notes.
  • Filters on GET /v1/campaigns/budgets: campaign_id, line, currency, source, platform and notes.
  • Errors: 409 with line_taken when the campaign already has a line of that name. 409 with budget_line_from_ads when a line that the ads app books day by day is edited or deleted by hand, or when a body sends source as ads or sends a platform.

Ad spend

OperationScopeWhat it does
GET /v1/campaigns/spendcampaigns.spend.listLists the booked days of ad spend.
POST /v1/campaigns/spendcampaigns.spend.importBooks daily ad spend into the campaign budgets.
GET /v1/campaigns/spend/{id}campaigns.spend.getReads one booked day.
  • POST /v1/campaigns/spend body: rows, a list of one to 500 rows. Each row books one day of one platform into the campaign's budget line for that platform. Each row has campaign_id, date (YYYY-MM-DD), spend (zero or more), currency and platform. Optional: impressions and clicks, whole numbers.
  • The budget line: each platform books into its own line, ads:<platform>, with :<currency> added when the row's currency differs from the campaign's. The line is created on first use. Booking the same campaign, platform and day again replaces the earlier booking for that day.
  • Answer and per-row reasons: the answer counts booked and replaced and names each rejected row by index and reason, one of not_an_object, unknown_campaign, invalid_date, invalid_spend, invalid_currency or invalid_platform.
  • Filters on GET /v1/campaigns/spend: campaign_id, budget_id, platform, spend_date, currency, impressions and clicks.

Calendar

OperationScopeWhat it does
GET /v1/campaigns/calendarcampaigns.calendar.readReads the dated activity of the campaigns that overlap a range, at most 100 campaigns. Archived campaigns appear only with status=archived. type is a comma list of campaign, mailing, promotion, journey, page and task.
  • Range: from and to are required dates. A bare date as to covers the whole of that day. A to before from is 400. A range can span at most 400 days, or the call is 400.
  • Filters: type, market, status and owner_id.
  • What it holds: campaign windows and due tasks from this app. The send times of mailings, the windows of promotions, the live periods of automations and the publish dates of pages are read from their own apps on every call and are not stored here.
  • sources: the answer says which app answered for each part.

Vocabularies

OperationScopeWhat it does
GET /v1/campaigns/vocabulariescampaigns.vocabularies.listLists the closed vocabularies this app enforces.
GET /v1/campaigns/vocabularies/{name}campaigns.vocabularies.getReads one vocabulary with its values and labels. 404 when there is no such vocabulary.
Was this page helpful?