{"openapi":"3.0.3","info":{"title":"Faceplacer API","description":"Realistic AI avatar images with customizable attributes. Generate, browse, search, and find similar avatars with API-key access. Stable version 2 uses /api/v2. Existing /api URLs remain compatible. Additive fields may be introduced within a major version; breaking changes require a new major URL. Before retirement, publish a migration guide and Deprecation and Sunset headers with at least 90 days notice. No retirement is scheduled. See https://www.faceplacer.com/docs for the versioning and deprecation policy.","version":"2.0.0","contact":{"name":"Faceplacer","url":"https://faceplacer.com"}},"servers":[{"url":"https://www.faceplacer.com/api/v2","description":"Stable API version 2"},{"url":"https://www.faceplacer.com/api","description":"Compatible unversioned URLs; no retirement scheduled"}],"paths":{"/collection":{"get":{"operationId":"getCollection","summary":"Browse completed avatars","description":"Public collection index, with no key, inference, semantic search, uploads or generation. All eight facets filter the complete displayable collection: comma-separated OR within a facet, AND across facets. Unknown/repeated parameters and invalid/empty values return400. With neither limit nor cursor, returns all matches in the existing newest-first order. Paginated requests use ascending avatarUUID keyset order and a bounded database query. Pages are live views, not snapshots: concurrent inserts before a cursor require restarting to see them. Return the cursor unchanged with the same filters; changing filters returns400. No pagination metadata is returned for unpaginated requests.","security":[],"parameters":[{"name":"gender","in":"query","description":"Comma-separated values: OR within this attribute and AND with other attributes.","style":"form","explode":false,"schema":{"type":"array","items":{"$ref":"#/components/schemas/Gender"}}},{"name":"age","in":"query","description":"Comma-separated values: OR within this attribute and AND with other attributes.","style":"form","explode":false,"schema":{"type":"array","items":{"$ref":"#/components/schemas/Age"}}},{"name":"ethnicity","in":"query","description":"Comma-separated values: OR within this attribute and AND with other attributes.","style":"form","explode":false,"schema":{"type":"array","items":{"$ref":"#/components/schemas/Ethnicity"}}},{"name":"background","in":"query","description":"Comma-separated values: OR within this attribute and AND with other attributes.","style":"form","explode":false,"schema":{"type":"array","items":{"$ref":"#/components/schemas/Background"}}},{"name":"style","in":"query","description":"Comma-separated values: OR within this attribute and AND with other attributes.","style":"form","explode":false,"schema":{"type":"array","items":{"$ref":"#/components/schemas/Style"}}},{"name":"profession","in":"query","description":"Comma-separated values: OR within this attribute and AND with other attributes.","style":"form","explode":false,"schema":{"type":"array","items":{"$ref":"#/components/schemas/Profession"}}},{"name":"expression","in":"query","description":"Comma-separated values: OR within this attribute and AND with other attributes.","style":"form","explode":false,"schema":{"type":"array","items":{"$ref":"#/components/schemas/Expression"}}},{"name":"pose","in":"query","description":"Comma-separated values: OR within this attribute and AND with other attributes.","style":"form","explode":false,"schema":{"type":"array","items":{"$ref":"#/components/schemas/Pose"}}},{"name":"limit","in":"query","description":"Optional page size,1–100. Omit both limit and cursor to return all matches. A cursor without limit uses50.","schema":{"type":"integer","minimum":1,"maximum":100}},{"name":"cursor","in":"query","description":"Opaque pagination.nextCursor from the preceding response. Preserve the same filters (value order may differ). Null nextCursor means the last page. Paging order is ascending avatarUUID, not creation time.","schema":{"type":"string","maxLength":1024}},{"name":"If-None-Match","in":"header","description":"ETag from the same selected representation; a match returns304 without a body. Supports comma-separated validators and *.","schema":{"type":"string"}}],"responses":{"200":{"description":"Completed displayable avatars.","content":{"application/json":{"schema":{"type":"object","required":["avatars"],"properties":{"avatars":{"type":"array","items":{"$ref":"#/components/schemas/CollectionAvatar"}},"pagination":{"$ref":"#/components/schemas/CollectionPagination"}}}}},"headers":{"ETag":{"description":"Weak SHA-256 validator for the selected JSON representation.","schema":{"type":"string"}},"Cache-Control":{"description":"CDN freshness300seconds, stale-while-revalidate86400seconds. ETags describe the served representation, not an uncached database snapshot.","schema":{"type":"string"}}}},"304":{"description":"Selected representation has not changed; no response body.","headers":{"ETag":{"description":"Weak SHA-256 validator for the selected JSON representation.","schema":{"type":"string"}},"Cache-Control":{"description":"CDN freshness300seconds, stale-while-revalidate86400seconds. ETags describe the served representation, not an uncached database snapshot.","schema":{"type":"string"}}}},"400":{"description":"Unknown/repeated parameter, invalid facet/limit, malformed cursor or cursor/filter mismatch.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"Unsupported method. Consult Allow; avatar, search, similarity, and image endpoints do not support HEAD because GET can invoke providers.","headers":{"Allow":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Collection unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/avatar":{"get":{"operationId":"getAvatar","summary":"Generate or retrieve an avatar image","description":"Returns a matching avatar. By default, missing matches are generated. Set generate=false to return only an existing displayable match (404 if absent); name and query inference still run. When generation is enabled and the exact combination exists but is unavailable, returns 409 rather than attempting a conflicting generation. Requires an API key.","tags":["Avatar"],"security":[{"apiKey":[]}],"parameters":[{"name":"name","in":"query","description":"Name to infer attributes from (e.g., 'Sarah Chen'). Used as seed for consistent results.","schema":{"type":"string"},"example":"Sarah Chen"},{"name":"seed","in":"query","description":"Explicit seed string for reproducibility.","schema":{"type":"string"}},{"name":"gender","in":"query","description":"Gender of the avatar. Inferred from name if omitted.","schema":{"$ref":"#/components/schemas/Gender"}},{"name":"age","in":"query","description":"Age range. Random if omitted.","schema":{"$ref":"#/components/schemas/Age"}},{"name":"ethnicity","in":"query","description":"Ethnic appearance. Inferred from name if omitted.","schema":{"$ref":"#/components/schemas/Ethnicity"}},{"name":"location","in":"query","description":"Location string to map to ethnicity (e.g., 'Japan', 'Brazil').","schema":{"type":"string"},"example":"Tokyo"},{"name":"profession","in":"query","description":"Professional context affecting attire.","schema":{"$ref":"#/components/schemas/Profession"}},{"name":"expression","in":"query","description":"Facial expression.","schema":{"$ref":"#/components/schemas/Expression"}},{"name":"pose","in":"query","description":"Head orientation. Random/seeded if omitted.","schema":{"$ref":"#/components/schemas/Pose"}},{"name":"style","in":"query","description":"Clothing style.","schema":{"$ref":"#/components/schemas/Style"}},{"name":"background","in":"query","description":"Background color/style.","schema":{"$ref":"#/components/schemas/Background"}},{"name":"variation","in":"query","description":"Variation number for different looks with the same attributes.","schema":{"type":"integer","minimum":1},"example":1},{"name":"size","in":"query","description":"Image size in pixels (square).","schema":{"$ref":"#/components/schemas/Size"}},{"name":"query","in":"query","description":"Natural-language avatar request; explicit attributes override inferred values.","schema":{"type":"string","maxLength":300}},{"name":"generate","in":"query","description":"Whether a missing match may be generated. false returns 404 instead.","schema":{"type":"boolean","default":true}},{"name":"excludeIds","in":"query","description":"Comma-separated avatar UUIDs to exclude.","style":"form","explode":false,"schema":{"type":"array","items":{"type":"string","format":"uuid"}}}],"responses":{"302":{"description":"Redirect to the stable Faceplacer image endpoint.","headers":{"Location":{"description":"Faceplacer image URL.","schema":{"type":"string","format":"uri"}},"X-Faceplacer-Source":{"description":"Whether the redirect came from cache or generation.","schema":{"type":"string","enum":["cache","generated"]}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No existing displayable avatar matched generate=false.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"Unsupported method. Consult Allow; avatar, search, similarity, and image endpoints do not support HEAD because GET can invoke providers.","headers":{"Allow":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Generation is enabled, but the exact avatar combination already exists and is unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Generation service unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/search":{"get":{"operationId":"searchAvatars","summary":"Semantic text search across avatars","description":"Search existing displayable avatars. API key is optional: anonymous requests are rate-limited by IP and valid keys by key. Hard collection filters apply before the response limit; filtering uses the top 50 provider candidates, so fewer results may be returned. A nonempty q is required; use /collection for structured-only lookup. metadata.collectionMatches counts all displayable rows matching the structured filters, not semantic relevance. If results is empty but collectionMatches is positive, the semantic candidate window missed those matches. Counts and ranking are separate live reads, not a transactional snapshot.","tags":["Search"],"security":[{},{"apiKey":[]}],"parameters":[{"name":"q","in":"query","required":true,"description":"Natural language search query.","schema":{"type":"string","minLength":1,"maxLength":200},"example":"smiling woman in blazer"},{"name":"limit","in":"query","description":"Maximum number of results.","schema":{"type":"integer","default":12,"maximum":50,"minimum":1}},{"name":"gender","in":"query","description":"Comma-separated values: OR within this attribute and AND with other attributes.","style":"form","explode":false,"schema":{"type":"array","items":{"$ref":"#/components/schemas/Gender"}}},{"name":"age","in":"query","description":"Comma-separated values: OR within this attribute and AND with other attributes.","style":"form","explode":false,"schema":{"type":"array","items":{"$ref":"#/components/schemas/Age"}}},{"name":"ethnicity","in":"query","description":"Comma-separated values: OR within this attribute and AND with other attributes.","style":"form","explode":false,"schema":{"type":"array","items":{"$ref":"#/components/schemas/Ethnicity"}}},{"name":"background","in":"query","description":"Comma-separated values: OR within this attribute and AND with other attributes.","style":"form","explode":false,"schema":{"type":"array","items":{"$ref":"#/components/schemas/Background"}}},{"name":"style","in":"query","description":"Comma-separated values: OR within this attribute and AND with other attributes.","style":"form","explode":false,"schema":{"type":"array","items":{"$ref":"#/components/schemas/Style"}}},{"name":"profession","in":"query","description":"Comma-separated values: OR within this attribute and AND with other attributes.","style":"form","explode":false,"schema":{"type":"array","items":{"$ref":"#/components/schemas/Profession"}}},{"name":"expression","in":"query","description":"Comma-separated values: OR within this attribute and AND with other attributes.","style":"form","explode":false,"schema":{"type":"array","items":{"$ref":"#/components/schemas/Expression"}}},{"name":"pose","in":"query","description":"Comma-separated values: OR within this attribute and AND with other attributes.","style":"form","explode":false,"schema":{"type":"array","items":{"$ref":"#/components/schemas/Pose"}}}],"responses":{"200":{"description":"Search results ranked by similarity","content":{"application/json":{"schema":{"type":"object","properties":{"results":{"type":"array","items":{"$ref":"#/components/schemas/SearchResult"}},"metadata":{"$ref":"#/components/schemas/SearchCoverage"}},"required":["results","metadata"]}}}},"400":{"description":"Invalid query, limit, or filter value.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid explicitly supplied API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"Unsupported method. Consult Allow; avatar, search, similarity, and image endpoints do not support HEAD because GET can invoke providers.","headers":{"Allow":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit resets.","schema":{"type":"integer"}}}},"503":{"description":"Search provider unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/similar":{"get":{"operationId":"findSimilar","summary":"Find visually similar avatars","description":"Find avatars that are visually similar to a reference avatar using vector similarity search. Requires an API key.","tags":["Search"],"security":[{"apiKey":[]}],"parameters":[{"name":"key","in":"query","required":true,"description":"Faceplacer file key of the reference avatar.","schema":{"type":"string"},"example":"ZoUz8Wl9GzXQ.png"},{"name":"limit","in":"query","description":"Maximum number of results.","schema":{"type":"integer","default":12,"maximum":50}}],"responses":{"200":{"description":"Similar avatars ranked by cosine similarity","content":{"application/json":{"schema":{"type":"object","properties":{"results":{"type":"array","items":{"$ref":"#/components/schemas/SearchResult"}}}}}}},"405":{"description":"Unsupported method. Consult Allow; avatar, search, similarity, and image endpoints do not support HEAD because GET can invoke providers.","headers":{"Allow":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/image/{id}":{"get":{"operationId":"getImage","summary":"Serve an avatar image","description":"Retrieves a generated avatar image by ID. Supports dynamic resizing via CDN transforms. Image URLs returned by authenticated API calls are directly renderable.","tags":["Image"],"security":[],"parameters":[{"name":"id","in":"path","required":true,"description":"Avatar ID","schema":{"type":"string","format":"uuid"}},{"name":"size","in":"query","description":"Desired image size in pixels. Defaults to 1024.","schema":{"allOf":[{"$ref":"#/components/schemas/Size"}],"default":1024}},{"name":"download","in":"query","description":"Set to 1 or true to request an attachment download.","schema":{"type":"string","enum":["1","true"]}}],"responses":{"200":{"description":"Avatar image","content":{"image/png":{"schema":{"type":"string","format":"binary"}}}},"302":{"description":"Redirect to the stable image response.","headers":{"Location":{"description":"Stable Faceplacer image URL.","schema":{"type":"string","format":"uri"}}}},"400":{"description":"Invalid avatar id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Avatar not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"Unsupported method. Consult Allow; avatar, search, similarity, and image endpoints do not support HEAD because GET can invoke providers.","headers":{"Allow":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"X-API-Key","description":"API key for avatar generation, search, and similarity endpoints. Image URLs remain directly renderable."}},"schemas":{"Gender":{"type":"string","enum":["male","female","non-binary"]},"Age":{"type":"string","enum":["early-twenties","thirties","middle-aged","senior"]},"Ethnicity":{"type":"string","enum":["east-asian","south-asian","southeast-asian","black","white","latino","middle-eastern","mixed"]},"Background":{"type":"string","enum":["white","dark","gray","blurred"]},"Style":{"type":"string","enum":["casual","formal","business-casual"]},"Profession":{"type":"string","enum":["general","tech","creative","legal","education"]},"Expression":{"type":"string","enum":["neutral","smiling","laughing"]},"Pose":{"type":"string","enum":["front","slight-left","slight-right"]},"Size":{"type":"integer","enum":[64,128,256,512,1024],"default":256},"SearchResult":{"type":"object","properties":{"key":{"type":"string","description":"File key"},"similarity":{"type":"number","description":"Cosine similarity score (0-1)"},"url":{"type":"string","format":"uri","description":"Direct CDN image URL"}}},"Error":{"type":"object","required":["error","code","message","resolution"],"properties":{"error":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"},"resolution":{"type":"string"}}},"CollectionAvatar":{"type":"object","required":["id","url","name","gender","age","ethnicity","background","style","profession","expression","pose"],"properties":{"id":{"type":"string","format":"uuid"},"url":{"type":"string","format":"uri"},"name":{"type":"string","description":"Fictional display name."},"gender":{"$ref":"#/components/schemas/Gender"},"age":{"$ref":"#/components/schemas/Age"},"ethnicity":{"$ref":"#/components/schemas/Ethnicity"},"background":{"$ref":"#/components/schemas/Background"},"style":{"$ref":"#/components/schemas/Style"},"profession":{"$ref":"#/components/schemas/Profession"},"expression":{"$ref":"#/components/schemas/Expression"},"pose":{"$ref":"#/components/schemas/Pose"}}},"CollectionPagination":{"type":"object","required":["limit","hasMore","nextCursor"],"properties":{"limit":{"type":"integer","minimum":1,"maximum":100},"hasMore":{"type":"boolean"},"nextCursor":{"type":"string","nullable":true,"description":"Pass unchanged with the same filters; null at the final page."}}},"SearchCoverage":{"type":"object","required":["scope","candidateLimit","candidatesExamined","matchingCandidates","collectionMatches"],"properties":{"scope":{"type":"string","enum":["semantic-candidates"]},"candidateLimit":{"type":"integer","enum":[50]},"candidatesExamined":{"type":"integer","minimum":0,"description":"Provider candidates returned before joining and filtering."},"matchingCandidates":{"type":"integer","minimum":0,"description":"Displayable candidates satisfying all structured filters before the response limit."},"collectionMatches":{"type":"integer","minimum":0,"description":"All displayable collection rows satisfying the structured filters, independent of semantic query relevance. Zero means no structured matches in this live count."}}}}},"tags":[{"name":"Avatar","description":"Generate and retrieve avatar images"},{"name":"Search","description":"Search and find similar avatars"},{"name":"Image","description":"Serve and resize avatar images"}]}