← All API operations

POST /api/v1/plans/manual

Create a plan from selected inventory

Creates a draft plan from exact inventory choices and budget allocations. Availability and prices remain subject to the configured supplier and execution mode.

Authenticated and advertiser scoped. Cross-tenant resource access returns 404. Product/channel entitlements also apply.

The request schema is generated from the runtime Zod input validator. Cross-field refinements and state-dependent constraints are additionally enforced by the API.

Request

HTTP
POST /api/v1/plans/manual

Use the configured API origin. Private requests require a verified Bearer credential; an agent mutation can additionally require exact approval headers. Authentication guide →

Request body contract
{
  "required": true,
  "content": {
    "application/json": {
      "schema": {
        "type": "object",
        "properties": {
          "personaId": {
            "type": "string"
          },
          "budgetMinor": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "maximum": 1900000000
          },
          "currency": {
            "type": "string",
            "const": "GBP",
            "default": "GBP"
          },
          "goal": {
            "type": "string",
            "enum": [
              "awareness",
              "consideration",
              "performance"
            ]
          },
          "startDate": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "endDate": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "commercialBrief": {
            "type": "object",
            "properties": {
              "productOrOffer": {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              },
              "landingPageUrl": {
                "type": "string",
                "maxLength": 2048,
                "format": "uri"
              },
              "primaryKpi": {
                "type": "string",
                "enum": [
                  "reach",
                  "brand-awareness",
                  "consideration",
                  "site-visits",
                  "leads",
                  "sales",
                  "app-installs",
                  "custom"
                ]
              },
              "conversionDefinition": {
                "type": "string",
                "minLength": 1,
                "maxLength": 300
              },
              "outcomeSource": {
                "type": "string",
                "enum": [
                  "campaign-tracking",
                  "analytics",
                  "crm",
                  "commerce",
                  "offline",
                  "none"
                ]
              },
              "targetValueMinor": {
                "type": "integer",
                "minimum": 0,
                "maximum": 2000000000
              },
              "baselineWeeklyConversions": {
                "type": "integer",
                "minimum": 0,
                "maximum": 10000000
              },
              "priorMonthlyMediaSpendMinor": {
                "type": "integer",
                "minimum": 0,
                "maximum": 2000000000
              },
              "existingMediaMix": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "ctv",
                    "audio",
                    "tv",
                    "cinema",
                    "dooh",
                    "search",
                    "social",
                    "display",
                    "email",
                    "print",
                    "other"
                  ]
                },
                "maxItems": 11
              },
              "firstPartyDataAvailability": {
                "type": "string",
                "enum": [
                  "none",
                  "limited",
                  "ready"
                ]
              },
              "creativeReadiness": {
                "type": "string",
                "enum": [
                  "needs-production",
                  "in-progress",
                  "ready"
                ]
              },
              "containsEuPoliticalAdvertising": {
                "type": "boolean"
              },
              "containsPoliticalAdvertising": {
                "type": "boolean"
              },
              "containsHfssAdvertising": {
                "type": "boolean"
              },
              "measurementIntent": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "delivered",
                    "responded",
                    "caused",
                    "remembered"
                  ]
                },
                "minItems": 1,
                "maxItems": 4
              },
              "exclusions": {
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 300
                },
                "maxItems": 20
              },
              "mandatories": {
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 300
                },
                "maxItems": 20
              }
            },
            "required": [
              "productOrOffer",
              "primaryKpi",
              "outcomeSource",
              "existingMediaMix",
              "firstPartyDataAvailability",
              "creativeReadiness",
              "measurementIntent",
              "exclusions",
              "mandatories"
            ],
            "additionalProperties": false
          },
          "selections": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "channel": {
                  "type": "string",
                  "enum": [
                    "ctv",
                    "audio",
                    "tv",
                    "cinema",
                    "dooh",
                    "search",
                    "social"
                  ]
                },
                "adapterKey": {
                  "type": "string",
                  "minLength": 1
                },
                "itemIds": {
                  "type": "array",
                  "items": {
                    "type": "string",
                    "minLength": 1
                  },
                  "minItems": 1
                }
              },
              "required": [
                "channel",
                "adapterKey",
                "itemIds"
              ],
              "additionalProperties": false
            },
            "minItems": 1
          }
        },
        "required": [
          "budgetMinor",
          "goal",
          "startDate",
          "endDate",
          "selections"
        ],
        "additionalProperties": false
      }
    }
  }
}

