openapi: 3.2.0 info: title: FrameThrower Search API version: 1.0.0 summary: Cinematography reference search over 5,489 films. description: Search a film stills library indexed frame by frame on lighting, lens character, shot size, camera angle, colour palette and mood — in plain language, by reference image, or by colour. contact: name: FrameThrower url: https://framethrower.ai/developers email: contact@framethrower.ai license: name: Proprietary url: https://framethrower.ai/legal/tos termsOfService: https://framethrower.ai/legal/tos servers: - url: https://framethrower.ai/api/v1 description: Production security: - bearerAuth: [] tags: - name: Search description: Find frames by text, image or colour paths: /search: post: tags: - Search operationId: search summary: Search by text description: 'Describe a mood, scene or visual concept in natural language. **Cost: 2 credits.** $1 = 1,000 credits. Returns 402 when the balance is short.' security: - bearerAuth: [] requestBody: required: true content: application/json: schema: type: object required: - query properties: query: type: string description: Natural-language query examples: - neon-lit rainy street at night limit: type: integer minimum: 1 maximum: 50 default: 20 mode: type: string enum: - hybrid - description default: hybrid description: hybrid fuses the image and scene-description embeddings via reciprocal rank fusion — use it unless you have a reason not to. description ranks on the written descriptions only, better when the query is about story, action or named objects. color: type: string pattern: ^#?[0-9a-fA-F]{6}$ examples: - '#1f7a8c' description: 'Bias the search toward frames dominated by this colour, without abandoning the query. Fused with the text ranking rather than replacing it — "ocean" with #1f7a8c returns teal seas, not teal anything. For colour alone, use /search/color.' enhance: type: boolean default: false description: 'Rewrite the query into the descriptive register the frames were embedded from before searching — "man on fire" becomes a full sentence. Benchmarked recall@10: 0.72 raw, 0.88 enhanced. This is what the website does by default. Adds ~1s on a cache miss and falls back to the raw query on error. When it fires, the rewritten text comes back as meta.enhancedQuery — send that as the query for later pages so every page ranks in the same neighbourhood.' offset: type: integer minimum: 0 maximum: 500 default: 0 description: 'Skip this many results before returning. Use with limit to page: offset 0 then 50 then 100. Capped at 500 — ranking past that is noise, and the candidate pool is built to offset+limit.' shot_type: type: string enum: - medium - closeup - wide - fullbody - establishing description: Shot size. Aliased, so close-up and closeup both land. camera_angle: type: string enum: - eye_level - high_angle - low_angle - top_down - overhead - worms_eye - dutch_angle - pov - birds_eye description: Camera angle. time_of_day: type: string enum: - night - day - interior_indeterminate - golden_hour - dusk - blue_hour - dawn - overcast description: Time of day / light. setting: type: string enum: - interior - exterior - both description: Interior or exterior. visual_style: type: string enum: - live_action - cg_stylized - anime - cg_photorealistic - cartoon_2d - stop_motion - mixed_media - rotoscope - noir - watercolor - minimalist - documentary - expressionist - painterly - surreal description: Medium and treatment. lens: type: string enum: - anamorphic - spherical - vintage_soft description: Lens character. lighting: type: string enum: - sun - window - moonlight - practical - neon - fluorescent - firelight - candlelight - streetlamp - screen_glow - headlight - lightning description: What is lighting the frame — a different question from the time of day. depth_of_field: type: string enum: - shallow - deep - rack_focus - medium description: Focus depth. director: type: string genre: type: string film_title: type: string era: type: string enum: - ancient - medieval - renaissance - 1800s - 1900s_1910s - 1920s - 1930s - 1940s - 1950s - 1960s - 1970s - 1980s - 1990s - 2000s - 2010s - contemporary - near_future - far_future - fantasy description: The era depicted on screen, not the release year. year_min: type: integer year_max: type: integer responses: '200': description: Matching frames content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/Frame' meta: type: object additionalProperties: true '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/InsufficientCredits' /search/image: post: tags: - Search operationId: searchByImage summary: Search by reference image description: 'Find frames matching a reference image by visual similarity, colour and semantic meaning. **Cost: 10 credits.** $1 = 1,000 credits. Returns 402 when the balance is short.' security: - bearerAuth: [] requestBody: required: true content: application/json: schema: type: object required: - imageUrl properties: imageUrl: type: string format: uri limit: type: integer minimum: 1 maximum: 50 default: 20 responses: '200': description: Matching frames content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/Frame' meta: type: object additionalProperties: true '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/InsufficientCredits' /search/color: post: tags: - Search operationId: searchByColor summary: Search by colour description: 'Find frames dominated by a hex colour or a blended palette. Use `color` OR `colors`, not both. **Cost: 2 credits.** $1 = 1,000 credits. Returns 402 when the balance is short.' security: - bearerAuth: [] requestBody: required: true content: application/json: schema: type: object properties: color: type: string pattern: ^#?[0-9a-fA-F]{6}$ examples: - '#e94560' colors: type: array maxItems: 6 items: type: string pattern: ^#?[0-9a-fA-F]{6}$ limit: type: integer minimum: 1 maximum: 50 default: 20 responses: '200': description: Matching frames content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/Frame' meta: type: object additionalProperties: true '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/InsufficientCredits' /browse: post: tags: - Search operationId: browse summary: Filter by craft attribute description: 'Filter frames by cinematography attributes — no text query needed. Combine any filters. Common spellings ("close-up", "magic hour") are normalised for you; anything unrecognised comes back in `meta.hint` rather than as a silent empty result. **Cost: 2 credits.** $1 = 1,000 credits. Returns 402 when the balance is short.' security: - bearerAuth: [] requestBody: required: true content: application/json: schema: type: object properties: shot_type: type: string enum: - medium - closeup - wide - fullbody - establishing description: Shot size lens_character: type: string enum: - anamorphic - spherical - vintage_soft description: Lens character setting: type: string enum: - interior - exterior - both description: Interior or exterior time_of_day: type: string enum: - night - day - interior_indeterminate - golden_hour - dusk - blue_hour - dawn - overcast description: Time of day camera_angle: type: string enum: - eye_level - high_angle - low_angle - top_down - overhead - worms_eye - dutch_angle - pov - birds_eye description: Camera angle visual_style: type: string enum: - live_action - cg_stylized - anime - cg_photorealistic - cartoon_2d - stop_motion - mixed_media - rotoscope - noir - watercolor - minimalist - documentary - expressionist - painterly - surreal description: Visual style director: type: string description: Free text, e.g. "Ridley Scott" genre: type: string description: Free text, e.g. "Science Fiction" era: type: string description: Depicted era, e.g. "1980s", "near_future" year_min: type: integer year_max: type: integer limit: type: integer minimum: 1 maximum: 50 default: 20 responses: '200': description: Matching frames content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/Frame' meta: type: object additionalProperties: true '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/InsufficientCredits' /similar: post: tags: - Search operationId: findSimilar summary: Find similar frames description: 'More frames like one already returned. Pass several ids to search from their centroid. **Cost: 2 credits.** $1 = 1,000 credits. Returns 402 when the balance is short.' security: - bearerAuth: [] requestBody: required: true content: application/json: schema: type: object properties: frameId: type: string frameIds: type: array items: type: string mode: type: string enum: - semantic - visual - color default: semantic limit: type: integer minimum: 1 maximum: 50 default: 20 responses: '200': description: Matching frames content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/Frame' meta: type: object additionalProperties: true '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/InsufficientCredits' components: responses: InsufficientCredits: description: Not enough credits. The body carries everything needed to recover without reading docs. content: application/json: schema: type: object properties: error: type: string code: type: string const: insufficient_credits cost: type: integer balance: type: integer buy_credits: type: string format: uri Unauthorized: description: Missing, malformed, revoked or unknown token content: application/json: schema: $ref: '#/components/schemas/Error' BadRequest: description: Malformed request content: application/json: schema: $ref: '#/components/schemas/Error' schemas: Frame: type: object description: A single film frame. Thumbnails and deep links only — never raw image bytes. properties: id: type: string url: type: string format: uri description: Deep link to this frame on FrameThrower thumbnail: type: string format: uri depthUrl: type: string format: uri nullable: true description: Precomputed depth map (Depth-Anything V2), WebP, same pixel dimensions as the frame — feed straight to a depth ControlNet. null when the frame has no map; a stale URL 404s, in which case compute depth locally. Never falls back to the colour image. score: type: number description: Relevance, when the call was a search film: type: object properties: title: type: string year: type: integer slug: type: string frameCount: type: integer director: type: string cinematographer: type: string shot_type: type: string lens_character: type: string camera_angle: type: string setting: type: string time_of_day: type: string visual_style: type: string colorPalette: type: array items: type: string description: Dominant colours as hex colorDescription: type: string prompt: type: string description: Stored descriptive prompt for the frame Error: type: object properties: error: type: string docs: type: string api_reference: type: string securitySchemes: bearerAuth: type: http scheme: bearer description: Personal access token, prefix `ft_`. Create one at https://framethrower.ai/settings?tab=api — free accounts included, no plan required. externalDocs: url: https://framethrower.ai/developers description: Developer documentation