---
title: "Validate a deployment plan"
method: POST
path: "/workspaces/{workspace}/admin/plans/{deployment_plan}/validate"
tags: ["DeploymentPlan"]
---

# Validate a deployment plan

`POST /workspaces/{workspace}/admin/plans/{deployment_plan}/validate`

## Request

- Base URL: `https://plainrouter.com/api/v1`
- URL: `https://plainrouter.com/api/v1/workspaces/{workspace}/admin/plans/{deployment_plan}/validate`
- Auth: HTTP bearer

Validate a plan without provider writes. Reuse a ready Meta video in the same ad account; plans needing a new video upload are refused.

## Path parameters

- `workspace` integer, required
- `deployment_plan` string, required

## Response `200`

The plan and its validation result.

- object
  - `plan` DeploymentPlanRead, required: Complete projection rows are paged within 80,000 JSON bytes, accounting for both MCP representations. Defaults are bounded. Follow next_cursor with the same scope and filters. One oversized row is explicitly refused; fields are never silently clipped.
    - `name` string, nullable
    - `id` string, required
    - `platform_ad_account_id` integer, required
    - `review_version` string, required: Current review version. Pass this value when executing the plan you reviewed.
    - `copy` object, nullable
      - `primary_text` string, required
      - `headline` string, required
      - `description` string, required
      - `cta` 'learn_more' | 'shop_now' | 'sign_up', required
    - `landing_page` string
    - `creatives` object[]
      - `id` string, required
      - `position` integer, required
      - `copy` object, nullable, required: Optional complete per-ad copy override; null uses the plan copy.
        - `primary_text` string, required
        - `headline` string, required
        - `description` string, required
        - `cta` 'learn_more' | 'shop_now' | 'sign_up', required
      - `landing_page` string, nullable, required: Optional per-ad HTTPS landing URL override; null uses the plan landing URL.
      - `resolved_copy` object, nullable, required
        - `primary_text` string, required
        - `headline` string, required
        - `description` string, required
        - `cta` 'learn_more' | 'shop_now' | 'sign_up', required
      - `resolved_landing_page` string, required
      - `copy_differs` boolean, required
      - `landing_page_differs` boolean, required
    - `next_cursor` integer, nullable
    - `truncated` boolean
    - `continuation` string
    - `creative_count` integer

## Other responses

- `401`: Invalid or missing Server secret.
- `404`: A missing workspace returns the api_route_not_found envelope.
- `422`: Request and integer selector validation returns message plus field errors. Domain refusals return error.code and error.message, including launch_video_upload_unavailable: New video uploads to Meta are unavailable. Use a video already uploaded to this Meta ad account or choose an image.

---

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