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. Whenexecute_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
ApacingPeriods 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.days × weight.
Budget mode
Budget mode pins explicit dollars to each period. The sum of period budgets must not exceedbudget.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.
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.0update_media_buy.new_packages. The result is returned on
the update response as pacingCascadeResult.
What gets cascaded
Only strict appends are cascaded: the newpacingPeriods.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 advertiseadd_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
pacingPeriods is not part of the update payload.
Per-media-buy pacing
Campaign-levelpacingPeriods 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 campaignbudget.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
CampaignGET 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.Validation
The campaign endpoints validatepacingPeriods against the campaign before
saving:
- Date order: every period’s
startmust be ≤end. - Inside flight: every period must lie within
flightDates.startDateandflightDates.endDate. - No overlaps: when sorted by
start, no period may begin on or before the previous period’send. - 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 abudget. - 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.
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
periodsrather than settingweight: 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.