{
  "openapi": "3.1.0",
  "jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
  "info": {
    "title": "Nano Ad Studio API",
    "version": "1.0.0",
    "description": "Create and retrieve photo, video, and animation ads with an active Business subscription and a Nano API key.\n\nSend Authorization: Bearer <key> on every request. Create and revoke keys in Nano Settings → Developer.\n\nEstimate first, create a plan, review its direction or shot list, then render the planned ad.\n\nA 202 response acknowledges an operation. Poll its status_url to observe planning or rendering.\n\nPhoto estimates separate planning and rendering ceilings. Motion estimates include planning and reserved rendering.\n\nCredits ceilings limit admitted work. Settlement charges actual usage.\n\nKeep each paid request body and Idempotency-Key for retries. Edited bodies and separate operations need new keys.\n\nKeys deduplicate requests across API keys belonging to the same account. Never replace a key after a lost response.\n\nAll failures use the Error envelope. Preserve request_id when contacting support.\n\nHonor Retry-After on 429 responses. Retry transient failures with bounded backoff and the original paid request key.\n\nDo not retry permanent validation, ownership, or entitlement errors without resolving their cause.",
    "contact": {
      "name": "Nano Ad Studio",
      "email": "support@nanoadstudio.com",
      "url": "https://nanoadstudio.com"
    }
  },
  "servers": [
    {
      "url": "https://api.nanoadstudio.com/v1",
      "description": "Nano Ad Studio public API"
    }
  ],
  "security": [
    {
      "NanoApiKey": []
    }
  ],
  "tags": [
    {
      "name": "Ads",
      "description": "Plan, review, render, and retrieve owned ads."
    },
    {
      "name": "Account",
      "description": "Read the available Credits balance and owned brands and offerings."
    },
    {
      "name": "Estimates",
      "description": "Estimate Credits before admitting paid work."
    }
  ],
  "paths": {
    "/ads": {
      "get": {
        "operationId": "listAds",
        "tags": [
          "Ads"
        ],
        "summary": "List your ads",
        "description": "Return active owned ads in newest-first order. Only limit and cursor query parameters are accepted. Duplicate parameters are rejected.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of ads. Use next_cursor when has_more is true.",
            "headers": {
              "X-Request-Id": {
                "description": "Request identifier for support and error correlation.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Public API responses use private, no-store.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdList"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidRequest"
          },
          "401": {
            "$ref": "#/components/responses/InvalidApiKey"
          },
          "403": {
            "$ref": "#/components/responses/BusinessRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "operationId": "createAdPlan",
        "tags": [
          "Ads"
        ],
        "summary": "Create an ad plan",
        "description": "Admit paid planning for one photo, video, or animation. This operation does not start the final render.\n\nPhoto planning can return planned with a direction. Motion planning starts queued and completes asynchronously.\n\nPoll status_url until planned, inspect direction for photos or shot_list for motion, then call the render operation.\n\nChoose an optional brand_id for a brand-wide ad or offering_id for one offering. Both must identify active owned records. Do not supply both.\n\nBusiness context organizes ads. Generation uses the prompt and selected reference images, without hidden brand facts.\n\nSupplied strings are trimmed before contract validation.\n\nRetries with the original key and body replay the saved acceptance response, including after an API-key change within the same account.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/PolicyConfirmation"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Choose photo, video, or animation. Photo requests cannot contain duration.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AdCreateRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Planning was accepted. status_url is relative to the API origin, not the /v1 base path.",
            "headers": {
              "X-Request-Id": {
                "description": "Request identifier for support and error correlation.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Public API responses use private, no-store.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdAccepted"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidRequest"
          },
          "401": {
            "$ref": "#/components/responses/InvalidApiKey"
          },
          "402": {
            "$ref": "#/components/responses/InsufficientCredits"
          },
          "403": {
            "$ref": "#/components/responses/BusinessRequired"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "422": {
            "$ref": "#/components/responses/OperationRejected"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/ads/{id}": {
      "get": {
        "operationId": "getAd",
        "tags": [
          "Ads"
        ],
        "summary": "Read an ad and its outputs",
        "description": "Read an owned active ad, its current status, billing, editable plan, and available outputs.\n\nUse planned as the review point before rendering. A failed status can occur during planning or rendering.\n\nA generation failure appears in the ad error field even when this read succeeds with HTTP 200.\n\nEach output download_url expires 15 minutes after this read mints it. Use expires_at and read the ad again for fresh URLs.\n\nTreat download URLs as temporary credentials. Do not infer completion from an empty output list alone.",
        "parameters": [
          {
            "$ref": "#/components/parameters/AdId"
          }
        ],
        "responses": {
          "200": {
            "description": "Current ad state. Unavailable plan fields are null.",
            "headers": {
              "X-Request-Id": {
                "description": "Request identifier for support and error correlation.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Public API responses use private, no-store.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ad"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/InvalidApiKey"
          },
          "403": {
            "$ref": "#/components/responses/BusinessRequired"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/ads/{id}/render": {
      "post": {
        "operationId": "renderAd",
        "tags": [
          "Ads"
        ],
        "summary": "Render a reviewed ad plan",
        "description": "Admit rendering for a planned ad. Omit the body or send {} to use its saved plan.\n\nFor a photo, send direction to revise the plan. For video or animation, send shot_list instead.\n\nThe opposite field is rejected even though the shared request schema describes both ad types.\n\nUse a new Idempotency-Key for the render operation. Keep that key and body for every retry of that render.\n\nA new render key after admission returns invalid_state. Retry the original request to recover its result.\n\nA 202 response can report succeeded when rendering requires no additional work. Otherwise poll status_url.",
        "parameters": [
          {
            "$ref": "#/components/parameters/AdId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/PolicyConfirmation"
          }
        ],
        "requestBody": {
          "required": false,
          "description": "Optional JSON body. direction applies to photos. shot_list applies to video and animation.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AdRenderRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Rendering was accepted or the existing output satisfied the request.",
            "headers": {
              "X-Request-Id": {
                "description": "Request identifier for support and error correlation.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Public API responses use private, no-store.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdAccepted"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidRequest"
          },
          "401": {
            "$ref": "#/components/responses/InvalidApiKey"
          },
          "402": {
            "$ref": "#/components/responses/InsufficientCredits"
          },
          "403": {
            "$ref": "#/components/responses/BusinessRequired"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "422": {
            "$ref": "#/components/responses/OperationRejected"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/credits": {
      "get": {
        "operationId": "getCredits",
        "tags": [
          "Account"
        ],
        "summary": "Read available Credits",
        "description": "Read the account balance available for new work. Existing holds can reduce the available balance.",
        "responses": {
          "200": {
            "description": "Available Credits, bounded below by zero.",
            "headers": {
              "X-Request-Id": {
                "description": "Request identifier for support and error correlation.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Public API responses use private, no-store.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Credits"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/InvalidApiKey"
          },
          "403": {
            "$ref": "#/components/responses/BusinessRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/estimates": {
      "post": {
        "operationId": "estimateAd",
        "tags": [
          "Estimates"
        ],
        "summary": "Estimate an ad before planning",
        "description": "Estimate Credits without starting generation or reserving Credits. No Idempotency-Key is required.\n\nFor photos, ceiling_credits estimates planning and render_ceiling_credits estimates the separate render.\n\nFor video and animation, ceiling_credits covers planning and the reserved rendering budget. render_ceiling_credits is absent.\n\nThe accepted creation or render response supplies its admission ceiling. An estimate is not a guarantee of later admission.\n\nChoose an optional brand_id or offering_id, never both. The selected record must be active and owned.",
        "requestBody": {
          "required": true,
          "description": "The same creative inputs accepted by ad planning.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EstimateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Credits ceilings for the supplied creative inputs.",
            "headers": {
              "X-Request-Id": {
                "description": "Request identifier for support and error correlation.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Public API responses use private, no-store.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Estimate"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidRequest"
          },
          "401": {
            "$ref": "#/components/responses/InvalidApiKey"
          },
          "403": {
            "$ref": "#/components/responses/BusinessRequired"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "$ref": "#/components/responses/RequestTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/brands": {
      "get": {
        "operationId": "listBrands",
        "tags": [
          "Account"
        ],
        "summary": "List your brands",
        "description": "Return active owned brands, including those without offerings. Use an id as brand_id for a brand-wide ad.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of brands. Cursors belong to the current account and collection.",
            "headers": {
              "X-Request-Id": {
                "description": "Request identifier for support and error correlation.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Public API responses use private, no-store.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BrandList"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidRequest"
          },
          "401": {
            "$ref": "#/components/responses/InvalidApiKey"
          },
          "403": {
            "$ref": "#/components/responses/BusinessRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/offerings": {
      "get": {
        "operationId": "listOfferings",
        "tags": [
          "Account"
        ],
        "summary": "List your catalog offerings",
        "description": "Return active owned catalog offerings in newest-first order. Use an id as offering_id when estimating or planning. Only limit and cursor are accepted.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of offerings. Cursors belong to the current account and collection.",
            "headers": {
              "X-Request-Id": {
                "description": "Request identifier for support and error correlation.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Public API responses use private, no-store.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OfferingList"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidRequest"
          },
          "401": {
            "$ref": "#/components/responses/InvalidApiKey"
          },
          "403": {
            "$ref": "#/components/responses/BusinessRequired"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          },
          "default": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "NanoApiKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "Nano API key",
        "description": "Use a Nano API key from an account with an active Business subscription."
      }
    },
    "parameters": {
      "AdId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "Owned ad identifier from a creation or list response.",
        "schema": {
          "type": "string",
          "minLength": 1
        }
      },
      "Limit": {
        "name": "limit",
        "in": "query",
        "description": "Maximum items per page. Supply this parameter once.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 20
        }
      },
      "Cursor": {
        "name": "cursor",
        "in": "query",
        "description": "Opaque next_cursor from the preceding page. Do not construct or reuse across accounts or collections.",
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 2000
        }
      },
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": true,
        "description": "Required for paid planning and rendering. Use a distinct nonblank key per operation. Reuse the same key and body after timeouts or transient failures. The server trims the key.",
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 200,
          "pattern": "\\S"
        }
      },
      "PolicyConfirmation": {
        "name": "X-Ad-Policy-Confirmation",
        "in": "header",
        "required": false,
        "description": "After a 409 ad_policy_confirmation_required response, review error.details.ad_policy. If the user confirms, retry the same body and Idempotency-Key with its confirmation_token here. Never synthesize a token or silently confirm a warning.",
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 2000
        }
      }
    },
    "responses": {
      "Error": {
        "description": "Error envelope. Read error.code, error.message, optional param and details, and request_id.",
        "headers": {
          "X-Request-Id": {
            "description": "Request identifier for support and error correlation.",
            "schema": {
              "type": "string"
            }
          },
          "Cache-Control": {
            "description": "Public API responses use private, no-store.",
            "schema": {
              "type": "string"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "InvalidRequest": {
        "description": "Invalid body, unsupported or repeated query parameter, invalid_cursor, or missing Idempotency-Key. Correct the request before retrying.",
        "headers": {
          "X-Request-Id": {
            "description": "Request identifier for support and error correlation.",
            "schema": {
              "type": "string"
            }
          },
          "Cache-Control": {
            "description": "Public API responses use private, no-store.",
            "schema": {
              "type": "string"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "InvalidApiKey": {
        "description": "The API key is missing, invalid, revoked, or belongs to an unavailable account.",
        "headers": {
          "X-Request-Id": {
            "description": "Request identifier for support and error correlation.",
            "schema": {
              "type": "string"
            }
          },
          "Cache-Control": {
            "description": "Public API responses use private, no-store.",
            "schema": {
              "type": "string"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "BusinessRequired": {
        "description": "The key owner needs an active Business subscription.",
        "headers": {
          "X-Request-Id": {
            "description": "Request identifier for support and error correlation.",
            "schema": {
              "type": "string"
            }
          },
          "Cache-Control": {
            "description": "Public API responses use private, no-store.",
            "schema": {
              "type": "string"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "InsufficientCredits": {
        "description": "Insufficient Credits or a billing limit prevented admission. Resolve billing before retrying the original request.",
        "headers": {
          "X-Request-Id": {
            "description": "Request identifier for support and error correlation.",
            "schema": {
              "type": "string"
            }
          },
          "Cache-Control": {
            "description": "Public API responses use private, no-store.",
            "schema": {
              "type": "string"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "The ad, brand, or offering does not exist, is deleted, or is not owned by this account.",
        "headers": {
          "X-Request-Id": {
            "description": "Request identifier for support and error correlation.",
            "schema": {
              "type": "string"
            }
          },
          "Cache-Control": {
            "description": "Public API responses use private, no-store.",
            "schema": {
              "type": "string"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Conflict": {
        "description": "Inspect error.code before retrying. idempotency_conflict means the key was bound to a different request.\n\ninvalid_state means the ad is not eligible for this render. request_in_progress means the original request remains pending.\n\nad_policy_confirmation_required includes AdPolicyConfirmationDetails in error.details. Present its findings, limitations, and any billing information for review.\n\nIf the user confirms that policy review, retry the original key and body with X-Ad-Policy-Confirmation.",
        "headers": {
          "X-Request-Id": {
            "description": "Request identifier for support and error correlation.",
            "schema": {
              "type": "string"
            }
          },
          "Cache-Control": {
            "description": "Public API responses use private, no-store.",
            "schema": {
              "type": "string"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RequestTooLarge": {
        "description": "The request exceeds the ingress body limit.",
        "headers": {
          "X-Request-Id": {
            "description": "Request identifier for support and error correlation.",
            "schema": {
              "type": "string"
            }
          },
          "Cache-Control": {
            "description": "Public API responses use private, no-store.",
            "schema": {
              "type": "string"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "UnsupportedMediaType": {
        "description": "Use Content-Type: application/json for a nonempty JSON body.",
        "headers": {
          "X-Request-Id": {
            "description": "Request identifier for support and error correlation.",
            "schema": {
              "type": "string"
            }
          },
          "Cache-Control": {
            "description": "Public API responses use private, no-store.",
            "schema": {
              "type": "string"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "OperationRejected": {
        "description": "The requested operation cannot proceed. Read the error before changing or retrying the request.",
        "headers": {
          "X-Request-Id": {
            "description": "Request identifier for support and error correlation.",
            "schema": {
              "type": "string"
            }
          },
          "Cache-Control": {
            "description": "Public API responses use private, no-store.",
            "schema": {
              "type": "string"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RateLimited": {
        "description": "A rate limit rejected the request. Honor Retry-After before retrying with the original paid request key.",
        "headers": {
          "X-Request-Id": {
            "description": "Request identifier for support and error correlation.",
            "schema": {
              "type": "string"
            }
          },
          "Cache-Control": {
            "description": "Public API responses use private, no-store.",
            "schema": {
              "type": "string"
            }
          },
          "Retry-After": {
            "description": "Seconds to wait before retrying.",
            "schema": {
              "type": "string",
              "pattern": "^\\d+$"
            }
          },
          "RateLimit-Policy": {
            "description": "The applicable limit and window, when provided.",
            "schema": {
              "type": "string"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "InternalError": {
        "description": "The request failed internally. Retry with bounded backoff and the original paid request key. Include request_id in support reports.",
        "headers": {
          "X-Request-Id": {
            "description": "Request identifier for support and error correlation.",
            "schema": {
              "type": "string"
            }
          },
          "Cache-Control": {
            "description": "Public API responses use private, no-store.",
            "schema": {
              "type": "string"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unavailable": {
        "description": "The API is temporarily unavailable. Retry with bounded backoff and the original paid request key.",
        "headers": {
          "X-Request-Id": {
            "description": "Request identifier for support and error correlation.",
            "schema": {
              "type": "string"
            }
          },
          "Cache-Control": {
            "description": "Public API responses use private, no-store.",
            "schema": {
              "type": "string"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "AdCreateRequest": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "prompt": {
                "type": "string",
                "minLength": 3,
                "maxLength": 20000
              },
              "brand_id": {
                "type": "string",
                "minLength": 1,
                "maxLength": 160
              },
              "offering_id": {
                "type": "string",
                "minLength": 1,
                "maxLength": 160
              },
              "use_default_reference": {
                "default": true,
                "description": "Attach the default catalog photo or ready reference sheet. Set false to keep catalog context without an image.",
                "type": "boolean"
              },
              "type": {
                "type": "string",
                "const": "photo"
              },
              "aspect_ratio": {
                "type": "string",
                "enum": [
                  "1:1",
                  "4:5",
                  "9:16",
                  "16:9"
                ]
              },
              "resolution": {
                "type": "string",
                "const": "1K"
              },
              "duration": {
                "not": {}
              }
            },
            "required": [
              "prompt",
              "type"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "prompt": {
                "type": "string",
                "minLength": 1,
                "maxLength": 30000
              },
              "brand_id": {
                "type": "string",
                "minLength": 1,
                "maxLength": 160
              },
              "offering_id": {
                "type": "string",
                "minLength": 1,
                "maxLength": 160
              },
              "use_default_reference": {
                "default": true,
                "description": "Attach the default catalog photo or ready reference sheet. Set false to keep catalog context without an image.",
                "type": "boolean"
              },
              "type": {
                "type": "string",
                "enum": [
                  "video",
                  "animation"
                ]
              },
              "aspect_ratio": {
                "type": "string",
                "enum": [
                  "9:16",
                  "16:9",
                  "1:1"
                ]
              },
              "resolution": {
                "type": "string",
                "enum": [
                  "480p",
                  "720p",
                  "1080p"
                ]
              },
              "duration": {
                "type": "integer",
                "minimum": 4,
                "maximum": 600
              }
            },
            "required": [
              "prompt",
              "type"
            ],
            "additionalProperties": false
          }
        ]
      },
      "AdRenderRequest": {
        "type": "object",
        "properties": {
          "direction": {
            "type": "string",
            "minLength": 3,
            "maxLength": 32768
          },
          "shot_list": {
            "type": "string",
            "minLength": 1,
            "maxLength": 60000
          }
        },
        "additionalProperties": false
      },
      "EstimateRequest": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "prompt": {
                "type": "string",
                "minLength": 3,
                "maxLength": 20000
              },
              "brand_id": {
                "type": "string",
                "minLength": 1,
                "maxLength": 160
              },
              "offering_id": {
                "type": "string",
                "minLength": 1,
                "maxLength": 160
              },
              "use_default_reference": {
                "default": true,
                "description": "Attach the default catalog photo or ready reference sheet. Set false to keep catalog context without an image.",
                "type": "boolean"
              },
              "type": {
                "type": "string",
                "const": "photo"
              },
              "aspect_ratio": {
                "type": "string",
                "enum": [
                  "1:1",
                  "4:5",
                  "9:16",
                  "16:9"
                ]
              },
              "resolution": {
                "type": "string",
                "const": "1K"
              },
              "duration": {
                "not": {}
              }
            },
            "required": [
              "prompt",
              "type"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "prompt": {
                "type": "string",
                "minLength": 1,
                "maxLength": 30000
              },
              "brand_id": {
                "type": "string",
                "minLength": 1,
                "maxLength": 160
              },
              "offering_id": {
                "type": "string",
                "minLength": 1,
                "maxLength": 160
              },
              "use_default_reference": {
                "default": true,
                "description": "Attach the default catalog photo or ready reference sheet. Set false to keep catalog context without an image.",
                "type": "boolean"
              },
              "type": {
                "type": "string",
                "enum": [
                  "video",
                  "animation"
                ]
              },
              "aspect_ratio": {
                "type": "string",
                "enum": [
                  "9:16",
                  "16:9",
                  "1:1"
                ]
              },
              "resolution": {
                "type": "string",
                "enum": [
                  "480p",
                  "720p",
                  "1080p"
                ]
              },
              "duration": {
                "type": "integer",
                "minimum": 4,
                "maximum": 600
              }
            },
            "required": [
              "prompt",
              "type"
            ],
            "additionalProperties": false
          }
        ]
      },
      "Ad": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "photo",
              "video",
              "animation"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "processing",
              "planned",
              "succeeded",
              "failed"
            ]
          },
          "created_at": {
            "type": "string"
          },
          "credits": {
            "type": "object",
            "properties": {
              "ceiling": {
                "anyOf": [
                  {
                    "type": "number",
                    "minimum": 0
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "charged": {
                "type": "number",
                "minimum": 0
              }
            },
            "required": [
              "ceiling",
              "charged"
            ],
            "additionalProperties": false
          },
          "outputs": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "media_type": {
                  "type": "string",
                  "enum": [
                    "image",
                    "video"
                  ]
                },
                "download_url": {
                  "type": "string",
                  "format": "uri"
                },
                "expires_at": {
                  "type": "string",
                  "format": "date-time",
                  "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
                }
              },
              "required": [
                "id",
                "media_type",
                "download_url",
                "expires_at"
              ],
              "additionalProperties": false
            }
          },
          "error": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "code": {
                    "type": "string"
                  },
                  "message": {
                    "type": "string"
                  }
                },
                "required": [
                  "code",
                  "message"
                ],
                "additionalProperties": false
              },
              {
                "type": "null"
              }
            ]
          },
          "shot_list": {
            "type": [
              "string",
              "null"
            ]
          },
          "direction": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "type",
          "status",
          "created_at",
          "credits",
          "outputs",
          "error",
          "shot_list",
          "direction"
        ],
        "additionalProperties": false
      },
      "AdList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "type": {
                  "type": "string",
                  "enum": [
                    "photo",
                    "video",
                    "animation"
                  ]
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "queued",
                    "processing",
                    "planned",
                    "succeeded",
                    "failed"
                  ]
                },
                "created_at": {
                  "type": "string"
                }
              },
              "required": [
                "id",
                "type",
                "status",
                "created_at"
              ],
              "additionalProperties": false
            }
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ]
          },
          "has_more": {
            "type": "boolean"
          }
        },
        "required": [
          "data",
          "next_cursor",
          "has_more"
        ],
        "additionalProperties": false
      },
      "AdAccepted": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "processing",
              "planned",
              "succeeded",
              "failed"
            ]
          },
          "credits": {
            "type": "object",
            "properties": {
              "ceiling": {
                "type": "number",
                "minimum": 0
              }
            },
            "required": [
              "ceiling"
            ],
            "additionalProperties": false
          },
          "status_url": {
            "type": "string"
          },
          "direction": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "status",
          "credits",
          "status_url"
        ],
        "additionalProperties": false
      },
      "Credits": {
        "type": "object",
        "properties": {
          "available_credits": {
            "type": "number",
            "minimum": 0
          }
        },
        "required": [
          "available_credits"
        ],
        "additionalProperties": false
      },
      "Estimate": {
        "type": "object",
        "properties": {
          "ceiling_credits": {
            "type": "number",
            "minimum": 0
          },
          "render_ceiling_credits": {
            "type": "number",
            "minimum": 0
          }
        },
        "required": [
          "ceiling_credits"
        ],
        "additionalProperties": false
      },
      "OfferingList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "brand_id": {
                  "type": "string"
                },
                "created_at": {
                  "type": "string"
                }
              },
              "required": [
                "id",
                "name",
                "brand_id",
                "created_at"
              ],
              "additionalProperties": false
            }
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ]
          },
          "has_more": {
            "type": "boolean"
          }
        },
        "required": [
          "data",
          "next_cursor",
          "has_more"
        ],
        "additionalProperties": false
      },
      "BrandList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "created_at": {
                  "type": "string"
                }
              },
              "required": [
                "id",
                "name",
                "created_at"
              ],
              "additionalProperties": false
            }
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ]
          },
          "has_more": {
            "type": "boolean"
          }
        },
        "required": [
          "data",
          "next_cursor",
          "has_more"
        ],
        "additionalProperties": false
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "param": {
                "type": "string"
              },
              "details": {}
            },
            "required": [
              "code",
              "message"
            ],
            "additionalProperties": false
          },
          "request_id": {
            "type": "string"
          }
        },
        "required": [
          "error",
          "request_id"
        ],
        "additionalProperties": false
      },
      "AdPolicyConfirmationDetails": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "const": "AD_POLICY_CONFIRMATION_REQUIRED"
          },
          "ad_policy": {
            "type": "object",
            "properties": {
              "status": {
                "type": "string",
                "enum": [
                  "warning",
                  "unavailable"
                ]
              },
              "findings": {
                "maxItems": 8,
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "dimension": {
                      "type": "string",
                      "enum": [
                        "prohibited_content",
                        "restricted_categories",
                        "claim_substantiation",
                        "personal_attributes_and_body_image",
                        "deceptive_presentation",
                        "endorsements_and_rights",
                        "disclosures",
                        "targeting_and_destination"
                      ]
                    },
                    "citation_ids": {
                      "minItems": 1,
                      "maxItems": 3,
                      "type": "array",
                      "items": {
                        "type": "string",
                        "enum": [
                          "meta_prohibited_commercial_practices",
                          "meta_misinformation",
                          "meta_health_and_wellness",
                          "meta_personal_attributes",
                          "meta_third_party_ip_infringement",
                          "meta_discriminatory_practices",
                          "meta_locally_illegal_products",
                          "meta_tobacco",
                          "meta_drugs_and_pharmaceuticals",
                          "meta_weapons",
                          "meta_adult_nudity",
                          "meta_financial_services",
                          "meta_gambling",
                          "meta_alcohol",
                          "meta_dating",
                          "meta_social_issues_elections_politics",
                          "meta_spam_deceptive_links",
                          "meta_inauthentic_behavior",
                          "tiktok_misleading_and_false_content",
                          "tiktok_deceptive_practices",
                          "tiktok_weight_management_body_image",
                          "tiktok_discrimination_harassment",
                          "tiktok_ip_infringement",
                          "tiktok_healthcare_pharmaceuticals",
                          "tiktok_financial_services",
                          "tiktok_alcohol",
                          "tiktok_gambling",
                          "tiktok_politics_elections",
                          "tiktok_dangerous_products",
                          "tiktok_adult_content",
                          "tiktok_ad_format_functionality",
                          "tiktok_anti_discrimination",
                          "google_misrepresentation",
                          "google_unreliable_claims",
                          "google_unacceptable_business_practices",
                          "google_clickbait",
                          "google_misleading_ad_design",
                          "google_manipulated_media",
                          "google_healthcare_medicines",
                          "google_financial_services",
                          "google_gambling",
                          "google_alcohol",
                          "google_dating",
                          "google_political_content",
                          "google_sexual_content",
                          "google_dangerous_products",
                          "google_inappropriate_content",
                          "google_trademarks",
                          "google_copyrights",
                          "google_personalized_advertising",
                          "google_abusing_ad_network",
                          "google_destination_requirements"
                        ]
                      }
                    },
                    "reason": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 600
                    },
                    "suggestion": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 600
                    },
                    "evidence": {
                      "anyOf": [
                        {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 500
                        },
                        {
                          "type": "null"
                        }
                      ],
                      "description": "Evidence is one short, exact, contiguous excerpt from a single decoded string value inside material, preserving its spelling, case, punctuation and whitespace. Quote decoded string content only: text from one value, verbatim, as it reads after decoding. Use null when the finding rests on inference, numbers, keys, or labels rather than a matching string excerpt."
                    }
                  },
                  "required": [
                    "dimension",
                    "citation_ids",
                    "reason",
                    "suggestion",
                    "evidence"
                  ],
                  "additionalProperties": false
                }
              },
              "confirmation_token": {
                "type": "string",
                "minLength": 1,
                "maxLength": 2000
              },
              "policy_version": {
                "type": "string",
                "const": "ad_policy_2026_09_29_v1"
              },
              "limitations": {
                "maxItems": 8,
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "billing": {
                "type": "object",
                "properties": {
                  "operation_id": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 350
                  },
                  "usage_ledger_id": {
                    "anyOf": [
                      {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 400
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "credits_charged": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 9007199254740991
                  },
                  "credits_reserved": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 9007199254740991
                  }
                },
                "required": [
                  "operation_id",
                  "usage_ledger_id",
                  "credits_charged",
                  "credits_reserved"
                ],
                "additionalProperties": false
              }
            },
            "required": [
              "status",
              "findings",
              "confirmation_token",
              "policy_version",
              "limitations"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "code",
          "ad_policy"
        ],
        "additionalProperties": false
      }
    }
  }
}
