---
title: "Move a plan's dates"
method: POST
path: "/plans/{id}/dates"
---

# Move a plan's dates

`POST /plans/{id}/dates`

## Request

- Base URL: `https://app.distribution.tech/api/v1`
- URL: `https://app.distribution.tech/api/v1/plans/{id}/dates`
- Auth: HTTP bearer

Move a plan awaiting approval to new dates in one step: start and end (YYYY-MM-DD) become the plan's launch window and the campaign's dates, and every creator's post date moves with them, keeping its place in the window (a post three days in stays three days in) and pulled inside the new window when it is shorter. Both happen or neither does. start is today or later, end is on or after start, at most a year apart (conflict, reason bad_dates); two posts by one creator that would land on the same day are refused (conflict, reason same_day) and nothing moves; a signed plan or one the team wrote is refused (conflict, reason plan_signed). Prices do not change. Returns lines_moved and the plan as plan_quote returns it. Needs an idempotency_key. Scope: campaigns:write. MCP tool: plan_move_dates.

## Path parameters

- `id` string, uuid, required

## Headers

- `Idempotency-Key` string, required

## Request body

- MoveDatesInput
  - `start` string, date, required: The new first day, YYYY-MM-DD, today or later.
  - `end` string, date, required: The new last day, YYYY-MM-DD, on or after start, at most a year later.

## Response `200`

OK

- DatesMoved
  - `lines_moved` integer, required: How many creators' post dates moved.
  - `plan` Quote, required: A plan as the person sees it and as an agent signs it (v1-product-spec 8.5 Quote).
    - `plan_id` string, uuid
    - `campaign_id` string, uuid
    - `version` integer
    - `status` 'awaiting_approval' | 'approved'
    - `currency` string
    - `launch_window_start` string, date
    - `launch_window_end` string, date
    - `terms_fingerprint` string: Send exactly this to approve. It changes when a line, a price or the dates change.
    - `total_cents` integer
    - `totals` object: creators, total_cents, views_low, views_high, unmeasured, cpm_low_cents, cpm_high_cents, tiers, budget_cents, remaining_cents.
    - `lines` QuoteLine[]
      - `id` string, uuid, required
      - `creator` object, nullable, required
        - `id` string, uuid: The creator's id, for creator_get. Left out when not known.
        - `name` string, nullable, required
        - `handle` string, nullable, required: The creator's X handle once this plan's order is paid; null before (the name shows before payment).
        - `profile_url` string, nullable, required: The creator's X profile link once this plan's order is paid; null before.
        - `avatar_url` string, uri: The creator's live profile photo. Left out when there is none.
        - `followers` integer: The creator's follower count on the channel. Left out when not measured.
      - `creator_id` string, uuid, nullable, required: The creator's id at the top level (the same as creator.id); null when not known.
      - `unit_id` string, uuid, nullable, required
      - `stage_id` 'planned' | 'offered' | 'creator_confirmed' | 'scheduled' | 'live' | 'proof_attached' | 'cancelled', required: Where this post stands; the same stage model as a campaign's lines_by_stage. Branch on this, never on stage.
      - `stage` string, required: The label for stage_id: Planned, Offered, Creator confirmed, Scheduled, Live, Proof attached, Cancelled.
      - `channel` string, required
      - `channel_label` string, required
      - `format` string, nullable, required
      - `deliverable` string, required
      - `scheduled_date` string, date, required
      - `price_cents` integer, required: The all-in price of this line. Never split into parts.
      - `vetting` string, nullable, required
      - `reason` string, nullable, required
      - `expected_views_low` integer, nullable, required
      - `expected_views_high` integer, nullable, required
      - `on_sale` boolean, required
    - `payment_options` PaymentOption[]
      - `rail` 'checkout' | 'invoice', required
      - `label` string, required
      - `clears` string, required
    - `agent_payment` 'checkout' | 'team_invoice'
    - `brand_terms` object
      - `current_version` string, nullable, required: The current brand terms version id (a date).
      - `current_number` integer, nullable, required: The number the app shows for that version (version 3).
      - `url` string, nullable, required
      - `accepted_for_this_key` string, nullable, required
      - `accepted_number_for_this_key` integer, nullable, required
    - `mandate` Mandate, nullable
      - `key_id` string, uuid
      - `version` integer
      - `max_plan_cents` integer
      - `monthly_cap_cents` integer
      - `channels` string[]
      - `may_approve` boolean
      - `may_exceed_budget` boolean: Retired, always false. No key and no person can approve a plan over its campaign's budget: approve_plan refuses it with over_budget until a creator is removed or the budget is raised.
      - `expires_at` string, date-time
      - `updated_at` string, date-time
      - `spent_this_month_cents` integer
      - `terms_version` string, nullable: The brand terms a person accepted for this key. Null on a mandate that may not sign (the terms govern signing) and on the workspace's own agent key.
      - `terms_accepted_at` string, date-time, nullable
      - `terms_accepted_email` string, nullable
    - `policy` object: allowed: whether this key's mandate lets it sign now; refusal: the reason and numbers when not (over_budget when the plan is over the campaign's budget, which no mandate can approve: remove a creator or have the brand raise the budget).
      - `allowed` boolean
      - `refusal` object, nullable
    - `blocked_lines` string[]
    - `over_budget` object, nullable: The plan over its campaign's budget: budget_cents, total_cents and over_by_cents, at current prices when a creator's price rose past the budget (the plan then keeps its earlier prices, so total_cents alone reads as within it). Null within the budget, with no budget, or once signed. Approval refuses it until a creator is removed or the budget is raised.
      - `budget_cents` integer
      - `total_cents` integer
      - `over_by_cents` integer
    - `order` object, nullable
    - `valid_while` 'terms_fingerprint_unchanged'

## Other responses

- `400`: A parameter is not valid: details.problems names each field and what it accepts.
- `401`: No API key, an unknown one, or a revoked one.
- `403`: The key lacks the scope, or the mandate refuses (mandate_refused, with the limit and how much over).
- `404`: No plan, line or creator of yours has that id.
- `409`: conflict (with a reason), idempotency_conflict, or in_progress (Retry-After).
- `422`: unprocessable: the body is readable but a value cannot be used (a blank or too long name, a campaign that cannot be planned yet); details.problems names each field when there are several.
- `429`: Too many requests for this key in the current minute (60); Retry-After and RateLimit-Reset say when to try again. On POST /campaigns and on POST /plans/current/lines when it starts a plan: the brand's 3 new campaigns in 24 hours are used (details.reason daily_campaign_limit); details.resets_at and Retry-After say when the limit reopens, a rolling 24 hours from the first of them, not a calendar day; archiving or deleting a campaign does not give its slot back. On GET /creators and GET /creators/{id}: a creator read limit is used (details.reason per_minute, daily_lists, daily_reveals, daily_seen or locked). daily_seen is your workspace's one pool of 300 creator views a day (300 different creators shown or opened since midnight UTC), shared by the app and every API key of the brand: details.scope workspace and details.limit 300; a creator already seen today, in the app or through any key, still opens and costs nothing. The other reasons are this key's own limit (details.scope key) or the brand's ceiling over all its keys (details.scope api).
- `500`: internal: the request failed on our side. Retry it with the same Idempotency-Key.
- `503`: unavailable: writes are not available right now (for an approval: payments are not open yet).

---

[API](https://skmtc.dev/distribution/apis/distribution-api.md) · [All operations](https://skmtc.dev/distribution/apis/distribution-api/llms.txt) · [OpenAPI document](https://skmtc.dev/distribution/apis/distribution-api/revisions/5ca6ca44a7c0?raw)
