Skip to main content

Overview

Pacing periods let you express a non-flat campaign flight as a sequence of dated periods, each with its own spend intensity. Use them when a campaign needs to spend more during a holiday window, less during a quiet stretch, or explicit dollar amounts in specific months. When execute_campaign is called, each DRAFT media buy that has no per-buy schedule of its own is split into one package per active period, with budget allocated according to the schedule. You do not have to compute or set per-package budgets yourself.

Weight mode

Express each period as a relative multiplier (1.0 = normal, 2.5 = 150% heavier). Scope3 distributes the campaign budget proportionally by days × weight.

Budget mode

Set explicit dollar amounts per period. Useful when finance hands you a monthly spend plan you must hit exactly.
Pacing splits apply at execute time, for DRAFT buys only. When you call execute_campaign, every DRAFT media buy without its own per-buy schedule is split into one package per period. Live buys (ACTIVE or PAUSED) are not affected when you add or change the campaign pacing plan. You can set the plan before or after creating buys; it takes effect the next time you execute. The API rejects a write if all periods have already elapsed.

Concept

A pacingPeriods object has two fields: Each period has: Periods must be inside the campaign flight dates and must not overlap. Gaps between periods are allowed and are treated as pauses: the campaign spends $0 during a gap.

How to use

Weight mode

Weight mode is the most common: declare the shape, let Scope3 do the math.
When the campaign executes, each product is split four ways with budget proportional to days × weight.

Budget mode

Budget mode pins explicit dollars to each period. The sum of period budgets must not exceed budget.total on the campaign; anything left over stays as unallocated headroom.

Updating a schedule

PUT /api/v2/buyer/campaigns/:id accepts the full pacingPeriods object. To clear an existing schedule, send "pacingPeriods": null.
Periods that have already started or ended cannot be modified or removed. Updates may only change future periods. Changing the mode is rejected if any existing period is already in progress or past.

Live cascade for appended periods

When you append new periods to a campaign that already has paced live media buys, Scope3 automatically pushes the new period packages to those media buys via ADCP 3.0 update_media_buy.new_packages. The result is returned on the update response as pacingCascadeResult.

What gets cascaded

Only strict appends are cascaded: the new pacingPeriods.periods array must start with the same items as the existing schedule. Insertions in the middle, modifications of an existing period, removals, and mode changes return pacingCascadeResult.attempted: false with a notAppendedReason and require manually creating new media buys to apply. Only media buys that were already paced (executed with pacingPeriods set on the campaign at execution time) are eligible. Unpaced media buys are reported with outcome: "skipped", reason: "unpaced". To apply pacing, create a new media buy.

Agent capability

Each seller agent must advertise add_packages in its valid_actions to accept new packages mid-flight. Agents that don’t are reported with outcome: "unsupported". Manual workaround: create new media buys for the appended periods on those agents.

Response shape

The block is omitted when pacingPeriods is not part of the update payload.

Per-media-buy pacing

Campaign-level pacingPeriods shapes the whole campaign: every paced media buy under it follows the same schedule. When you only want to shape one media buy (heavy-up on a specific publisher with seasonal or event-driven inventory, leave the rest flat), set pacingPeriods on the mediaBuys[] entry of update_campaign instead. The per-buy schedule replaces the campaign-level shape for that specific buy. It uses the same mode + periods[] shape as the campaign-level field.

Behavior by media buy state

Pass "pacingPeriods": null to clear an existing per-buy schedule. The column is cleared but any deployed period packages keep running. To stop spend on a deployed window, cancel those packages directly. Periods must lie inside the media buy’s flight (not the campaign’s), must not overlap, and follow the same future-only update rules as the campaign-level field. In response shapes, each per-buy period includes a resolved budget computed from the sum of the buy’s product budgets. When per-buy pacing is set on the same update_campaign call as mediaBuys[].creative_ids (or relies on auto-sync from the campaign manifest), the appended period packages inherit those creatives in the same seller request. There is no separate creative-attach step.

Budget reductions

Lowering campaign budget.total through update_campaign can also reduce live package budgets. If the new media budget is below current live package allocations, Scope3 proportionally reduces eligible live package budgets, including period packages created from pacing periods. Explicit mediaBuys[].packages[].budget values in the same request take precedence over proportional scaling. If Scope3 cannot apply a generated seller budget update, the campaign budget is not lowered. This keeps campaign budget and live package allocations in sync.

Response shape

Campaign GET responses surface the schedule with resolved budgets for every period. In weight mode, the resolved dollar amount is computed by (days × weight) proportional split of budget.total; weights are preserved alongside the resolved budget so you can audit the math.
unallocatedBudget is the dollar gap between budget.total and allocatedBudget (the sum of active media buy budgets plus delivered spend on ended or archived media buys, all gross and fee-inclusive), telling you how much room is left for new media buys to fill the schedule. It can go negative when delivered spend on ended buys exceeds budget.total.

Automatic package splitting

When a campaign with pacing periods executes:
1

Resolve per-product budgets

Each selected product gets a budget, either set by the user or derived from a discovery proposal.
2

Split per period

For every product, Scope3 creates one package per pacing period. In weight mode, the per-period budget is (days × weight) / sum(all weighted days) × product_budget. In budget mode, each period’s fixed budget is split across products proportionally to each product’s share of total product budgets.
3

Round to last

Each period after the first uses banker’s rounding to two decimals; the last period absorbs any rounding remainder so per-product totals match exactly.
4

Submit to sales agent

The split packages are sent to the sales agent as the media buy composition. Each package carries its own start, end, and budget.
This means a campaign with 10 products and 4 periods produces 40 packages on execution, each one a discrete dated bucket of spend.

Validation

The campaign endpoints validate pacingPeriods against the campaign before saving:
  • Date order: every period’s start must be ≤ end.
  • Inside flight: every period must lie within flightDates.startDate and flightDates.endDate.
  • No overlaps: when sorted by start, no period may begin on or before the previous period’s end.
  • Budget sum (budget mode): the sum of period budgets must not exceed budget.total.
  • Required fields per mode: weight periods need a weight; budget periods need a budget.
  • Update safety: a period that has already started cannot be changed or removed; the mode cannot change while any period is in progress or past.
A failing validation returns a 400 with a clear error message identifying the offending period by label.

Best practices

  • Start in weight mode. It’s easier to reason about “2× during the holiday week” than to recompute exact dollar splits when the budget moves.
  • Use labels generously. Period labels show up in package metadata and in reporting; names like "July 4th heavy" beat "Period 2".
  • Keep periods aligned with media buy intent. A media buy can have any start/end inside the campaign flight, but matching its dates to a period boundary keeps reporting clean.
  • Treat gaps as pauses. If you don’t want spend on July 16–18, leave that range out of periods rather than setting weight: 0 (which is rejected as non-positive).
  • Plan ahead: past periods are immutable. Once a period starts, its shape is locked. Front-load decisions you might need to revisit.
  • Cap period count. The schema allows up to 52 periods; in practice, monthly or weekly granularity is plenty.

Limits