How to plan a flight in Tempio
A brief becomes a media plan, the plan becomes items with a whole-flight budget per platform, and materializing the plan produces one draft batch per connection. Nothing is launched — a plan makes drafts. This note is the method and the rules that refuse a plan.
Last reviewed 2026-09-13.
A media plan is the one ads surface that is free to edit: nothing in it touches live spend, so there is no approval gate on writing one. Ungated is not unrecorded — every write lands an audit row — and the moment a plan meets the platforms, it does so as drafts.
Planning
The shape is brief → plan → items → drafts.
A plan carries a name, an optional brief, a start and end date, and exactly one currency. One currency per plan is not a simplification; it is the same law the metrics layer follows, and it is what makes a plan's total a number rather than a digit count.
An item is one platform's share of the flight: a platform, a name, an optional objective, a whole-flight budget in minor units of the plan's currency, its own start and end dates, and optionally an explicit ad account. An item's flight must sit inside the plan's window, in both directions — so narrowing a plan window under existing items is refused too. A budget that is not a whole number at or above zero is refused with the number that failed.
Before choosing the channel mix, read the platform's playbook. tempio://playbooks
is the index of everything published; one document is
tempio://playbooks/{platform}/{topic}, which is the slug — platform/topic —
after the scheme. Playbooks are published per platform as they are written;
when there is none for a platform you are about to plan on, say so rather than
implying the choice was informed. Tempio's own operating notes — this one,
tempio://playbooks/tempio/money, tempio://playbooks/tempio/guardrails — are
on the shelf now.
Doing
Account resolution. An item names an ad account explicitly, or it resolves
to one. The rule is deliberately unambitious: an explicit adAccountId must
belong to the workspace and be on the item's platform, or it does not
resolve; with no explicit account, the item resolves only when the workspace
has exactly one ad account on that platform. Two accounts on a platform and
no choice made is an unresolved item, and the plan refuses to materialize until
someone picks. A guess between two accounts would be a guess about where
money goes.
Materializing. materializePlan walks the items and, for each, re-checks
the window, the budget and the account, then converts the whole-flight total to
a daily figure over the inclusive flight, converts the planned days to
instants in the ad account's own time zone (the flight's stop is exclusive),
and stamps the plan's currency. It refuses the whole plan when any item has no
account, and it refuses when any resolved account bills in a different currency
from the plan.
Then the guardrails run as a pre-flight, using the same function the draft batch and the approval claim use, so the three cannot disagree. The kill switch is checked per connection. A veto on the last item must not leave the first connection's batch sitting in the queue, which is why the check runs across every item before a single row is written.
What comes out is one draft batch per connection, items keeping their board
order inside it, each a create_campaign row at pending_approval linked back
to the plan item it came from. If a later batch fails, the batches already
created are rejected as a rollback, and both stories are in the audit log.
What "launch" means here
Nothing. A plan makes drafts. Materializing a plan starts no spend, changes
no live campaign and tells no platform anything: it fills the review queue with
rows that are approved by a person, by an MCP key holding approve, or by a
rule the workspace wrote — and a create_campaign is on the list no rule may
ever clear, so a materialized plan always waits for one of the first two.
Do not say a plan was launched, went live, or started running. Say it was drafted, say how many drafts and on which connections, and give the review link. The one sentence worth repeating to whoever asked: the plan is ready, and nothing spends until someone approves it.
Sources
- createPlan, upsertPlanItem, resolveAccount, materializePlan —
repo://apps/app/lib/ads/plans.service.ts(read 2026-09-13) - create_media_plan, upsert_plan_item, materialize_plan —
repo://apps/app/lib/ads/tools/plan-tools.ts(read 2026-09-13) - flightToInstants — a planned day becomes an instant in the account's zone —
repo://apps/app/lib/ads/flight-dates.ts(read 2026-09-13) - createDraftBatch — what a materialized plan becomes —
repo://apps/app/lib/ads/drafts/batch.ts(read 2026-09-13) - Plans — the product page for the same flow —
repo://apps/docs/content/docs/plans/index.mdx(read 2026-09-13)