{
  "openapi": "3.0.0",
  "info": {
    "title": "Treza Pipelines API",
    "description": "Treza builds video pipelines from a description. Build pipelines that chain the best AI models (Veo 3.1, Seedance 2.5, Gemini Image, Llama, and any open model) with voiceover, captions, sequencing, and publishing, then call any published pipeline as an API.\n\nTwo ways to call a published pipeline:\n- Typed invoke: POST /api/pipelines/{id}/invoke with JSON inputs matching the pipeline's input contract. Returns a runId (HTTP 202); poll GET /api/pipelines/{id}/invoke?runId=... for status and outputs.\n- OpenAI-compatible: POST /api/pipelines/{id}/chat/completions works as a drop-in for any OpenAI SDK, streaming included. The latest user message feeds the pipeline and the output returns as the assistant message.\n\nAuthentication uses scoped API keys (Bearer treza_live_...) created in the Treza platform or minted over MCP (create_api_key). The key must own the pipeline and the pipeline must be published. Billing is prepaid credits that work across every model; check the balance at GET /api/account/balance, and top up either via a human at the dashboard or, on deployments with x402 enabled, agent-natively at POST /api/billing/credits/x402.\n\nAn MCP server is also available at https://www.trezalabs.com/api/mcp (streamable HTTP, OAuth 2.1) exposing tools to list, author, and publish pipelines, inspect runs, trigger new runs, check the credit balance, estimate run cost, and mint scoped API keys (create_api_key, for OAuth connections).",
    "version": "3.0.0",
    "contact": {
      "name": "Treza Support",
      "url": "https://www.trezalabs.com/support",
      "email": "hello@trezalabs.com"
    }
  },
  "servers": [
    {
      "url": "https://www.trezalabs.com",
      "description": "Production"
    }
  ],
  "security": [{ "bearerAuth": [] }],
  "paths": {
    "/api/pipelines/{id}/invoke": {
      "post": {
        "operationId": "invokePipeline",
        "summary": "Invoke a published pipeline",
        "description": "Starts a run of the deployed pipeline snapshot with the given inputs. Returns a runId immediately; poll the GET variant of this path for status and outputs.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Pipeline id",
            "schema": { "type": "string" }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "inputs": {
                    "type": "object",
                    "description": "Values keyed by the pipeline's input contract",
                    "additionalProperties": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Run accepted",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/RunAccepted" }
              }
            }
          },
          "401": { "description": "Missing or invalid API key" },
          "402": {
            "description": "Insufficient prepaid credits. code is INSUFFICIENT_CREDITS; relay topUpUrl to a human — credits are purchased through the signed-in dashboard.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": { "type": "string" },
                    "code": { "type": "string", "enum": ["INSUFFICIENT_CREDITS"] },
                    "balanceUsd": { "type": "number" },
                    "topUpUrl": { "type": "string", "format": "uri" }
                  }
                }
              }
            }
          },
          "403": { "description": "Key does not own this pipeline" },
          "404": { "description": "Pipeline not found" },
          "409": { "description": "Pipeline is not published" }
        }
      },
      "get": {
        "operationId": "getInvokeRunStatus",
        "summary": "Poll a pipeline run",
        "description": "Returns the status of a run started via invoke, including outputs once the run completes.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Pipeline id",
            "schema": { "type": "string" }
          },
          {
            "name": "runId",
            "in": "query",
            "required": true,
            "description": "Run id returned by the invoke call",
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": {
            "description": "Run status",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/RunStatus" }
              }
            }
          },
          "401": { "description": "Missing or invalid API key" },
          "404": { "description": "Run not found" }
        }
      }
    },
    "/api/pipelines/{id}/chat/completions": {
      "post": {
        "operationId": "pipelineChatCompletions",
        "summary": "OpenAI-compatible pipeline endpoint",
        "description": "Drop-in replacement for the OpenAI chat completions API. Point any OpenAI SDK at this base URL with a Treza API key. The latest user message is fed into the pipeline and the pipeline output is returned as the assistant message. Supports streaming via server-sent events.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Pipeline id",
            "schema": { "type": "string" }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["messages"],
                "properties": {
                  "messages": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "role": { "type": "string" },
                        "content": { "type": "string" }
                      }
                    }
                  },
                  "stream": { "type": "boolean" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Chat completion (JSON, or SSE when stream is true)" },
          "401": { "description": "Missing or invalid API key" },
          "402": { "description": "Insufficient prepaid credits. The OpenAI-style error object carries code INSUFFICIENT_CREDITS, balanceUsd, and a topUpUrl to relay to a human." },
          "403": { "description": "Key does not own this pipeline" },
          "404": { "description": "Pipeline not found" },
          "409": { "description": "Pipeline is not published" }
        }
      }
    },
    "/api/billing/credits/x402": {
      "post": {
        "operationId": "x402CreditTopUp",
        "x-payment-info": {
          "protocols": ["x402"],
          "price": { "mode": "fixed", "currency": "USD", "amount": "5.00" }
        },
        "summary": "Top up credits with an x402 payment (agent-native)",
        "description": "Adds a fixed amount of Treza credit per call, paid via the x402 protocol (HTTP 402): call without payment to receive a 402 challenge carrying the price and network, sign the payment with an x402-capable wallet, and retry with the payment-signature header. Grants are idempotent per settled transaction. A bearer (API key, OAuth token, or session) is optional and only chooses which account is credited; without one the credits are keyed to the paying wallet, so an agent holding nothing but a wallet can still fund itself. Only available when the deployment has x402 enabled — the balance endpoint's x402 field says so.",
        "responses": {
          "200": {
            "description": "Credits granted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "grantedUsd": { "type": "number" },
                    "duplicate": { "type": "boolean", "description": "True when this payment was already credited (idempotent replay)." },
                    "balanceUsd": { "type": "number" },
                    "network": { "type": "string" }
                  }
                }
              }
            }
          },
          "401": { "description": "A bearer was sent and is invalid, or the request carried neither a bearer nor a settled payer" },
          "402": { "description": "Payment required: the challenge response carrying x402 payment instructions" },
          "429": { "description": "Rate limit exceeded" },
          "503": { "description": "x402 payments are not enabled on this deployment" }
        }
      }
    },
    "/api/x402/video": {
      "post": {
        "operationId": "x402GenerateVideo",
        "x-payment-info": {
          "protocols": ["x402"],
          "price": { "mode": "dynamic", "currency": "USD", "min": "1.64", "max": "4.90" }
        },
        "summary": "Generate a video from a prompt, paid with x402",
        "description": "Generates a video from a text prompt and returns it. Pay via the x402 protocol (HTTP 402): call without payment to receive a 402 challenge carrying the price and network, sign the payment with an x402-capable wallet, and retry with the payment-signature header. No account, API key, or signup is involved — the payment is the only credential. Price is quoted per request and scales with clip length, so send the seconds you want and read the amount off the challenge rather than assuming a fixed figure. Renders take minutes, so a paid call answers 202 with a runId and a statusUrl carrying a signed claim ticket; poll that URL until status leaves \"running\" and the video URL appears.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["prompt"],
                "properties": {
                  "prompt": { "type": "string", "maxLength": 2000, "description": "What the video should show." },
                  "seconds": { "type": "number", "enum": [5, 10, 15], "default": 5, "description": "Clip length. Longer clips cost proportionally more; the 402 challenge quotes the price for the length you send." },
                  "aspectRatio": { "type": "string", "enum": ["16:9", "9:16"], "default": "16:9", "description": "Landscape or vertical." }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Payment settled and the render started",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "runId": { "type": "string" },
                    "status": { "type": "string", "example": "running" },
                    "statusUrl": { "type": "string", "format": "uri", "description": "Poll this for the finished video. It carries its own signed ticket, so it needs no other credential." },
                    "pollAfterMs": { "type": "integer" },
                    "paidUsd": { "type": "number", "description": "What this request cost, quoted from its clip length." },
                    "seconds": { "type": "number" },
                    "aspectRatio": { "type": "string" },
                    "balanceUsd": { "type": "number", "description": "Credit left on the paying wallet once this render is funded." },
                    "transaction": { "type": "string" },
                    "payer": { "type": "string" }
                  }
                }
              }
            }
          },
          "400": { "description": "Missing or oversized prompt, or a size that is not on sale. Refused before settlement, so nothing was charged" },
          "402": { "description": "Payment required: the challenge response carrying x402 payment instructions" },
          "429": { "description": "Rate limit exceeded" },
          "503": { "description": "Pay-per-video is not enabled on this deployment" }
        }
      },
      "get": {
        "operationId": "x402GetVideoRun",
        "summary": "Poll a video run bought with an x402 payment",
        "description": "Returns the run's status and, once it has finished, the video URL. The token is the claim ticket handed back by the paid POST, and is the only credential needed.",
        "parameters": [
          { "name": "runId", "in": "query", "required": true, "schema": { "type": "string" } },
          { "name": "token", "in": "query", "required": true, "schema": { "type": "string" }, "description": "Signed claim ticket from the paid POST." }
        ],
        "responses": {
          "200": {
            "description": "Run status, plus the video URL once it has finished",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "runId": { "type": "string" },
                    "status": { "type": "string", "example": "success" },
                    "video": { "type": "string", "format": "uri", "description": "URL of the finished video." },
                    "outputs": { "type": "object" }
                  }
                }
              }
            }
          },
          "400": { "description": "runId and token are both required" },
          "403": { "description": "Invalid, expired, or mismatched token" },
          "404": { "description": "Run not found" }
        }
      }
    },
    "/api/account/balance": {
      "get": {
        "operationId": "getAccountBalance",
        "summary": "Get credit balance and plan usage",
        "description": "Current prepaid credit balance, plan usage, and purchasable credit packs. Accepts a scoped API key (any pipelines scope), an MCP OAuth access token, or a session bearer. Use it to budget runs before starting them; when the balance is low, hand topUpUrl to a human — credits are purchased by a signed-in human.",
        "responses": {
          "200": {
            "description": "Balance summary",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "balanceUsd": { "type": "number" },
                    "enforced": { "type": "boolean", "description": "False when this account runs free (credits not enforced)." },
                    "markup": { "type": "number", "description": "Multiplier applied to estimated provider cost when charging the balance." },
                    "typicalVideoChargeUsd": { "type": "number" },
                    "approxVideosRemaining": { "type": "integer" },
                    "plan": {
                      "type": "object",
                      "nullable": true,
                      "properties": {
                        "name": { "type": "string" },
                        "status": { "type": "string" },
                        "requestsThisPeriod": { "type": "integer" },
                        "includedRequests": { "type": "integer" },
                        "overLimit": { "type": "boolean" }
                      }
                    },
                    "packs": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": { "type": "string" },
                          "priceUsd": { "type": "number" },
                          "creditsUsd": { "type": "number" },
                          "label": { "type": "string" }
                        }
                      }
                    },
                    "topUpUrl": { "type": "string", "format": "uri" },
                    "x402": {
                      "type": "object",
                      "description": "Present when the deployment supports agent-native x402 top-ups.",
                      "properties": {
                        "url": { "type": "string", "format": "uri" },
                        "topUpPerCallUsd": { "type": "number" },
                        "network": { "type": "string" }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": { "description": "Missing or invalid bearer token" },
          "429": { "description": "Rate limit exceeded" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Scoped API key created in the Treza platform (treza_live_...)"
      }
    },
    "schemas": {
      "RunAccepted": {
        "type": "object",
        "properties": {
          "runId": { "type": "string" },
          "status": { "type": "string", "example": "running" }
        }
      },
      "RunStatus": {
        "type": "object",
        "properties": {
          "runId": { "type": "string" },
          "status": {
            "type": "string",
            "description": "running, succeeded, failed, or cancelled"
          },
          "outputs": {
            "type": "object",
            "description": "Values keyed by the pipeline's output contract, present once the run succeeds. Media outputs are returned as URLs.",
            "additionalProperties": true
          },
          "error": { "type": "string" }
        }
      }
    }
  }
}