Responses

Reference schemas resolve through the downloadable OpenAPI components. The specification marks unmodeled success payloads; an unrestricted payload is not a promise that arbitrary fields exist.

400Invalid request or unsupported fields
Response contract
{
  "description": "Invalid request or unsupported fields",
  "content": {
    "application/json": {
      "schema": {
        "$ref": "#/components/schemas/Error"
      }
    }
  }
}
401Missing or invalid authentication
Response contract
{
  "description": "Missing or invalid authentication",
  "content": {
    "application/json": {
      "schema": {
        "$ref": "#/components/schemas/Error"
      }
    }
  }
}
403Permission or product scope refused
Response contract
{
  "description": "Permission or product scope refused",
  "content": {
    "application/json": {
      "schema": {
        "$ref": "#/components/schemas/Error"
      }
    }
  }
}
404Route or tenant-scoped resource not found
Response contract
{
  "description": "Route or tenant-scoped resource not found",
  "content": {
    "application/json": {
      "schema": {
        "$ref": "#/components/schemas/Error"
      }
    }
  }
}
409State, revision, approval, funding or idempotency conflict
Response contract
{
  "description": "State, revision, approval, funding or idempotency conflict",
  "content": {
    "application/json": {
      "schema": {
        "$ref": "#/components/schemas/Error"
      }
    }
  }
}
422Supplier configuration, capability or upstream refusal
Response contract
{
  "description": "Supplier configuration, capability or upstream refusal",
  "content": {
    "application/json": {
      "schema": {
        "$ref": "#/components/schemas/Error"
      }
    }
  }
}
429Rate limit reached; wait before retrying
Response contract
{
  "description": "Rate limit reached; wait before retrying",
  "headers": {
    "x-ratelimit-limit": {
      "description": "Maximum requests permitted in the current rate-limit window.",
      "schema": {
        "type": "integer"
      }
    },
    "x-ratelimit-remaining": {
      "description": "Requests remaining in the current window.",
      "schema": {
        "type": "integer"
      }
    },
    "x-ratelimit-reset": {
      "description": "Seconds until the current rate-limit window resets.",
      "schema": {
        "type": "integer"
      }
    },
    "retry-after": {
      "description": "Minimum seconds to wait before retrying.",
      "schema": {
        "type": "integer"
      }
    }
  },
  "content": {
    "application/json": {
      "schema": {
        "$ref": "#/components/schemas/Error"
      }
    }
  }
}
500Internal error; inspect state before retrying a mutation
Response contract
{
  "description": "Internal error; inspect state before retrying a mutation",
  "content": {
    "application/json": {
      "schema": {
        "$ref": "#/components/schemas/Error"
      }
    }
  }
}
503Dependency or authentication verifier unavailable
Response contract
{
  "description": "Dependency or authentication verifier unavailable",
  "content": {
    "application/json": {
      "schema": {
        "$ref": "#/components/schemas/Error"
      }
    }
  }
}
2XXSuccessful response. Response schema completeness: envelope-only. The request contract is complete; nested service payloads are not yet fully modeled in OpenAPI. Inspect returned fields before generating a typed SDK.
Response contract
{
  "description": "Successful response. Response schema completeness: envelope-only. The request contract is complete; nested service payloads are not yet fully modeled in OpenAPI. Inspect returned fields before generating a typed SDK.",
  "headers": {
    "x-ratelimit-limit": {
      "description": "Maximum requests permitted in the current rate-limit window.",
      "schema": {
        "type": "integer"
      }
    },
    "x-ratelimit-remaining": {
      "description": "Requests remaining in the current window.",
      "schema": {
        "type": "integer"
      }
    },
    "x-ratelimit-reset": {
      "description": "Seconds until the current rate-limit window resets.",
      "schema": {
        "type": "integer"
      }
    }
  },
  "content": {
    "application/json": {
      "schema": {
        "type": "object",
        "properties": {
          "plan": {
            "type": "object",
            "properties": {},
            "additionalProperties": true
          }
        },
        "required": [
          "plan"
        ],
        "additionalProperties": true
      }
    }
  }
}

