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
POST /api/v1/plans/manualUse the configured API origin. Private requests require a verified Bearer credential; an agent mutation can additionally require exact approval headers. Authentication guide →
{
"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
{
"description": "Invalid request or unsupported fields",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}401Missing or invalid authentication
{
"description": "Missing or invalid authentication",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}403Permission or product scope refused
{
"description": "Permission or product scope refused",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}404Route or tenant-scoped resource not found
{
"description": "Route or tenant-scoped resource not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}409State, revision, approval, funding or idempotency conflict
{
"description": "State, revision, approval, funding or idempotency conflict",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}422Supplier configuration, capability or upstream refusal
{
"description": "Supplier configuration, capability or upstream refusal",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}429Rate limit reached; wait before retrying
{
"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
{
"description": "Internal error; inspect state before retrying a mutation",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}503Dependency or authentication verifier unavailable
{
"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.
{
"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
{
"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
{
"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."
}
}