{
  "openapi": "3.1.0",
  "info": {
    "title": "Short Video Clip API (Agentropolis)",
    "version": "0.1.0",
    "summary": "Your image or prompt → a short 9:16 / 16:9 video clip (MP4 URL). Caller-owned media only. Flat price per clip with x402.",
    "description": "Send YOUR image (URL or upload) and/or your own prompt. The service validates the ownership assertion, prompt and options, fetches and checks the image, then asks for payment; after payment it generates a short clip and returns a temporary MP4 URL. Pricing: $0.50 USDC per clip via x402 on Base mainnet. The unpaid call returns HTTP 402 with an x402 v2 PAYMENT-REQUIRED header plus a JSON quote. Retry the same request with PAYMENT-SIGNATURE. x402 settles only after the clip is delivered. Ownership: only media you own or are licensed to use. Links to third-party platforms (YouTube, TikTok, Instagram, ...) and stock sites are refused before payment.",
    "contact": {
      "name": "Agentropolis",
      "email": "hello@agentropolis.io",
      "url": "https://agentropolis.io"
    },
    "x-guidance": "POST https://seenly-video-clip.vercel.app/api/clip with JSON {\"image_url\": \"https://<your storage>/photo.png\", \"prompt\": \"<motion, in your own words>\", \"aspect_ratio\": \"9:16\", \"duration\": 5, \"assert_rights\": true}. Image-to-video is the main mode (JPEG/PNG/WebP up to 10 MB by URL, 3 MB inline as {\"image\": {\"base64\": \"...\"}}, multipart field \"image\", or a raw image/* body). Text-to-video: omit the image and send only your prompt. Options: aspect_ratio 9:16|16:9|1:1|4:3|3:4|3:2|2:3 (default: the image's own ratio, or 9:16 for text-to-video), duration 1-6 s (default 5), resolution 480p|720p (default 720p), audio true|false (default true). \"assert_rights\": true is REQUIRED: Caller asserts it owns, or is licensed to use, the supplied image and prompt, that every identifiable person in the image consented to this use, and that the output will not be used to impersonate or mislead. Refused before payment: links to YouTube/TikTok/Instagram/other platforms or stock sites, web pages, URLs inside prompts, requests to download or repost third-party content, named copyrighted characters/franchises, deepfakes/impersonation, sexual content. Price: $0.50 USDC per clip, flat. The unpaid call validates everything and then returns HTTP 402 with PAYMENT-REQUIRED; sign it with any x402 client and retry the SAME request with PAYMENT-SIGNATURE. Settles only after the clip is delivered. Generation takes about 20-90 s; keep the connection open (timeout >= 180 s). The clip URL is deleted after 24 h."
  },
  "servers": [
    {
      "url": "https://seenly-video-clip.vercel.app"
    }
  ],
  "x-pricing": {
    "status": "live",
    "unit": "clip",
    "priceUsd": "0.50",
    "rail": {
      "protocol": "x402",
      "version": 2,
      "scheme": "exact",
      "network": "eip155:8453",
      "networkName": "Base mainnet",
      "asset": "USDC",
      "assetAddress": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "amount": "500000",
      "payTo": "0xeE6239F3E17bEBe5e89F21F29D74D68CAa0d78CE",
      "facilitator": "Coinbase CDP (gas sponsored; payer needs USDC only, no ETH)",
      "header": "PAYMENT-SIGNATURE"
    },
    "chargedOn": "x402 settles only after a successful (2xx) response; failed calls are not charged."
  },
  "paths": {
    "/api/clip": {
      "post": {
        "operationId": "createClip",
        "summary": "Generate a short video clip from your image and/or prompt (paid, x402)",
        "description": "Validated before payment. Synchronous: keep the connection open ~20-90 s (up to 240 s).",
        "x-payment-info": {
          "protocols": [
            "x402"
          ],
          "price": {
            "mode": "fixed",
            "currency": "USD",
            "amount": "0.50"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClipRequest"
              },
              "example": {
                "image_url": "https://seenly-video-clip.vercel.app/samples/input-sunrise.png",
                "prompt": "slow camera push-in, clouds drifting, warm morning light",
                "aspect_ratio": "9:16",
                "duration": 5,
                "assert_rights": true
              }
            },
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "image",
                  "assert_rights"
                ],
                "properties": {
                  "image": {
                    "type": "string",
                    "format": "binary"
                  },
                  "prompt": {
                    "type": "string",
                    "maxLength": 1500,
                    "description": "Motion / scene description in your own words. Optional with an image (a subtle default motion is used); required for text-to-video. No URLs."
                  },
                  "aspect_ratio": {
                    "type": "string",
                    "enum": [
                      "9:16",
                      "16:9",
                      "1:1",
                      "4:3",
                      "3:4",
                      "3:2",
                      "2:3"
                    ],
                    "description": "Output ratio. Default: the input image's own ratio (image-to-video) or 9:16 (text-to-video). Setting it with an image fits the image to that ratio."
                  },
                  "duration": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 6,
                    "default": 5,
                    "description": "Clip length in seconds (flat price)."
                  },
                  "resolution": {
                    "type": "string",
                    "enum": [
                      "480p",
                      "720p"
                    ],
                    "default": "720p"
                  },
                  "audio": {
                    "type": "boolean",
                    "default": true,
                    "description": "Generate a native soundtrack (ambient / effects)."
                  },
                  "assert_rights": {
                    "type": "boolean",
                    "const": true,
                    "description": "REQUIRED. Caller asserts it owns, or is licensed to use, the supplied image and prompt, that every identifiable person in the image consented to this use, and that the output will not be used to impersonate or mislead."
                  }
                }
              }
            },
            "image/jpeg": {
              "schema": {
                "type": "string",
                "format": "binary"
              },
              "description": "Raw image; options (assert_rights=true etc.) in the query string."
            },
            "image/png": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            },
            "image/webp": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Clip generated. Paid responses carry PAYMENT-RESPONSE (settlement tx).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VideoClip"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Payment required: PAYMENT-REQUIRED header (x402 v2), JSON body with quote {priceUsd, amount}. Only returned for requests that passed validation (or an empty price probe).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "413": {
            "description": "Image too large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "Not a JPEG/PNG/WebP image, or unreadable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "rights_not_asserted, third_party_source_refused, content_refused, url_not_allowed, url_fetch_failed, not_image, image_unreadable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "Generation or storage failed (not charged)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Busy or payments misconfigured",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "details": {}
            }
          }
        }
      },
      "ClipRequest": {
        "type": "object",
        "required": [
          "assert_rights"
        ],
        "description": "image_url or image (image-to-video), and/or prompt (text-to-video when no image).",
        "properties": {
          "image_url": {
            "type": "string",
            "format": "uri",
            "description": "Direct public http(s) link to YOUR JPEG/PNG/WebP image (≤ 10 MB). Third-party platforms and stock sites are refused."
          },
          "image": {
            "type": "object",
            "required": [
              "base64"
            ],
            "properties": {
              "base64": {
                "type": "string"
              },
              "filename": {
                "type": "string"
              }
            },
            "description": "Inline image (≤ 3 MB decoded; 256 KB through the Agentropolis relay). A data: URL string is also accepted."
          },
          "prompt": {
            "type": "string",
            "maxLength": 1500,
            "description": "Motion / scene description in your own words. Optional with an image (a subtle default motion is used); required for text-to-video. No URLs."
          },
          "aspect_ratio": {
            "type": "string",
            "enum": [
              "9:16",
              "16:9",
              "1:1",
              "4:3",
              "3:4",
              "3:2",
              "2:3"
            ],
            "description": "Output ratio. Default: the input image's own ratio (image-to-video) or 9:16 (text-to-video). Setting it with an image fits the image to that ratio."
          },
          "duration": {
            "type": "integer",
            "minimum": 1,
            "maximum": 6,
            "default": 5,
            "description": "Clip length in seconds (flat price)."
          },
          "resolution": {
            "type": "string",
            "enum": [
              "480p",
              "720p"
            ],
            "default": "720p"
          },
          "audio": {
            "type": "boolean",
            "default": true,
            "description": "Generate a native soundtrack (ambient / effects)."
          },
          "assert_rights": {
            "type": "boolean",
            "const": true,
            "description": "REQUIRED. Caller asserts it owns, or is licensed to use, the supplied image and prompt, that every identifiable person in the image consented to this use, and that the output will not be used to impersonate or mislead."
          }
        }
      },
      "VideoClip": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "object": {
            "const": "video_clip"
          },
          "clip": {
            "type": "object",
            "properties": {
              "url": {
                "type": "string",
                "format": "uri",
                "description": "Temporary MP4 URL (deleted after 24 h)."
              },
              "expires_at": {
                "type": "string",
                "format": "date-time"
              },
              "content_type": {
                "type": "string"
              },
              "bytes": {
                "type": "integer"
              },
              "duration_sec": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "width": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "height": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "has_audio": {
                "type": "boolean"
              }
            }
          },
          "request": {
            "type": "object"
          },
          "model": {
            "type": "string"
          },
          "fallback_used": {
            "type": "boolean"
          },
          "billing": {
            "type": "object",
            "properties": {
              "priceUsd": {
                "type": "string"
              },
              "totalUsd": {
                "type": "string"
              },
              "charged": {
                "type": "boolean"
              },
              "rail": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "rights": {
            "type": "object",
            "properties": {
              "asserted": {
                "type": "boolean"
              },
              "statement": {
                "type": "string"
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "retention": {
            "type": "string"
          }
        }
      }
    }
  }
}