Operation constraints

Machine-readable metadata
{
  "x-response-schema-completeness": "envelope-only",
  "x-rate-limit": {
    "requests": 300,
    "windowMilliseconds": 60000,
    "key": "request IP",
    "headers": [
      "x-ratelimit-limit",
      "x-ratelimit-remaining",
      "x-ratelimit-reset"
    ]
  },
  "x-idempotency": {
    "policy": "not-generalized",
    "note": "There is no universal Idempotency-Key middleware. Only the documented endpoint mechanisms protect retries."
  }
}

Complete operation

OpenAPI
{
  "operationId": "post_api_v1_plans_manual",
  "summary": "Create a plan from selected inventory",
  "description": "Creates a draft plan from exact inventory choices and budget allocations. Availability and prices remain subject to the configured supplier and execution mode.\n\nAuthenticated and advertiser scoped. Cross-tenant resource access returns 404. Product/channel entitlements also apply.\n\nThe request schema is generated from the runtime Zod input validator. Cross-field refinements and state-dependent constraints are additionally enforced by the API.",
  "tags": [
    "Plans"
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "parameters": [],
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "type": "object",
          "properties": {
            "personaId": {
              "type": "string"
            },
            "budgetMinor": {
              "type": "integer",
              "exclusiveMinimum": 0,
              "maximum": 1900000000
            },
            "currency": {
              "type": "string",
              "const": "GBP",
              "default": "GBP"
            },
            "goal": {
              "type": "string",
              "enum": [
                "awareness",
                "consideration",
                "performance"
              ]
            },
            "startDate": {
              "type": "string",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
            },
            "endDate": {
              "type": "string",
              "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
            },
            "commercialBrief": {
              "type": "object",
              "properties": {
                "productOrOffer": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                },
                "landingPageUrl": {
                  "type": "string",
                  "maxLength": 2048,
                  "format": "uri"
                },
                "primaryKpi": {
                  "type": "string",
                  "enum": [
                    "reach",
                    "brand-awareness",
                    "consideration",
                    "site-visits",
                    "leads",
                    "sales",
                    "app-installs",
                    "custom"
                  ]
                },
                "conversionDefinition": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 300
                },
                "outcomeSource": {
                  "type": "string",
                  "enum": [
                    "campaign-tracking",
                    "analytics",
                    "crm",
                    "commerce",
                    "offline",
                    "none"
                  ]
                },
                "targetValueMinor": {
                  "type": "integer",
                  "minimum": 0,
                  "maximum": 2000000000
                },
                "baselineWeeklyConversions": {
                  "type": "integer",
                  "minimum": 0,
                  "maximum": 10000000
                },
                "priorMonthlyMediaSpendMinor": {
                  "type": "integer",
                  "minimum": 0,
                  "maximum": 2000000000
                },
                "existingMediaMix": {
                  "type": "array",
                  "items": {
                    "type": "string",
                    "enum": [
                      "ctv",
                      "audio",
                      "tv",
                      "cinema",
                      "dooh",
                      "search",
                      "social",
                      "display",
                      "email",
                      "print",
                      "other"
                    ]
                  },
                  "maxItems": 11
                },
                "firstPartyDataAvailability": {
                  "type": "string",
                  "enum": [
                    "none",
                    "limited",
                    "ready"
                  ]
                },
                "creativeReadiness": {
                  "type": "string",
                  "enum": [
                    "needs-production",
                    "in-progress",
                    "ready"
                  ]
                },
                "containsEuPoliticalAdvertising": {
                  "type": "boolean"
                },
                "containsPoliticalAdvertising": {
                  "type": "boolean"
                },
                "containsHfssAdvertising": {
                  "type": "boolean"
                },
                "measurementIntent": {
                  "type": "array",
                  "items": {
                    "type": "string",
                    "enum": [
                      "delivered",
                      "responded",
                      "caused",
                      "remembered"
                    ]
                  },
                  "minItems": 1,
                  "maxItems": 4
                },
                "exclusions": {
                  "type": "array",
                  "items": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 300
                  },
                  "maxItems": 20
                },
                "mandatories": {
                  "type": "array",
                  "items": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 300
                  },
                  "maxItems": 20
                }
              },
              "required": [
                "productOrOffer",
                "primaryKpi",
                "outcomeSource",
                "existingMediaMix",
                "firstPartyDataAvailability",
                "creativeReadiness",
                "measurementIntent",
                "exclusions",
                "mandatories"
              ],
              "additionalProperties": false
            },
            "selections": {
              "type": "array",
              "items": {
                "type": "object",
                "properties": {
                  "channel": {
                    "type": "string",
                    "enum": [
                      "ctv",
                      "audio",
                      "tv",
                      "cinema",
                      "dooh",
                      "search",
                      "social"
                    ]
                  },
                  "adapterKey": {
                    "type": "string",
                    "minLength": 1
                  },
                  "itemIds": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "minLength": 1
                    },
                    "minItems": 1
                  }
                },
                "required": [
                  "channel",
                  "adapterKey",
                  "itemIds"
                ],
                "additionalProperties": false
              },
              "minItems": 1
            }
          },
          "required": [
            "budgetMinor",
            "goal",
            "startDate",
            "endDate",
            "selections"
          ],
          "additionalProperties": false
        }
      }
    }
  },
  "responses": {
    "400": {
      "description": "Invalid request or unsupported fields",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Error"
          }
        }
      }
    },
    "401": {
      "description": "Missing or invalid authentication",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Error"
          }
        }
      }
    },
    "403": {
      "description": "Permission or product scope refused",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Error"
          }
        }
      }
    },
    "404": {
      "description": "Route or tenant-scoped resource not found",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Error"
          }
        }
      }
    },
    "409": {
      "description": "State, revision, approval, funding or idempotency conflict",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Error"
          }
        }
      }
    },
    "422": {
      "description": "Supplier configuration, capability or upstream refusal",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Error"
          }
        }
      }
    },
    "429": {
      "description": "Rate limit reached; wait before retrying",
      "headers": {
        "x-ratelimit-limit": {
          "description": "Maximum requests permitted in the current rate-limit window.",
          "schema": {
            "type": "integer"
          }
        },
        "x-ratelimit-remaining": {
          "description": "Requests remaining in the current window.",
          "schema": {
            "type": "integer"
          }
        },
        "x-ratelimit-reset": {
          "description": "Seconds until the current rate-limit window resets.",
          "schema": {
            "type": "integer"
          }
        },
        "retry-after": {
          "description": "Minimum seconds to wait before retrying.",
          "schema": {
            "type": "integer"
          }
        }
      },
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Error"
          }
        }
      }
    },
    "500": {
      "description": "Internal error; inspect state before retrying a mutation",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Error"
          }
        }
      }
    },
    "503": {
      "description": "Dependency or authentication verifier unavailable",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Error"
          }
        }
      }
    },
    "2XX": {
      "description": "Successful response. Response schema completeness: envelope-only. The request contract is complete; nested service payloads are not yet fully modeled in OpenAPI. Inspect returned fields before generating a typed SDK.",
      "headers": {
        "x-ratelimit-limit": {
          "description": "Maximum requests permitted in the current rate-limit window.",
          "schema": {
            "type": "integer"
          }
        },
        "x-ratelimit-remaining": {
          "description": "Requests remaining in the current window.",
          "schema": {
            "type": "integer"
          }
        },
        "x-ratelimit-reset": {
          "description": "Seconds until the current rate-limit window resets.",
          "schema": {
            "type": "integer"
          }
        }
      },
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "plan": {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              }
            },
            "required": [
              "plan"
            ],
            "additionalProperties": true
          }
        }
      }
    }
  },
  "x-response-schema-completeness": "envelope-only",
  "x-rate-limit": {
    "requests": 300,
    "windowMilliseconds": 60000,
    "key": "request IP",
    "headers": [
      "x-ratelimit-limit",
      "x-ratelimit-remaining",
      "x-ratelimit-reset"
    ]
  },
  "x-idempotency": {
    "policy": "not-generalized",
    "note": "There is no universal Idempotency-Key middleware. Only the documented endpoint mechanisms protect retries."
  }
}
Download the complete specification, including shared schema components →