{"openapi":"3.1.0","info":{"title":"Colour Memory API","description":"The colour reasoning layer for AI agents. Cultural risk, palette intelligence, WCAG accessibility, brand audit, image fidelity verification, archive-verified colour naming, ecommerce copy, and image generation briefs. Thousands of named colours across extensive cultural and historical archives. One MCP endpoint. colourmemory.com","version":"2.3.4"},"paths":{"/admin/stats":{"get":{"tags":["admin"],"summary":"Get Stats","operationId":"get_stats_admin_stats_get","parameters":[{"name":"x-admin-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Admin-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/queries":{"get":{"summary":"Admin Queries","description":"Return the last n queries in reverse-chronological order.\nIn-memory only -- resets on redeploy. Use for tester review.\n\nRequires X-Admin-Key header matching ADMIN_SECRET env var.\n\nExample: GET /admin/queries?n=50","operationId":"admin_queries_admin_queries_get","parameters":[{"name":"n","in":"query","required":false,"schema":{"type":"integer","default":100,"title":"N"}},{"name":"x-admin-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Admin-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/mcp":{"get":{"tags":["admin"],"summary":"Get Mcp","operationId":"get_mcp_admin_mcp_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":100,"title":"Limit"}},{"name":"x-admin-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Admin-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/expire-logs":{"get":{"tags":["admin"],"summary":"Expire Logs","description":"Security fix (2026-09-02), part 2 -- query_log/mcp_log retention.\ndry_run defaults to TRUE: reports what would be deleted, deletes\nnothing. Pass dry_run=false to actually delete. Same\nreport-then-confirm discipline as /admin/expire-anonymous-projects.\nThe real purge does not depend on this endpoint: main.py's\n_start_retention_job runs expire_old_logs(90, dry_run=False) daily.\nUse this for a manual dry-run report.","operationId":"expire_logs_admin_expire_logs_get","parameters":[{"name":"retention_days","in":"query","required":false,"schema":{"type":"integer","default":90,"title":"Retention Days"}},{"name":"dry_run","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Dry Run"}},{"name":"x-admin-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Admin-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/intelligence":{"get":{"tags":["admin"],"summary":"Get Intelligence","operationId":"get_intelligence_admin_intelligence_get","parameters":[{"name":"x-admin-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Admin-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/material":{"get":{"summary":"Get Material","operationId":"get_material_v1_material_get","parameters":[{"name":"period","in":"query","required":true,"schema":{"type":"string","description":"Historical period e.g. Tudor, Victorian, Georgian","title":"Period"},"description":"Historical period e.g. Tudor, Victorian, Georgian"},{"name":"surface","in":"query","required":true,"schema":{"type":"string","description":"Surface type e.g. wall, floor, textile, metal, ceramic","title":"Surface"},"description":"Surface type e.g. wall, floor, textile, metal, ceramic"},{"name":"style","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional style hint e.g. royal, domestic, ecclesiastical","title":"Style"},"description":"Optional style hint e.g. royal, domestic, ecclesiastical"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MaterialResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/scene":{"post":{"summary":"Get Scene","description":"Return a complete, coherent material palette for a defined period and room type.\nAll surfaces cross-checked for anachronisms. All illuminant values consistent.\nThe hard problem in historical world-building is not finding one correct colour.\nIt is finding twelve correct colours that were actually in the same room at the\nsame time and looked right together by firelight. This endpoint solves that.","operationId":"get_scene_v1_scene_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SceneRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SceneResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/personal-colour-analysis/jpeg":{"post":{"summary":"Personal Colour Analysis Jpeg","description":"Generate a shareable 1080x1350 JPEG personal colour analysis card.\n\nDELIBERATELY DISABLED (fix/llm-route-auth follow-up).\n\nAuthentication runs first and is unchanged: invalid or absent\ncredentials still terminate here with a 401, before anything else.\nOnce authenticated, this feature is simply not available -- it does\nNOT proceed to Vision or any other paid model call. This endpoint\nused to look up a route registered at the path\n\"/personal-colour-analysis\", which does not exist (the real route is\n\"/image/personal\"), so it always failed with a 500 before reaching\nthe model. Wiring it up to the real analysis core would make it\nnewly functional -- more scope than intended here -- so it stays\noff, deliberately and visibly, until that is its own decision.","operationId":"personal_colour_analysis_jpeg_personal_colour_analysis_jpeg_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PersonalColourJpegRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/reliability":{"get":{"summary":"Admin Reliability","description":"Fix 9 (Session 2B-i): connections, distinct authenticated callers\n(count only, never which keys), PDFs generated, top failure codes,\nand schema hashes currently being served -- the last one is\nspecifically useful for checking this session's own rollback\ncondition \"more than one schema hash served by the same deployed\nbuild\" without a manual log query.\n\nAdmin-gated (same X-Admin-Key/ADMIN_SECRET pattern as /admin/queries)\nand already rate-limited by the global RateLimitMiddleware every\nnon-/health route gets. Never returns individual API keys, IPs, or\nprompt/argument content -- see get_reliability_stats()'s own\ndocstring in persistent_logs.py for exactly what is and isn't queried.","operationId":"admin_reliability_admin_reliability_get","parameters":[{"name":"hours","in":"query","required":false,"schema":{"type":"integer","default":24,"title":"Hours"}},{"name":"x-admin-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Admin-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/project_migration_rehearsal":{"post":{"summary":"Admin Project Migration Rehearsal","description":"Session 2B-ii mandatory-checkpoint rehearsal -- exercises every\npersistent_projects.py function (including the Gap 1 ownership fix)\nagainst REHEARSAL_DATABASE_URL, NEVER the real DATABASE_URL. Refuses\nto run at all if REHEARSAL_DATABASE_URL is unset, rather than silently\nfalling back to production. This process runs on the real Railway\nservice (inside its private network) specifically because railway run\ncannot tunnel *.railway.internal DNS to a local machine -- see\npersistent_projects.py's own docstring on _DATABASE_URL_OVERRIDE.\n\nReturns only pass/fail booleans and small derived facts (counts,\nhashes, booleans) -- never a connection string, never full house_json\ncontent, never a raw house_ref/project_id beyond what's needed to\nshow one check succeeded.","operationId":"admin_project_migration_rehearsal_admin_project_migration_rehearsal_post","parameters":[{"name":"x-admin-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Admin-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/gap4_seed_and_rehearse":{"post":{"summary":"Admin Gap4 Seed And Rehearse","description":"Gap 4: seed a throwaway database with PRODUCTION'S REAL SCHEMA SHAPE\n(table definitions only, obtained by the caller via a read-only\n`pg_dump --schema-only` against production -- this endpoint never\ntouches production itself) BEFORE running the additive migration and\nthe full rehearsal suite against it. Proves the new tables don't\ncollide with any real existing table/constraint/index name and that\ninit_projects_db() behaves identically alongside production's actual\nschema, not just an empty database.\n\nSame REHEARSAL_DATABASE_URL-only safety rule as the sibling rehearsal\nendpoint. schema_sql is applied ONCE per call (the caller is expected\nto pass a fresh empty throwaway database each time -- this endpoint\ndoes not attempt to make the seed step itself idempotent, since a\nschema dump may contain plain CREATE TABLE, not CREATE TABLE IF NOT\nEXISTS).","operationId":"admin_gap4_seed_and_rehearse_admin_gap4_seed_and_rehearse_post","parameters":[{"name":"x-admin-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Admin-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Gap4SeedRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/apply_project_type_migration":{"post":{"summary":"Admin Apply Project Type Migration","description":"Brand Standard: applies persistent_projects.migrate_widen_project_type_\nconstraint() to the REAL production DATABASE_URL. The deliberate\nmirror-image safety rule of the rehearsal endpoints above (those\nrefuse to run UNLESS REHEARSAL_DATABASE_URL is set; this one refuses\nto run if it IS set, since that would make it ambiguous whether the\ncall is meant to hit a rehearsal DB or real production -- this\nendpoint's whole purpose is targeting production once rehearsal has\nalready passed elsewhere).\n\nPurely additive: widens chk_colour_projects_type from ('house') to\n('house', 'brand'). Touches zero existing rows -- no house_ref project\nchanges shape, gets re-validated, or is even read. Idempotent, safe to\ncall more than once. Rehearsed 39/39 against a throwaway Postgres\n(see /admin/project_migration_rehearsal) before this endpoint is ever\ninvoked against production, per the same two-phase discipline as\nSession 2B-ii's own house_ref migration.","operationId":"admin_apply_project_type_migration_admin_apply_project_type_migration_post","parameters":[{"name":"x-admin-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Admin-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/apply_deletion_token_migration":{"post":{"summary":"Admin Apply Deletion Token Migration","description":"Release-hardening pass (2026-08-06): applies persistent_projects.\nmigrate_add_deletion_capability_token() to the REAL production\nDATABASE_URL. Same mirror-image safety rule as\nadmin_apply_project_type_migration above (refuses to run if\nREHEARSAL_DATABASE_URL is set, to avoid ambiguity about which\ndatabase is being targeted).\n\nPurely additive: ADD COLUMN IF NOT EXISTS deletion_token_hash TEXT,\nnullable. Touches zero existing rows' data -- every existing project\n(anonymous or authenticated) gets deletion_token_hash = NULL, which\ncan never match any supplied token, so nothing becomes retroactively\ndeletable by this migration alone. Idempotent, safe to call more than\nonce. Rehearsed against a throwaway Postgres (see\n/admin/project_migration_rehearsal, which now also exercises the full\nanonymous deletion-token create/wrong-token/correct-token/pre-\nmigration-NULL matrix) before this endpoint is ever invoked against\nproduction.","operationId":"admin_apply_deletion_token_migration_admin_apply_deletion_token_migration_post","parameters":[{"name":"x-admin-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Admin-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/project_performance_rehearsal":{"post":{"summary":"Admin Project Performance Rehearsal","description":"Step 13: p50/p95 latency for project creation, resolution (both\nidentifiers), list, version retrieval, and PDF rendering via a\npersisted reference -- against REHEARSAL_DATABASE_URL only, same\nsafety rule as /admin/project_migration_rehearsal. Uses a real\nhouse_specify response (GeorgianPleasures, the same known-good\nfixture verify_deploy.py uses) rather than a synthetic stub, so the\nrender-latency number reflects a genuinely renderable document, not\na trivial one. PROJECT_PERSISTENCE_PHASE stays whatever production\nalready has it set to (normally \"off\") throughout -- this measures\npersistent_projects.py's functions directly, never the phase-gated\nHTTP endpoints, so it carries no risk of writing to a real customer\nproject regardless of the live phase value.","operationId":"admin_project_performance_rehearsal_admin_project_performance_rehearsal_post","parameters":[{"name":"n","in":"query","required":false,"schema":{"type":"integer","default":20,"title":"N"}},{"name":"x-admin-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Admin-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/mcp/log/public":{"get":{"summary":"Mcp Log Public","operationId":"mcp_log_public_mcp_log_public_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/query/log/public":{"get":{"summary":"Mcp Log Public","operationId":"mcp_log_public_query_log_public_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/archive/validate-document":{"post":{"summary":"Validate Document","description":"Validate every entry in a proposed document against the canonical archive.","operationId":"validate_document_archive_validate_document_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Payload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/archives":{"get":{"summary":"List Archives","operationId":"list_archives_archives_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/report/pdf":{"post":{"summary":"Generate Report Pdf","description":"Luxury colour report PDF.\nOne colour per page. Full-bleed left panel. Museum-grade provenance right.\nDesigned to feel like a high-end brand agency or cultural intelligence report.","operationId":"generate_report_pdf_report_pdf_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportPDFRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/mcp/mcp":{"get":{"summary":"Mcp Double Path Fix","description":"Redirect /mcp/mcp → /mcp for misconfigured clients.","operationId":"mcp_double_path_fix_mcp_mcp_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"post":{"summary":"Mcp Double Path Fix","description":"Redirect /mcp/mcp → /mcp for misconfigured clients.","operationId":"mcp_double_path_fix_mcp_mcp_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/ready":{"get":{"summary":"Ready","description":"READINESS, separate from /health (liveness). The deploy healthcheck\npoints here: an instance takes traffic only once search can answer by the\none production method. /health stays 200 while the process is alive.","operationId":"ready_ready_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/health":{"get":{"summary":"Health","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/system/status":{"get":{"summary":"System Status Endpoint","description":"Fix 5 (Session 2B-i): system_status's own dedicated body -- always\nin the canonical registry (visibility=\"primary\", category=\"start\"),\nalways callable free of archive/LLM credit (see _FREE_TOOLS below --\nsystem_status is unconditionally in it), never rate-limited beyond\nthe same abuse protection every endpoint gets.\n\nDeliberately does NOT include database_status/project_store_status --\nthose describe the persistence layer this pass explicitly excludes\n(it needs a supervised migration). Adding placeholder fields for a\nlayer that doesn't exist yet would be worse than omitting them.","operationId":"system_status_endpoint_system_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/tools/guide":{"post":{"summary":"Tools Guide Endpoint","description":"Fix 8: deterministic (no LLM, no archive lookup) tool-routing lookup.\nDeliberately calls NO auth/credit check (mirrors /health and\n/system/status) -- see resolve_tool_guide() for the rule table this\nis a plain wrapper around.","operationId":"tools_guide_endpoint_tools_guide_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolGuideRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/historical/query":{"post":{"summary":"Historical Colour Query","description":"Retrieve evidence-grounded historical colour knowledge across the seven\nvalidated sources, preserving each source's distinct type of knowledge.\n\nRead-only. Deterministic: term retrieval, intent weighting from registry\nmetadata, and a rule table -- no LLM call and no writes to any source\nartefact.\n\nThe answer layer (historical_intelligence.answers) was built and tested but\nnever wired in, so this endpoint used to return raw retrieval output: no\nfalse-premise correction, and structured values (Vanderpoel's percentages,\nHokusai's application fields) reachable only in evidence mode. It now runs\nthrough build_packet, which is where that logic already lived.","operationId":"historical_colour_query_historical_query_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HistoricalColourQuery"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/query/conceptual":{"post":{"summary":"Query Conceptual","description":"Ask a cultural or material colour question. Archive-grounded response.\n\nn_results is now AUTO-DETECTED from query intent if not explicitly set:\n- Single colour questions  → 1 result\n- Conversational queries   → 3 results\n- Palette requests         → 5 results\n- Exploration queries      → 6 results\n\nOverride by passing n_results explicitly.\n\nExample:\n    {\"query\": \"what colour represents grief\", \"n_results\": 4}\n    {\"query\": \"toxic green pigment history\", \"archive\": \"Pigment\"}","operationId":"query_conceptual_query_conceptual_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConceptualQuery"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/verify":{"post":{"summary":"Public Verifier","description":"Public homepage verifier. Provide exactly one of:\n  {\"hex\": \"#D4AF37\"}          -- routes to the colour passport logic\n  {\"query\": \"toxic green pigment history\"}  -- routes to archive search\n\nNo API key required. Limited to 5 free checks per IP per rolling 24h\n(see check_verifier_quota) on top of the site-wide per-IP request floor.","operationId":"public_verifier_verify_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifierRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/query/hex":{"post":{"summary":"Query Hex","description":"Find nearest archive colours to a hex value.\nOptional: restrict to one archive.\n\nExample:\n    {\"hex\": \"#D4AF37\", \"n_results\": 5}\n    {\"hex\": \"#2030A0\", \"archive\": \"Pigment\"}","operationId":"query_hex_query_hex_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HexQuery"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/match":{"post":{"summary":"Match Image","description":"PRIMARY ENDPOINT for Pixel phone workflow.\n\nAccepts a photo. Extracts dominant colour in memory using:\n  - Five-point sampling (centre + four corners)\n  - sRGB pixels read as D65 CIELAB (no chromatic adaptation; no white-balance correction)\n  - CIEDE2000 nearest-neighbour against the full archive\n\nThe image is NEVER stored. It exists in memory only for the duration of this call.\nPrivacy guarantee: we never see your photos.\n\nReturns top-n archive matches with dE2000, confidence, nearest RAL.\n\nUsage from curl:\n    curl -X POST https://api.colourmemory.com/match           -F \"file=@photo.jpg\" -F \"n=5\"\n\nUsage from fetch (browser / PWA):\n    const fd = new FormData();\n    fd.append('file', blob, 'photo.jpg');\n    fd.append('n', '5');\n    fetch('/match', { method: 'POST', body: fd })","operationId":"match_image_match_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_match_image_match_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/physics/{hex_val}":{"get":{"summary":"Get Physics","description":"Display-colour metrics for any hex value (the colour_metrics tool).\n\nReturns:\n- LRV estimate from luminance (CIE Y x 100) and band -- not a measured LRV\n- Relative luminance and CIELAB L*, a*, b*, chroma, hue angle (D65)\n- Bradford corresponding colours under CIE A (2856K) and F11 (4000K)\n- not_derivable: what a hex cannot support (thermal / solar performance,\n  finish effects, measured LRV), with reasons\n- Pigment: always unknown -- not identifiable from a hex\n\nDerived from the display colour, not measured; methodology in the response.\n\nExample:\n    GET /physics/1B1556\n    GET /physics/CC1A14?zone=Red","operationId":"get_physics_physics__hex_val__get","parameters":[{"name":"hex_val","in":"path","required":true,"schema":{"type":"string","title":"Hex Val"}},{"name":"zone","in":"query","required":false,"schema":{"type":"string","default":"","title":"Zone"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/colour/{name}":{"get":{"summary":"Get Colour","description":"Look up a colour by exact name, partial name, or stable slug (archive:colour-slug).\nSlugs come from /archive/search results -- preferred for reliable agent retrieval.\nExample slug: racingsilks:sir-charles-bunbury-body-pink","operationId":"get_colour_colour__name__get","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/relationships/{record_id}":{"get":{"summary":"Record Relationships","description":"What is this record connected to, and why?\n\nBounded on purpose: one hop, a per-predicate cap (raisable via\nmax_per_predicate, default 12 -- see that parameter's own comment), and the\nfour relationship classes returned in SEPARATE blocks so a caller cannot\nmistake a computed colour distance for something a historical source said.\n\n`include_unresolved` defaults to FALSE. Same-name candidates across sources\nare the cheapest edge in the system and the easiest to misread as evidence,\nso they are withheld unless asked for by name.\n\nTruncation, at whatever cap is in effect, is never silent: `traversal.\ntruncated` reports how many edges of each predicate were cut, and the true\ntotal for a predicate is always edge_count + traversal.truncated.get(that\npredicate, 0) -- confirmed already correct today (2026-09-02) for real\ntruncated Wada records, independent of this parameter.","operationId":"record_relationships_relationships__record_id__get","parameters":[{"name":"record_id","in":"path","required":true,"schema":{"type":"string","title":"Record Id"}},{"name":"include_unresolved","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Unresolved"}},{"name":"include_computed","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Include Computed"}},{"name":"max_per_predicate","in":"query","required":false,"schema":{"type":"integer","default":12,"title":"Max Per Predicate"}},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/relationships/{record_id}/combinations":{"get":{"summary":"Record Combination Companions","description":"Every colour published alongside this one, across every combination.\n\nOne call, one metered charge, however many combinations the record has.\n\nA companion's hex is null when the name did not resolve to an\nINDEPENDENTLY CONFIRMED record from the same archive -- never a guessed\nhex. The name still comes back; only the swatch is withheld. This is the\nsame drop-rather-than-guess discipline _load_name_index() already applies\nserver-side, and the same one the plugin applied client-side before this\nendpoint existed (isVerifiedWadaLookup) -- moved, not relaxed.\n\nRides an open plugin trial rather than charging one of its own: the Wada\nsection is part of the selection the passport has already charged for.","operationId":"record_combination_companions_relationships__record_id__combinations_get","parameters":[{"name":"record_id","in":"path","required":true,"schema":{"type":"string","title":"Record Id"}},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/relationships/{a}/why/{b}":{"get":{"summary":"Why Connected","description":"Why are these two records connected -- if they are at all.","operationId":"why_connected_relationships__a__why__b__get","parameters":[{"name":"a","in":"path","required":true,"schema":{"type":"string","title":"A"}},{"name":"b","in":"path","required":true,"schema":{"type":"string","title":"B"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/archive/{name}":{"get":{"summary":"Get Archive","description":"List all colours in a named archive.","operationId":"get_archive_archive__name__get","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/zones":{"get":{"summary":"List Zones","operationId":"list_zones_zones_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/colours/zone/{zone}":{"get":{"summary":"Get Zone","operationId":"get_zone_colours_zone__zone__get","parameters":[{"name":"zone","in":"path","required":true,"schema":{"type":"string","title":"Zone"}},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/accessibility/{hex_val}":{"get":{"summary":"Get Accessibility","description":"WCAG 2.1 accessibility report. EU Accessibility Act June 2025.","operationId":"get_accessibility_accessibility__hex_val__get","parameters":[{"name":"hex_val","in":"path","required":true,"schema":{"type":"string","title":"Hex Val"}},{"name":"background","in":"query","required":false,"schema":{"type":"string","default":"FFFFFF","title":"Background"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/accessibility/pair":{"get":{"summary":"Accessibility Pair","description":"Contrast ratio between any two colours.","operationId":"accessibility_pair_accessibility_pair_get","parameters":[{"name":"hex1","in":"query","required":true,"schema":{"type":"string","title":"Hex1"}},{"name":"hex2","in":"query","required":true,"schema":{"type":"string","title":"Hex2"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/accessibility/matrix":{"post":{"summary":"Accessibility Matrix","description":"Full WCAG 2.1 accessibility matrix for a palette.\nEvery foreground/background combination, all four pass/fail grades.\nEU Accessibility Act June 2025.","operationId":"accessibility_matrix_accessibility_matrix_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccessibilityMatrixRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/accessibility/usage-rules":{"post":{"summary":"Accessibility Usage Rules","description":"Convert WCAG matrix into actionable design-system rules.\nReturns safe pairs, large-text-only pairs, decorative-only pairs,\nper-colour best text recommendation, and component usage rules.","operationId":"accessibility_usage_rules_accessibility_usage_rules_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccessibilityUsageRulesRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/colour/name-slugs":{"post":{"summary":"Colour Name Slugs","description":"Return every developer token format for a hex value.\nCSS variable, kebab-case, camelCase, PascalCase, Tailwind class,\nTypeScript const, and SCSS variable. Archive-grounded name source.","operationId":"colour_name_slugs_colour_name_slugs_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ColourNameSlugsRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/palette/quality-audit":{"post":{"summary":"Palette Quality Audit","description":"Full palette quality audit. Scores on accessibility, cultural risk,\ntonal range, colour diversity, and archive naming strength.\nReturns overall score 0-100, grade, and prioritised fix list.\nDeterministic — no LLM cost.","operationId":"palette_quality_audit_palette_quality_audit_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaletteAuditRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/palette/light-dark":{"post":{"summary":"Palette Light Dark","description":"Generate light-mode and dark-mode role maps from a palette.\nAnalyses LRV of each colour, assigns roles, identifies safe text pairs\nfor each mode, and flags missing neutrals.","operationId":"palette_light_dark_palette_light_dark_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaletteLightDarkRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/colour/font-advisor":{"post":{"summary":"Font Colour Advisor","description":"Given a background hex and a palette of candidate foreground colours,\nreturn them ranked by contrast ratio with WCAG grades and specific\nrecommendations for body text, large text, and UI components.","operationId":"font_colour_advisor_colour_font_advisor_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FontColourAdvisorRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/archive/search":{"post":{"summary":"Archive Search","description":"Full-text keyword search across archive colour names and notes.\nFind colours by name fragment, material, cultural reference, or pigment type.\nComplements conceptual embedding search with exact keyword matching.","operationId":"archive_search_archive_search_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArchiveSearchRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/colour/combination-check":{"post":{"summary":"Colour Combination Check","description":"Assess 2-5 colours as a combination for a given context.\nReturns harmony type, clash warnings, contrast summary,\nand specific deployment rules for the context.","operationId":"colour_combination_check_colour_combination_check_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ColourCombinationRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/accessibility/simulate/{hex_val}":{"get":{"summary":"Get Cvd Simulation","description":"Simulate full-severity protanopia, deuteranopia and tritanopia only\n(Machado, Oliveira & Fernandes 2009, severity 1.0, linear sRGB). Anomalous\ntrichromacy and partial severities are not simulated.","operationId":"get_cvd_simulation_accessibility_simulate__hex_val__get","parameters":[{"name":"hex_val","in":"path","required":true,"schema":{"type":"string","title":"Hex Val"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/palette/colourways":{"post":{"summary":"Palette Colourways","description":"Generate archive-grounded colourway variants from a base palette.\nTakes a base palette and returns 2-3 variant colourways at different\ntonal registers — darker, lighter, cooler, warmer, or complementary.\nEach colourway is archive-verified and scored.","operationId":"palette_colourways_palette_colourways_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaletteColourwaysRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/analyse/image":{"post":{"summary":"Analyse Image","description":"Extract dominant colours from an image using k-means clustering.\nDeterministic — same image always returns same palette.\nFeed hex values directly into POST /brand/audit.\n\nReturns colours ranked by pixel area percentage.","operationId":"analyse_image_analyse_image_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyseImageRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/colour/match-paint/{hex_val}":{"get":{"summary":"Get Brand Match","description":"Nearest paint colours from the brands in the paint data (Farrow & Ball,\nPaint & Paper Library). A brand filter that matches no loaded brand used\nto return an empty list with no explanation -- the tool's own argument\ntext names Little Greene, which the data does not contain -- so an agent\nfilled the gap with guessed colours. It now says the brand is absent and\nlists the brands that are present; it never substitutes another brand.","operationId":"get_brand_match_colour_match_paint__hex_val__get","parameters":[{"name":"hex_val","in":"path","required":true,"schema":{"type":"string","title":"Hex Val"}},{"name":"brand","in":"query","required":false,"schema":{"type":"string","default":"","title":"Brand"}},{"name":"n","in":"query","required":false,"schema":{"type":"integer","default":3,"title":"N"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/palette/pattern":{"post":{"summary":"Palette Pattern","description":"Assign archive palette colours to pattern roles based on pattern type.\nReturns structured colour assignments with role labels, proportions\nsumming to 100%, and a locked Midjourney prompt.\n\nPattern types: stripe, damask, lozenge, trellis, ogee, flock, geometric\nEach type has its own palette architecture logic.","operationId":"palette_pattern_palette_pattern_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PalettePatternRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/palette-card":{"post":{"summary":"Palette Card","description":"Upload a photo, get back a shareable palette card PNG.\n\nMatches the digby.shop / Colour Memory PWA output format:\n- Source photo at top (rounded corners)\n- Up to 6 archive-named colour swatches below\n- Colour name and hex on each swatch\n- www.colourmemory.com watermark\n\nReturns: image/png stream (direct download or display)","operationId":"palette_card_palette_card_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_palette_card_palette_card_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/colour-card/{hex_val}":{"get":{"summary":"Colour Card","description":"Returns a branded PNG colour card for any hex value.\n\nFormat matches the digby.shop / Colour Memory PWA single-colour view:\n- Full colour background\n- Archive name large in elegant serif (bottom anchored)\n- Provenance note in italic below\n- Hex · LRV in mono at bottom\n- www.colourmemory.com watermark\n\nUsage: GET /colour-card/54684F\nReturns: image/png","operationId":"colour_card_colour_card__hex_val__get","parameters":[{"name":"hex_val","in":"path","required":true,"schema":{"type":"string","title":"Hex Val"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/specify":{"post":{"summary":"Specify Palette","description":"Generate a complete room specification from a palette of hex values.\n\nTakes 2-8 colours and returns:\n- Surface assignments (walls, ceiling, joinery, floor, accents)\n- 60-30-10 proportion breakdown\n- Lighting behaviour under different illuminants\n- North/south facing recommendations\n- Archive names for each colour\n- Material and lightfastness warnings\n\nOne call. Complete specification. No further processing needed.\n\nExample:\n    POST /specify\n    {\"colours\": [\"#3A5C8C\", \"#E2D8C8\", \"#1B1556\", \"#C4A052\"],\n     \"room_type\": \"living\",\n     \"style\": \"heritage\"}","operationId":"specify_palette_specify_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpecifyRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/generate-prompt":{"post":{"summary":"Generate Image Prompt","description":"Generate a culturally grounded image prompt for any AI image generator.\n\nThe key insight: archive colour names carry civilisational weight that\nhex values do not. 'Funai XinguLaranja -- Museu do Indio' tells Midjourney\na civilisation. '#A66438' tells it nothing. This endpoint uses archive names\nas cultural anchors to produce prompts that generate historically specific,\ngeographically grounded imagery.\n\nSupports: midjourney, dalle, stable-diffusion, firefly, runway\nStyles: architectural, landscape, material, costume, abstract, cinematic\n\nAUTH: requires the normal API key mechanism, checked before any archive\nlookup or Claude call. Previously took no api_key parameter at all.","operationId":"generate_image_prompt_generate_prompt_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImagePromptRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/mcp/telemetry":{"get":{"summary":"Mcp Telemetry","description":"Recent MCP tool calls and what they returned. No arguments, no prompts.\n\nADMIN-GATED. It was readable by anyone: the rows carry no arguments and\nno colour values, but they do carry every caller's User-Agent, the tools\nthey called, when, and how long each took -- which is a usage picture of\nother people's clients, served to whoever asked. Operationally it is\nworth keeping, so it is gated rather than removed.\n\nThe SAME mechanism as /admin/queries and /admin/reliability -- _admin_ok\nagainst ADMIN_SECRET, 403 on failure -- deliberately, rather than a new\none. _admin_ok fails closed when ADMIN_SECRET is unset, so a deployment\nthat forgets the variable serves nothing instead of everything.","operationId":"mcp_telemetry_mcp_telemetry_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":200,"title":"Limit"}},{"name":"tool","in":"query","required":false,"schema":{"type":"string","default":"","title":"Tool"}},{"name":"client","in":"query","required":false,"schema":{"type":"string","default":"","title":"Client"}},{"name":"x-admin-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Admin-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/palette/export/{pid}/{fmt}":{"get":{"summary":"Palette Export File","description":"One export file. The id is the capability; nothing else is needed.\n\nObserved, because a host fetching a PDF and failing was invisible: format,\nstatus, size and the user-agent family, and nothing about the palette or\nthe id itself.","operationId":"palette_export_file_palette_export__pid___fmt__get","parameters":[{"name":"pid","in":"path","required":true,"schema":{"type":"string","title":"Pid"}},{"name":"fmt","in":"path","required":true,"schema":{"type":"string","title":"Fmt"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/colour-story/{hex_val}":{"get":{"summary":"Colour Story","description":"Return a rich cultural narrative about a colour's journey through history.","operationId":"colour_story_colour_story__hex_val__get","parameters":[{"name":"hex_val","in":"path","required":true,"schema":{"type":"string","title":"Hex Val"}},{"name":"n_archives","in":"query","required":false,"schema":{"type":"integer","default":5,"title":"N Archives"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/palette-from-concept":{"post":{"summary":"Palette From Concept","description":"Generate a historically grounded palette from a cultural concept.","operationId":"palette_from_concept_palette_from_concept_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaletteConceptRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/palette/strict-concept":{"post":{"summary":"Strict Palette From Concept","description":"Like palette_from_concept but with archive filtering and relevance controls.\nUse allowed_archives to restrict results to specific cultural traditions.\nUse min_relevance to filter out weak concept matches.","operationId":"strict_palette_from_concept_palette_strict_concept_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StrictPaletteConceptRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/mix-colours":{"post":{"summary":"Mix Colours","description":"Simulate subtractive pigment mixing of two colours in CIE Lab space.","operationId":"mix_colours_mix_colours_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MixRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/colour/timeline":{"post":{"summary":"Colour Timeline","description":"Trace a colour concept through history in chronological order.","operationId":"colour_timeline_colour_timeline_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ColourTimelineRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/image/palette":{"post":{"summary":"Analyse Image Palette","description":"Extract dominant colours from a base64 image or URL and match to archive.","operationId":"analyse_image_palette_image_palette_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImagePaletteRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/agent/verify-palette":{"post":{"summary":"Agent Verify Palette","description":"Verify that an AI-generated image actually used the colours specified\nin an agent_brief. Extracts dominant colours from the image and compares\nthem against the target palette using CIEDE2000. Returns a fidelity score,\nper-colour match report, and a verdict.","operationId":"agent_verify_palette_agent_verify_palette_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentVerifyRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/colour/passport":{"post":{"summary":"Colour Passport Endpoint","description":"Canonical colour truth object. Accepts a single hex or a list of hexes.\nFor a single hex, returns one passport. For multiple hexes, returns a batch.\n\nprincipal_archive/principal_name (single-hex mode only): \"pick the\nstory\" -- return a SPECIFIC named record's full passport data instead\nof the ranking algorithm's own pick, restricted to that hex's real\nexact-hex ties (see hex_collision/additional_matches on a prior\ncall). Not supported in batch (hexes) mode.\n\nBatch mode accepts at most 20 unique valid hexes; more is refused with\n400 TOO_MANY_UNIQUE_COLOURS rather than silently truncated.\n\nMetering: one unit per unique colour returned, identical to\n/colour/passports and identical for keyed and keyless callers. Keyless\ncallers draw on the plugin trial; the sections a single selection draws\nride that selection's charge (see _check_key_or_trial).","operationId":"colour_passport_endpoint_colour_passport_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ColourPassportRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/colour/passports":{"post":{"summary":"Batch Passport Endpoint","description":"Batch Colour Passport -- one passport per unique hex, in one call.\n\nDeduplicates and validates input, preserving order. Invalid hexes are\nlisted under `invalid`; hexes whose passport could not be built are listed\nunder `errors`. The response carries NO quota or entitlement information.\n\nAT MOST 20 UNIQUE VALID HEXES PER REQUEST, AND MORE IS REFUSED, NOT\nTRUNCATED. More than 20 returns 400 TOO_MANY_UNIQUE_COLOURS with\nrequested_unique and max_unique, having processed and charged nothing.\nDuplicates and invalid values do not count towards the limit. A caller\ncovering a larger set must split it into requests of at most 20.\n\nMetering: one unit per unique colour RETURNED -- the same as\n/colour/passport, not one per request. Requires a key; this route does not\naccept the keyless plugin trial (use /colour/passport with `hexes`).\nInsufficient entitlement fails closed: nothing processed, nothing charged,\n429 INSUFFICIENT_ENTITLEMENT with requested_unique and available.","operationId":"batch_passport_endpoint_colour_passports_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchPassportRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/compare-colours":{"post":{"summary":"Compare Colours Endpoint","description":"Deep perceptual and cultural comparison between two hex values.","operationId":"compare_colours_endpoint_compare_colours_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompareRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/colour/cultural-risk":{"post":{"summary":"Cultural Risk Endpoint","description":"Assess cultural risk of a hex value or palette.","operationId":"cultural_risk_endpoint_colour_cultural_risk_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CulturalRiskRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/colour/cultural-risk-v2":{"post":{"summary":"Cultural Risk V2 Endpoint","operationId":"cultural_risk_v2_endpoint_colour_cultural_risk_v2_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CulturalRiskV2Request"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/session/design":{"post":{"summary":"Design Session Endpoint","description":"One-call compound tool: concept to complete palette package.","operationId":"design_session_endpoint_session_design_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DesignSessionRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/image/personal":{"post":{"summary":"Personal Colour Analysis","description":"Full personal colour analysis from a portrait photo (public entry point).\n\nAUTH: requires the normal API key mechanism, checked BEFORE any image\ndecoding, Claude Vision call, or other model invocation. This endpoint\nwas previously reachable with no credential at all -- see the\nfix/llm-route-auth branch note. It now authenticates once here and\ndelegates to the shared, unauthenticated core.","operationId":"personal_colour_analysis_image_personal_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PersonalColourRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/colour/style-match":{"post":{"summary":"Style Match","description":"Fashion colour stylist. Does this bag go with this outfit?\nAnalyses outfit item colours against the archive and each other.\nReturns verdict, what works, what clashes, missing piece, and alternatives.","operationId":"style_match_colour_style_match_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StyleMatchRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/personal-colour-analysis/pdf":{"post":{"summary":"Personal Colour Analysis Pdf","description":"Premium branded personal colour analysis PDF.\nHybrid design: large photo, extracted colour circles, 3-column palette grid,\nsignature colour block, avoid section with X marks.\nPhoto never stored.\n\nAUTH: requires the normal API key mechanism, checked BEFORE the analysis\n(and therefore before any Claude Vision call) runs. Authenticates once\nhere and calls the shared, unauthenticated core directly -- NOT the\n/image/personal route wrapper -- so this in-process call is not charged\na second time.","operationId":"personal_colour_analysis_pdf_personal_colour_analysis_pdf_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PersonalColourRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/interior-specification":{"post":{"summary":"Interior Specification","description":"Generate a complete interior colour specification from a concept.\nReturns palette, surface assignments, paint matches, light behaviour,\nand cultural rationale. The colour consultation as an API.","operationId":"interior_specification_interior_specification_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InteriorSpecRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/interior-specification/pdf":{"post":{"summary":"Interior Specification Pdf","description":"Generate a premium branded PDF interior colour specification.\nThe colour consultation as a downloadable document.\nSuitable for sharing with clients, contractors, or on social media.","operationId":"interior_specification_pdf_interior_specification_pdf_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InteriorSpecRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/house/specify":{"post":{"summary":"House Specify","description":"Multi-room colour scheme grounded entirely in documented archive\nprovenance. Groups candidates by weighted provenance strength (same\nobject > same pattern colourway > same source entry > same pattern\nbook > same designer+material > same designer > same period+\ninstitution > visual similarity fallback), assigns groups to rooms\nrespecting orientation constraints, and builds full colour cards\n(paint matches, LRV, illuminant behaviour, WCAG) for every colour.\nHistorical rationale is templated only from documented fields; design\nrationale (room/surface assignment) is clearly separated and never\npresented as a historical claim.","operationId":"house_specify_house_specify_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HouseSpecifyRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/project/get":{"post":{"summary":"Project Get","operationId":"project_get_project_get_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectGetRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/project/list":{"post":{"summary":"Project List","operationId":"project_list_project_list_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectListRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/project/versions":{"post":{"summary":"Project Versions","operationId":"project_versions_project_versions_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectVersionsRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/project/delete":{"post":{"summary":"Project Delete","operationId":"project_delete_project_delete_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectDeleteRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/project/export":{"post":{"summary":"Project Export Route","description":"Session 2B-iii: editable DOCX/XLSX export of house-flagship content.\nAccepts exactly one of house/house_ref/project_id, resolved through\nthe SAME _resolve_house_input palette_pdf uses -- no separate auth\nor resolution path. Never calls house_specify, never re-runs\nreasoning; renders only what was already resolved and stored.","operationId":"project_export_route_project_export_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectExportRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/brand/guideline/specify":{"post":{"summary":"Brand Guideline Specify Route","description":"Colour Memory Brand Standard: brand_guideline_specify per\nbrand-guideline-generator-spec.md §4. A genuinely new, compute-heavy\ngeneration call (three archive-grounded candidate palettes, evidence\nscoring, collision/accessibility checks) -- metered like\nbrand_collision_check, unlike project_export's free reuse of\nalready-generated content.","operationId":"brand_guideline_specify_route_brand_guideline_specify_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandGuidelineSpecifyRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/brand/guideline/select":{"post":{"summary":"Brand Guideline Select Route","description":"Colour Memory Brand Standard: brand_guideline_select per\nbrand-guideline-generator-spec.md §5. Records a manual decision\nagainst an existing brand_ref and produces a revised version of it.","operationId":"brand_guideline_select_route_brand_guideline_select_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandGuidelineSelectRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/brand/guideline/pdf":{"post":{"summary":"Brand Guideline Pdf Route","description":"Colour Memory Brand Standard, step 6 of the build order: renders the\nclient-facing document (cover, directions, decision, system, argument,\napplication, accessibility matrix, provenance/evidence) from an\nalready-persisted brand_ref's\nfrozen snapshot. Never re-runs brand_guideline_specify, never\nrematches an archive, never mutates the resolved project -- the\nfrozen-snapshot invariant applies here exactly as it does for\nhouse_ref/palette_pdf.","operationId":"brand_guideline_pdf_route_brand_guideline_pdf_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandGuidelinePDFRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/brand/guideline/claims":{"post":{"summary":"Brand Guideline Claims Route","description":"Release-hardening pass (2026-08-06), Bug 3: resolves claim_id values\n(returned inline on every colour by brand_guideline_specify/select)\ninto their full claim record -- source title/locator/citation,\npermitted claim text, do_not_say restrictions, claim_role. Read-only,\nreads only the already-persisted frozen brand_ref snapshot exactly\nlike brand_guideline_pdf does.","operationId":"brand_guideline_claims_route_brand_guideline_claims_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandGuidelineClaimsRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/project_cleanup":{"post":{"summary":"Admin Project Cleanup","description":"Step 9: bounded expiry cleanup for TEMPORARY (anonymous) projects only\n-- deliberately NOT an automatic background thread (unlike the image\nsweeper above). Manually triggered, admin-gated, batched, and\ndry_run=True by default so an accidental call never deletes anything.\nAuthenticated projects (expires_at=NULL) are structurally unreachable\nby this query -- see expire_anonymous_projects's own docstring.","operationId":"admin_project_cleanup_admin_project_cleanup_post","parameters":[{"name":"batch_size","in":"query","required":false,"schema":{"type":"integer","default":500,"title":"Batch Size"}},{"name":"dry_run","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Dry Run"}},{"name":"x-admin-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Admin-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/palette/iterate":{"post":{"summary":"Palette Iterate","operationId":"palette_iterate_palette_iterate_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaletteIterateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/colour/{name}/variants":{"get":{"summary":"Colour Variants","operationId":"colour_variants_colour__name__variants_get","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/palette/export":{"post":{"summary":"Palette Export","operationId":"palette_export_palette_export_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaletteExportRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/palette/compare":{"post":{"summary":"Palette Compare","operationId":"palette_compare_palette_compare_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaletteCompareRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/colour/name-generator":{"post":{"summary":"Colour Name Generator","operationId":"colour_name_generator_colour_name_generator_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NameGeneratorRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/mcp/directory/":{"get":{"summary":"Mcp Directory Endpoint","description":"The submitted Anthropic Software Directory surface.\n\nSeven tools, anonymous, read-only. Deliberately takes NO api_key\nparameter and reads no key header: the surface advertises no\nauthentication, so a key must not be able to change what it does. All it\nadds over mcp_endpoint is the marker.","operationId":"mcp_directory_endpoint_mcp_directory__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"post":{"summary":"Mcp Directory Endpoint","description":"The submitted Anthropic Software Directory surface.\n\nSeven tools, anonymous, read-only. Deliberately takes NO api_key\nparameter and reads no key header: the surface advertises no\nauthentication, so a key must not be able to change what it does. All it\nadds over mcp_endpoint is the marker.","operationId":"mcp_directory_endpoint_mcp_directory__post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/mcp/directory":{"get":{"summary":"Mcp Directory Endpoint","description":"The submitted Anthropic Software Directory surface.\n\nSeven tools, anonymous, read-only. Deliberately takes NO api_key\nparameter and reads no key header: the surface advertises no\nauthentication, so a key must not be able to change what it does. All it\nadds over mcp_endpoint is the marker.","operationId":"mcp_directory_endpoint_mcp_directory_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"post":{"summary":"Mcp Directory Endpoint","description":"The submitted Anthropic Software Directory surface.\n\nSeven tools, anonymous, read-only. Deliberately takes NO api_key\nparameter and reads no key header: the surface advertises no\nauthentication, so a key must not be able to change what it does. All it\nadds over mcp_endpoint is the marker.","operationId":"mcp_directory_endpoint_mcp_directory_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/mcp/directory-preview/":{"get":{"summary":"Mcp Directory Preview Endpoint","description":"The directory surface with paid tools switched on. 404 when off.\n\nAnonymous or unpaid: the free directory tools plus the paid teasers, and\nany full-server tool answers with the sign-in / upgrade challenge.\nSigned in and PAYING: the full server, all of it, on the account's key.\nEither way every tool carries the Colour Memory card (cm_preview_ui).","operationId":"mcp_directory_preview_endpoint_mcp_directory_preview__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"post":{"summary":"Mcp Directory Preview Endpoint","description":"The directory surface with paid tools switched on. 404 when off.\n\nAnonymous or unpaid: the free directory tools plus the paid teasers, and\nany full-server tool answers with the sign-in / upgrade challenge.\nSigned in and PAYING: the full server, all of it, on the account's key.\nEither way every tool carries the Colour Memory card (cm_preview_ui).","operationId":"mcp_directory_preview_endpoint_mcp_directory_preview__post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/mcp/directory-preview":{"get":{"summary":"Mcp Directory Preview Endpoint","description":"The directory surface with paid tools switched on. 404 when off.\n\nAnonymous or unpaid: the free directory tools plus the paid teasers, and\nany full-server tool answers with the sign-in / upgrade challenge.\nSigned in and PAYING: the full server, all of it, on the account's key.\nEither way every tool carries the Colour Memory card (cm_preview_ui).","operationId":"mcp_directory_preview_endpoint_mcp_directory_preview_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"post":{"summary":"Mcp Directory Preview Endpoint","description":"The directory surface with paid tools switched on. 404 when off.\n\nAnonymous or unpaid: the free directory tools plus the paid teasers, and\nany full-server tool answers with the sign-in / upgrade challenge.\nSigned in and PAYING: the full server, all of it, on the account's key.\nEither way every tool carries the Colour Memory card (cm_preview_ui).","operationId":"mcp_directory_preview_endpoint_mcp_directory_preview_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/mcp/info":{"get":{"summary":"Mcp Info Endpoint","description":"Machine-readable product metadata for AI agents and crawlers.","operationId":"mcp_info_endpoint_mcp_info_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/.well-known/mcp.json":{"post":{"summary":"Mcp Endpoint","description":"MCP server — JSON-RPC 2.0 over Streamable HTTP transport.\nGET  → discovery document for registry scanners.\nPOST → JSON-RPC 2.0: initialize | tools/list | tools/call","operationId":"mcp_endpoint__well_known_mcp_json_post","parameters":[{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Key"}},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"summary":"Mcp Endpoint","description":"MCP server — JSON-RPC 2.0 over Streamable HTTP transport.\nGET  → discovery document for registry scanners.\nPOST → JSON-RPC 2.0: initialize | tools/list | tools/call","operationId":"mcp_endpoint__well_known_mcp_json_get","parameters":[{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Key"}},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/mcp/":{"post":{"summary":"Mcp Endpoint","description":"MCP server — JSON-RPC 2.0 over Streamable HTTP transport.\nGET  → discovery document for registry scanners.\nPOST → JSON-RPC 2.0: initialize | tools/list | tools/call","operationId":"mcp_endpoint_mcp__post","parameters":[{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Key"}},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"summary":"Mcp Endpoint","description":"MCP server — JSON-RPC 2.0 over Streamable HTTP transport.\nGET  → discovery document for registry scanners.\nPOST → JSON-RPC 2.0: initialize | tools/list | tools/call","operationId":"mcp_endpoint_mcp__get","parameters":[{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Key"}},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/mcp":{"post":{"summary":"Mcp Endpoint","description":"MCP server — JSON-RPC 2.0 over Streamable HTTP transport.\nGET  → discovery document for registry scanners.\nPOST → JSON-RPC 2.0: initialize | tools/list | tools/call","operationId":"mcp_endpoint_mcp_post","parameters":[{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Key"}},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"summary":"Mcp Endpoint","description":"MCP server — JSON-RPC 2.0 over Streamable HTTP transport.\nGET  → discovery document for registry scanners.\nPOST → JSON-RPC 2.0: initialize | tools/list | tools/call","operationId":"mcp_endpoint_mcp_get","parameters":[{"name":"api_key","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Key"}},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/":{"get":{"summary":"Root","operationId":"root__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/palette/pdf":{"post":{"summary":"Generate Palette Pdf","description":"Luxury colour specification PDF.\nOne colour per page. Full-bleed left panel. Museum-grade provenance right.","operationId":"generate_palette_pdf_palette_pdf_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PalettePDFRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/compare":{"post":{"summary":"Compare Archives","description":"Find the closest match to a colour from each archive independently.\n\nAccepts ONE of: hex value, colour name, or free-text query.\nReturns n_per_archive results from each available archive side by side.\n\nUseful for:\n  - \"How does the China archive describe this blue vs the Pigment archive?\"\n  - \"What pigment name matches this British heritage colour?\"\n  - \"Show me how all three archives see #2030A0\"\n\nExamples:\n    {\"hex\": \"#2030A0\", \"n_per_archive\": 2}\n    {\"name\": \"Jingtai Blue\", \"n_per_archive\": 3}\n    {\"query\": \"the colour of autumn wheat fields\", \"n_per_archive\": 2}","operationId":"compare_archives_compare_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompareRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/harmonies":{"post":{"summary":"Get Harmonies","description":"Archive-grounded colour harmonies in LCh perceptual colour space.\n\nFor each harmony type, rotates the input hue in LCh space, then finds\nthe nearest named archive colour to each harmony target using CIEDE2000.\n\nReturns named archive colours as harmonic partners -- with provenance,\ncultural context, and source -- not just hex codes.\n\n\"hay_contrast\" is a different kind of harmony type from the rest: not a\nfixed-angle rotation, but D.R. Hay's (1838) documented contrast pairing\nbetween six named hues, snapped from the input's nearest hue rather than\nrotated from it, and returning Field's proportional power for the pair\n(attributed to Field, not Hay, throughout) alongside the CIEDE2000\narchive match. Declines to answer (covered: false) rather than guess for\na hue nearer a tertiary region than any of the six -- Hay's data has no\nspecific number for those.\n\nExample:\n    {\"hex\": \"#1B1556\"}\n\nReturns complementary, analogous, triadic, and split-complementary\narchive colours for Iago Venom (Shakespeare, Othello II.3.347).","operationId":"get_harmonies_harmonies_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HarmonyRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/vanderpoel/pairing":{"post":{"summary":"Vanderpoel Pairing","description":"Emily Noyes Vanderpoel's documented \"good\" dyad/triad hue groupings\n(Color Problems, 1902, Plate XXXVI \"Good Dyads or Pairs\" and Plate\nXXXVII \"Good Triads\"), served straight from the build artefacts\nvanderpoel/vanderpoel_dyads.json and vanderpoel_triads.json.\n\nGiven a hex: snaps it to the nearest of Vanderpoel's eleven real\nhue-family labels, resolves that hex against the archive, and checks\nwhether the label is a member of any documented dyad or triad. Each\nOTHER member is returned with its own nearest real archive match\n(CIEDE2000, same machinery colour_harmonies uses), so a caller gets a\nnamed archive colour with provenance rather than a bare 1902 label\nstring.\n\nUnlike hay_contrast, this carries no proportional ratio -- only\nVanderpoel's own categorical \"good\" editorial judgement, printed\nverbatim on the plates. Member names are sourced from a transcriber's\ndigitisation_alt_text (an accessibility description of the plate\nimage), not verified printed captions -- every response says so in\nmember_source_caveat, and each grouping additionally carries its own\nrecord's wording of that caveat.\n\nReturns groupings: null (not an empty list, not a substituted weaker\nanswer) when there is nothing documented -- for a near-neutral input,\nwhere hue is not meaningfully defined and Vanderpoel's hue-family\njudgements do not apply, or where the nearest label is a member of no\ndyad or triad. With today's 11-label / 10-grouping dataset every label\nIS in at least one grouping, so in practice the near-neutral case is\nthe one that fires. Silence is the honest answer, not a forced match --\nsame principle as hay_contrast's covered:false.\n\nExample:\n    {\"hex\": \"#CC1A14\"}","operationId":"vanderpoel_pairing_vanderpoel_pairing_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VanderpoelPairingRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/subscribe":{"post":{"summary":"Subscribe","description":"Create a Colour Memory API key.\nPaid tiers only (studio / pro / enterprise): require Stripe payment_method_id.\n\nTrial keys are NOT issued here -- see the SECURITY note below.","operationId":"subscribe_subscribe_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscribeRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/key/status":{"get":{"summary":"Key Status","description":"Check usage and remaining calls for an API key.","operationId":"key_status_key_status_get","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/keys":{"get":{"summary":"Admin Keys","description":"Owner-only: all active keys and usage. Reads from Postgres. Requires X-Admin-Key header.","operationId":"admin_keys_admin_keys_get","parameters":[{"name":"x-admin-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Admin-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/diagnostics/preflight-negative-test":{"post":{"summary":"Preflight Negative Test","description":"Deterministically triggers a REAL bounds-check failure through the\nactual production renderer (a 60-character unbroken title, which\nSession 2A-i.1's regression suite confirmed reliably exceeds the\npage width since titles are character-sliced, not width-checked) --\nnot a mocked response, not a manifest-mutation shortcut. Confirms the\nfull pipeline (render -> preflight -> fail closed) behaves exactly\nlike the public path would on equivalently bad input, and that\n_deliver_pdf (and therefore the R2 upload it performs) is never\nreached: the early return on a failed preflight is structural, not\nconditional, so no upload is attempted here by construction.","operationId":"preflight_negative_test_admin_diagnostics_preflight_negative_test_post","parameters":[{"name":"x-admin-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Admin-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/mix/recipe":{"post":{"summary":"Mix Recipe","description":"Return a historically documented paint mixing recipe.\n\nSend a target hex colour or archive colour name plus your medium.\nReceive: nearest recipe, pigment details, modern supply equivalents,\ncompatibility warnings from historical trade manuals, fugitive flags.\n\nAdvisory use only. Not conservation or professional materials advice.","operationId":"mix_recipe_mix_recipe_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MixRecipeRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/mix/check":{"post":{"summary":"Mix Check","description":"Check compatibility of specific pigments in a given medium.\nReturns documented warnings from Cennini (1390), Tingry (1830),\nField (1835), and Church (1890).\n\nAdvisory use only.","operationId":"mix_check_mix_check_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PigmentCheckRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/mix/pigments":{"get":{"summary":"List Pigments","description":"List all pigments in the mixing database with their CI numbers and media compatibility.","operationId":"list_pigments_mix_pigments_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/mix/recipes":{"get":{"summary":"List Recipes","description":"List all available mixing recipes.","operationId":"list_recipes_mix_recipes_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/.well-known/oauth-authorization-server":{"get":{"summary":"Oauth Authorization Server","operationId":"oauth_authorization_server__well_known_oauth_authorization_server_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/oauth/token":{"post":{"summary":"Oauth Token","description":"Exchange an existing API key for a bearer token (client_credentials).\n\nKEPT, NOT DELETED. Nothing in this repository, the website source or the\nFigma plugin references it, and the flow it was added for cannot have\nbeen completing (its authorization endpoint 404s) -- but \"no caller\nfound by static search\" is not \"usage proven absent\", and the auth-scope\ninvariant is explicit that an authentication endpoint other product\nsurfaces might use is not removed on an assumption. Deleting it needs\nproduction request-log evidence, which is admin-gated; see\ndocs/audit/anthropic_review_response.md for the exact query.\n\nThe empty-bearer defect IS fixed. An anonymous caller posting {} used to\nreceive 200 {\"access_token\": \"\", \"token_type\": \"bearer\"} -- a token that\nauthenticates nobody, handed out to anyone, and the single worst thing\nfor a reviewer to find on a server submitted as unauthenticated. A\ncaller that was passing a real key is unaffected.","operationId":"oauth_token_oauth_token_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/.well-known/mcp/server-card.json":{"get":{"summary":"Mcp Server Card","operationId":"mcp_server_card__well_known_mcp_server_card_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/stripe/webhook":{"post":{"summary":"Stripe Webhook","operationId":"stripe_webhook_stripe_webhook_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/palette/archive/shelf":{"get":{"summary":"Palette Archive Shelf","description":"Archive-led mode: documented colours to start a palette from.\n\nWithout q: a fixed curated window -- 'featured' or one period -- free, no\nkey needed, no paging. With q: a keyed lookup (>=3 characters, names only,\noptionally narrowed by period), top ARCHIVE_SEARCH_RESULTS, 1 archive unit,\nARCHIVE_SEARCH_DAILY_CAP per key per day, and no story or source text.\nThe full record comes back only on generate with seed_record {id}.","operationId":"palette_archive_shelf_palette_archive_shelf_get","parameters":[{"name":"period","in":"query","required":false,"schema":{"type":"string","default":"","title":"Period"}},{"name":"q","in":"query","required":false,"schema":{"type":"string","default":"","title":"Q"}},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/palette/books":{"get":{"summary":"Palette Books","description":"The colour-book catalogue: a few featured palettes per book, each capped\nto COLOUR_BOOKS_FEATURED_COLOURS colours. No key, no units, no parameters --\nthe featured set is fixed, so it cannot be paged into a walk of a book.","operationId":"palette_books_palette_books_get","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/palette/books/{book_id}":{"get":{"summary":"Palette Book","description":"All palettes of one book, 12 per page: keyed, 1 archive unit per page.","operationId":"palette_book_palette_books__book_id__get","parameters":[{"name":"book_id","in":"path","required":true,"schema":{"type":"string","title":"Book Id"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Offset"}},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/palette/recipe/generate":{"post":{"summary":"Palette Recipe Generate","description":"One seed colour -> a reproducible five-role colour system\n(field, ground, support, signal, accent) with Base/Light/Dark modes.\n\nThe seed hex (and any locked hex) is returned byte-identical in its role;\nnothing is snapped to the archive. Every response carries its recipe,\nrecipe_hash and the exact algorithm_version. The same recipe and\nalgorithm_version always produce the same colours; development builds get a\nnew version id for any quality change, and retired ids return 410.\n\nOmit seed_role to use the engine's recommended role (returned in\nrole_selection with its reason).","operationId":"palette_recipe_generate_palette_recipe_generate_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaletteRecipeRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/palette/recipe/match":{"post":{"summary":"Palette Recipe Match","description":"Nearest eligible archive record for each swatch of a palette, with state and label.\n\nFree and keyless. At most one record per swatch, none beyond CIEDE2000 5,\nnever a record the publication gate or the matcher policy withholds.","operationId":"palette_recipe_match_palette_recipe_match_post","requestBody":{"content":{"application/json":{"schema":{"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/palette/method/chevreul":{"post":{"summary":"Palette Method Chevreul","description":"Your own colour, located in Chevreul's notation, with his documented\nrelationships, his 1839 contrast rules quoted verbatim, and the six\nharmonies of §180 built around it.\n\nThree kinds of claim are kept apart in the response: MECHANICAL navigation\ninside the notation (complement, neighbours, gamme, the harmony steps),\nTRANSCRIBED rules quoted with their locators, and the two INTERPRETED\nsteps — locating an arbitrary colour, and putting a number on an apparent\nshift — each of which carries its interpretation sentence in the payload.\n\n`your_colours` and `chevreuls_own` are never merged: the first is your\ncolour moved, the second is a reference rendering of an uncalibrated scan.","operationId":"palette_method_chevreul_palette_method_chevreul_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChevreulMethodRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/palette/method/vanderpoel":{"post":{"summary":"Palette Method Vanderpoel","description":"Your own colour, arranged by Vanderpoel's proportions: pick one of her\ncolour-analysis plates (or omit plate_id to have plates suggested), and\nyour colour takes the place of the plate's leading colour while every other\nrole is rebuilt around it -- hue family, lightness and chroma relationships\nmeasured from her printed colours, moved in CIELAB -- in her printed\npercentages.\n\nMECHANICAL, quoted exactly: the printed names, the printed percentages\n(Plate LVIII's add up to 99 and are shown as 99), the 10 x 10 grid, the\ncaption. INTERPRETED, each block carrying its sentence: the name reading,\nthe role your colour takes, the measured family angles, your palette, the\nsuggestions. Every plate behaves the same; the eleven funerary-context\nplates (LII-LXI, LXX) carry a descriptive note wherever they appear.\n\nmode \"keep_names\" (default) keeps her printed hue family for every role\nbut the one your colour takes; \"transpose\" turns the whole plate to your\nhue, and says her colour names no longer apply.","operationId":"palette_method_vanderpoel_palette_method_vanderpoel_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VanderpoelMethodRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/palette/gradient":{"post":{"summary":"Palette Gradient Endpoint","description":"Lab/LCh interpolated gradient between archive anchor colours.","operationId":"palette_gradient_endpoint_palette_gradient_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaletteGradientRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/palette/generate":{"post":{"summary":"Palette Generate","operationId":"palette_generate_palette_generate_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaletteGenerateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/palette/translate":{"post":{"summary":"Palette Translate","operationId":"palette_translate_palette_translate_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaletteTranslateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/cliche_breaker":{"post":{"summary":"Cliche Breaker","description":"Find the most surprising archive colour for a concept and generate\na memorable one-liner subverting the obvious expectation.\nExample: concept='love', expected_colour='red' → returns Shakespeare's green.","operationId":"cliche_breaker_cliche_breaker_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClicheBreakerRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/colour/verdict":{"post":{"summary":"Colour Verdict","description":"Evaluate a hex colour for a specific use case, market, and medium.\nReturns a decisive verdict (use_with_confidence / use_with_caution / avoid),\nstrengths, risks, and better alternatives.","operationId":"colour_verdict_colour_verdict_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ColourVerdictRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/palette/verdict":{"post":{"summary":"Palette Verdict","description":"Evaluate a palette of hex values for a use case, market, and medium.\nReturns a verdict, score 0-100, role for each colour, the single biggest\nweakness, and a concrete suggestion for what to add.","operationId":"palette_verdict_palette_verdict_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaletteVerdictRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/agent/brief":{"post":{"summary":"Agent Brief","description":"Generate a complete colour direction package for another AI agent.\nFetches a historically grounded palette from the concept, then produces\nan agent brief, colour tokens with roles, a model-specific image generation\nprompt, and a negative prompt. Supports midjourney, flux, dalle, stable_diffusion.","operationId":"agent_brief_agent_brief_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentBriefRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/capabilities":{"get":{"summary":"Get Capabilities","description":"Live inventory of all active endpoints and MCP tools.\nUse this to discover what the API can do before making calls.\n\nFix 4 step 3 (Session 2B-i): mcp_tool_count/mcp_tool_names now come\nfrom current_public_tools() -- the same canonical-registry-driven,\nrollback-flag-aware source /health, tools/list, and system_status all\nuse -- rather than the raw _MCP_TOOLS list, which included internal-\nonly tools never actually reachable via tools/list. That mismatch\n(this endpoint silently claiming a different tool count than /health)\nwas itself a real instance of the \"drift between MCP, REST, and\ndocumentation\" this session's brief opens with.\n\nFix 6: schema_hash is served as this response's ETag. A client\nsending If-None-Match with a still-current hash gets a bare 304, not\na re-fetched body -- and critically, a CHANGED schema can never keep\nserving an old body under an old ETag, since the ETag IS the content\nhash, not an independently-tracked version counter that could drift\nfrom what's actually being returned.","operationId":"get_capabilities_capabilities_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/brand/audit":{"post":{"summary":"Brand Audit","description":"Complete brand colour intelligence audit in one call.\nRuns accessibility matrix, cultural risk, palette verdict, and design token\nexport internally and assembles into a single structured response.\nNo LLM cost -- all computed data.","operationId":"brand_audit_brand_audit_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandAuditRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/brand/asset-pack":{"post":{"summary":"Brand Asset Pack","description":"Complete brand asset pack export.\nReturns CSS variables, Tailwind config, Figma tokens JSON,\ncitation cards, and a Markdown brand guide.\nDeterministic. No LLM cost.","operationId":"brand_asset_pack_brand_asset_pack_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandAuditRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/brand/system":{"post":{"summary":"Brand System","description":"Complete brand colour system in one call.\nExtends brand_audit with light/dark mode role maps,\ntypography guidance, per-colour usage rules, and citation cards.\nDeterministic. No LLM cost.","operationId":"brand_system_brand_system_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandAuditRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/archives/audit":{"get":{"summary":"Archive Audit","description":"Run a data quality audit on a named archive.\nReturns entry count, issue counts, affected colour names, health score 0-100,\nand a prioritised fix list. No Claude call — pure archive analysis.","operationId":"archive_audit_archives_audit_get","parameters":[{"name":"archive","in":"query","required":true,"schema":{"type":"string","title":"Archive"}},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/memory_hooks":{"post":{"summary":"Memory Hooks","description":"Make any hex colour memorable. Returns a hook sentence, three-sentence story,\ntweet, image prompt, and follow-up questions — tuned to audience and tone.\nBacked by the nearest archive colour's cultural provenance.","operationId":"memory_hooks_memory_hooks_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemoryHooksRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/archive/provenance":{"post":{"summary":"Provenance Explain","description":"Explain the provenance of a named archive colour with explicit separation of:\ndocumented historical fact, computational hex derivation, and cultural interpretation.\nThis is the trust endpoint — it answers 'how do you know this?'","operationId":"provenance_explain_archive_provenance_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvenanceRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/colour/forensics":{"post":{"summary":"Colour Forensics","description":"Assess whether a hex colour can be safely specified for a physical application.\nInputs: substrate, finish, orientation, use.\nReturns: specification safety verdict, risks, required actions,\nlight behaviour under three illuminants, and substrate-specific notes.","operationId":"colour_forensics_colour_forensics_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ColourForensicsRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/colour/strategy":{"post":{"summary":"Colour Strategy","description":"Single-call commercial colour strategy report. Combines archive grounding, verdict,\nbrand fit, market risk, category cliche check, material behaviour,\ncopy hooks, and usage rules.","operationId":"colour_strategy_colour_strategy_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ColourStrategyRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/colour/dna":{"post":{"summary":"Colour Dna","description":"Compact semantic fingerprint for any hex colour.\nReturns depth, temperature, chroma, material register,\nemotional register, commercial signal, risks, and best uses.\nNo Claude call -- pure archive and physics data. Fast and cacheable.","operationId":"colour_dna_colour_dna_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ColourDNARequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/ecommerce/product-copy":{"post":{"summary":"Ecommerce Product Copy","description":"Generate complete ecommerce product copy for a colour.\nInput: hex + product type + tone + channel.\nOutput: colour name, product title, short description,\nlong description, SEO title, meta description, alt text,\nInstagram caption, and cross-sell colour suggestions.\nBacked by archive provenance -- never generic AI colour copy.","operationId":"ecommerce_product_copy_ecommerce_product_copy_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EcommerceProductCopyRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/archive/report-brief":{"post":{"summary":"Archive Report Brief","description":"One-call complete archive research package for a document, PDF, or editorial brief.\n\nYou give it: a title, audience, themes, archives to draw from, things to avoid,\nand how many colours you want.\n\nIt returns: ranked colour cards with archive provenance, story order, source\nconfidence, pull quote, CTA line, CSS tokens, image prompt, and a one-paragraph\neditorial argument -- everything needed to brief a designer, write a document,\nor instruct an image model.\n\nThis is the endpoint that replaces chaining archive_search + get_colour_card\n+ cliche_breaker + agent_brief separately. Two Claude calls total.","operationId":"archive_report_brief_archive_report_brief_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArchiveReportBriefRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/palette/collection":{"post":{"summary":"Palette Collection","description":"Generate a collection of independent themed palettes in one call --\nn_palettes x colours_per_palette, each theme its own palette. Retrieval\nand validation are fully deterministic; the LLM only writes palette\nnames for palettes that already passed every QA assertion in Step 4.","operationId":"palette_collection_palette_collection_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaletteCollectionRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/palette/heritage-evolution":{"post":{"summary":"Heritage Evolution Palette","description":"Given a legacy palette, generate an archive-grounded premium support system.","operationId":"heritage_evolution_palette_palette_heritage_evolution_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeritageEvolutionRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/product/colour-names":{"post":{"summary":"Product Line Colour Namer","description":"Generate archive-grounded colour names for up to 40 product SKUs.\n\nFor each hex value: finds the nearest archive colour, returns the archive name\nas a candidate product name, plus the source and a one-line description.\nDesigned for paint ranges, candle collections, fashion lines, and homeware.\n\nEvery name is archive-sourced -- not invented. Each carries a primary source\ncitation so the name can be defended to buyers, press, and brand teams.","operationId":"product_line_colour_namer_product_colour_names_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductLineNamerRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/palette/ui-states":{"post":{"summary":"Ui State Palette","description":"Generate a complete UI state palette from a brand hex.\n\nReturns WCAG-compliant colours for: success, warning, error, info,\nhover, active, disabled, focus ring, and surface variants.\nAll states are computed to maintain sufficient contrast against the\nsupplied background. Each state includes hex, WCAG grade, and\na one-line usage note.","operationId":"ui_state_palette_palette_ui_states_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UIStatePaletteRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/archive/resonance-index":{"post":{"summary":"Archive Resonance Index","description":"Diagnostic keyword-pattern estimate of how strongly a colour's documented\nnotes connect a material property to an institutional or social context.\n\nThis is a heuristic, disclosed estimate -- see \"method\" in the response --\nnot a verified causal-chain analysis, and not a decision recommendation on\nits own. Only two score_basis values are currently supported. Candidates\nare resolved against canonical archive records by name+archive where\npossible; a mismatched archive hint is reported rather than silently\nresolved elsewhere. Only archive-verified candidates are eligible to be\nnamed a ranking winner.","operationId":"archive_resonance_index_archive_resonance_index_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResonanceIndexRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/archive/evidence-gap":{"post":{"summary":"Archive Evidence Gap","description":"Given a hex value and a proposed claim about it, return whether the archive supports\nthat claim, what is missing, what kind of source would be needed, and safe wording.\n\nThis is Colour Memory's anti-hallucination endpoint. It turns the absence of evidence\ninto a forensic finding rather than a gap to be filled with invention.\n\nA claim can only be \"supported\" or \"partial\" if a candidate is both a genuinely\nclose colour match (low dE2000) AND has real word-level overlap with the claim,\nusing whole-word matching against a stopword-filtered set. A nearby-but-different\ncolour that merely shares a generic word can never produce false confidence.\n\nExample: hex #4A535C + proposed_claim 'cyanosis in a death chamber'\nReturns: nearest archive support, whether the claim is supported, what is missing,\n         what source type would be needed, and safe agent wording.","operationId":"archive_evidence_gap_archive_evidence_gap_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EvidenceGapRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/archive/coverage-gap":{"post":{"summary":"Archive Coverage Gap","description":"Given a list of themes, report which are well-evidenced in the archive\nand which are under-evidenced or missing.\n\nReturns a coverage matrix: for each theme, the number of matching entries,\nthe strongest entry, the claim_strength of the best match, and what kind\nof source would be needed to improve coverage.\n\nUse this before building an archive_report_brief to know where the\nevidence is strong and where the agent will have to flag gaps.","operationId":"archive_coverage_gap_archive_coverage_gap_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoverageGapRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/archive/anachronism-guard":{"post":{"summary":"Archive Anachronism Guard","description":"Check a list of colour entries for anachronism risk.\n\nFor each entry: detects whether the primary source date falls outside\nthe requested period, whether the archive is a known modern source,\nand returns a period_relevance score and safe phrasing.\n\nEssential for historical documents where a modern racing silk registration\nor a 2011 Jockey Club entry must not be presented as Georgian evidence.","operationId":"archive_anachronism_guard_archive_anachronism_guard_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnachronismGuardRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/session/brief":{"post":{"summary":"Brief Forensic","description":"Single-call forensic colour brief generator. Covers:\ncoverage gap analysis, colour cards with full provenance, anachronism\nchecks, resonance scores, claim roles, do_not_say constraints,\neditorial argument, act structure, pull quote, image prompt,\nand a replacement log showing what was excluded and why.\n\nThis is what a designer, historian, creative director, or brand\nstrategist pays for. It replaces chaining coverage_gap + archive_report_brief\n+ anachronism_guard + resonance_index + evidence_gap separately.\n\nInput: title, audience, themes, archives, period, tone, confidence threshold.\nOutput: complete deliverable package ready for PDF or editorial use.","operationId":"brief_forensic_session_brief_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForensicBriefRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/brand/collision-check":{"post":{"summary":"Brand Collision Check","description":"Can this brand own this colour against these competitors in this market?\n\nComputes CIEDE2000 distances between the brand colour and each competitor,\nretrieves archive context for each, scores distinctiveness, and returns\na plain-English ownership verdict with strategic recommendation.","operationId":"brand_collision_check_brand_collision_check_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandCollisionRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/brand/report":{"post":{"summary":"Brand Report","description":"Complete one-call brand colour intelligence report.\nRuns archive anchor, cliche break, colour DNA, strategy,\npalette verdict, ecommerce copy, memory hooks, and agent\nbrief entirely internally — no chained httpx calls.","operationId":"brand_report_brand_report_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandReportRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/colour/{name}/relationships":{"get":{"summary":"Colour Relationships Endpoint","operationId":"colour_relationships_endpoint_colour__name__relationships_get","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}},{"name":"archive","in":"query","required":false,"schema":{"type":"string","title":"Archive"}},{"name":"relationship","in":"query","required":false,"schema":{"type":"string","title":"Relationship"}},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/search/concept/{concept}":{"get":{"summary":"Search By Concept","operationId":"search_by_concept_search_concept__concept__get","parameters":[{"name":"concept","in":"path","required":true,"schema":{"type":"string","title":"Concept"}},{"name":"archive","in":"query","required":false,"schema":{"type":"string","title":"Archive"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":20,"title":"Limit"}},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/colour/{name}/provenance":{"get":{"summary":"Colour Provenance Endpoint","operationId":"colour_provenance_endpoint_colour__name__provenance_get","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}},{"name":"archive","in":"query","required":false,"schema":{"type":"string","title":"Archive"}},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/search/publication-ready":{"get":{"summary":"Publication Ready Colours","description":"Return colours with citation score >= min_score.\nUse min_score=2 for documented, min_score=3 for verified.\nThese are publication-ready entries safe for export.","operationId":"publication_ready_colours_search_publication_ready_get","parameters":[{"name":"archive","in":"query","required":false,"schema":{"type":"string","title":"Archive"}},{"name":"min_score","in":"query","required":false,"schema":{"type":"integer","default":2,"title":"Min Score"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":20,"title":"Limit"}},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/colour/{name}/citation":{"get":{"summary":"Colour Citation","description":"Return citation completeness score for a named colour.","operationId":"colour_citation_colour__name__citation_get","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}},{"name":"archive","in":"query","required":false,"schema":{"type":"string","title":"Archive"}},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/search/family/{family}":{"get":{"summary":"Search By Family","description":"Search colours by perceptual family across all archives.\nFamilies: red, orange, yellow, yellow-green, green, teal, blue,\n          blue-violet, violet, magenta, white, light-grey, mid-grey,\n          dark-grey, black\nExample: GET /search/family/blue?archive=Victorian&limit=10","operationId":"search_by_family_search_family__family__get","parameters":[{"name":"family","in":"path","required":true,"schema":{"type":"string","title":"Family"}},{"name":"archive","in":"query","required":false,"schema":{"type":"string","title":"Archive"}},{"name":"subfamily","in":"query","required":false,"schema":{"type":"string","title":"Subfamily"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":20,"title":"Limit"}},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/archive/family-distribution":{"get":{"summary":"Family Distribution","description":"Return count of colours per family across the archive.\nUseful for understanding archive coverage and gaps.","operationId":"family_distribution_archive_family_distribution_get","parameters":[{"name":"archive","in":"query","required":false,"schema":{"type":"string","title":"Archive"}},{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/mailing-list":{"post":{"summary":"Mailing List Signup","description":"Add email to Colour Memory mailing list via Resend. No API key required.","operationId":"mailing_list_signup_mailing_list_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/trial/register":{"post":{"summary":"Trial Register","operationId":"trial_register_trial_register_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/trial/verify":{"get":{"summary":"Trial Verify","description":"The other half of the /trial/register security fix. A repeat\nsignup request for an email that already has a key no longer\nreturns that key -- it emails a one-time link here instead. This\nendpoint is what actually reveals the key, and only once: the\ntoken is single-use and expires in 30 minutes (both enforced in\nconsume_verification_token, in SQL, not here).\n\nAn unrecognised token and an expired token deliberately produce the\nidentical response -- never confirm which case it was.","operationId":"trial_verify_trial_verify_get","parameters":[{"name":"token","in":"query","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/palette/swatch.png":{"get":{"tags":["Palette"],"summary":"Colour palette swatch PNG","operationId":"palette_swatch_png_palette_swatch_png_get","parameters":[{"name":"hexes","in":"query","required":true,"schema":{"type":"string","description":"Comma-separated hex values e.g. #d4a829,#1a5c6e,#0a0a0b","title":"Hexes"},"description":"Comma-separated hex values e.g. #d4a829,#1a5c6e,#0a0a0b"},{"name":"weights","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated proportional weights from k-means extraction. Used only when layout=photo.","title":"Weights"},"description":"Comma-separated proportional weights from k-means extraction. Used only when layout=photo."},{"name":"layout","in":"query","required":false,"schema":{"type":"string","description":"photo | equal | grid | gradient | filmstrip | 6310 | 7020 | 5030 | 8010 | 5050 | 6040 | triptych | quad | 55-25-20 | quint | 70-10-20 | 40-30-20-10 | 33-33-24-10","default":"photo","title":"Layout"},"description":"photo | equal | grid | gradient | filmstrip | 6310 | 7020 | 5030 | 8010 | 5050 | 6040 | triptych | quad | 55-25-20 | quint | 70-10-20 | 40-30-20-10 | 33-33-24-10"},{"name":"w","in":"query","required":false,"schema":{"type":"integer","maximum":4000,"minimum":100,"default":1200,"title":"W"}},{"name":"h","in":"query","required":false,"schema":{"type":"integer","maximum":4000,"minimum":100,"default":630,"title":"H"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}},"image/png":{}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/palette/analyse":{"post":{"summary":"Palette Analyse","description":"Match a palette of hex colours against the archive in a single call.\n\nFor each colour returns the nearest named archive entry with:\n  name, archive, hex, dE2000, confidence, confidence_score,\n  claim_strength (A-E), primary_source, do_not_say guardrails,\n  and an alternatives array when confidence is low.\n\nPalette-level deduplication: no two colours share the same archive entry.\nDominant colours (weight >= 0.3) get a wider internal candidate search.\nCombined scoring: dE2000 penalised by record quality so weak sources\nlose to good sources at similar perceptual distance.","operationId":"palette_analyse_palette_analyse_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaletteAnalyseRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/image/ingest":{"post":{"summary":"Image Ingest Endpoint","description":"Ingest image via multipart or source_url. Returns image_id valid 5 min.","operationId":"image_ingest_endpoint_image_ingest_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_image_ingest_endpoint_image_ingest_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/palette/extract":{"post":{"summary":"Palette Extract","description":"Extract dominant colours from an image using the same k-means++ algorithm\nas the Colour Memory app. Accepts a public image URL or base64-encoded image.\nReturns hex values with proportional weights sorted by luminance.\nOptionally applies grey card white balance correction before extraction.\nOptionally runs palette/analyse on the results if analyse=True.","operationId":"palette_extract_palette_extract_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaletteExtractRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/palette/lut":{"post":{"summary":"Palette Lut","description":"Generate a 33x33x33 .cube LUT file from a palette of hex colours.\nThe LUT maps the neutral colour space toward the supplied palette\nusing inverse-distance weighting in RGB space.\nCompatible with Adobe Premiere, DaVinci Resolve, and Final Cut Pro X.\nStrength controls blend: 1.0 = full palette influence, 0.5 = half.","operationId":"palette_lut_palette_lut_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaletteLutRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"summary":"Palette Lut","description":"Generate a 33x33x33 .cube LUT file from a palette of hex colours.\nThe LUT maps the neutral colour space toward the supplied palette\nusing inverse-distance weighting in RGB space.\nCompatible with Adobe Premiere, DaVinci Resolve, and Final Cut Pro X.\nStrength controls blend: 1.0 = full palette influence, 0.5 = half.","operationId":"palette_lut_palette_lut_get","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaletteLutRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/image/brief":{"post":{"summary":"Image Brief","operationId":"image_brief_image_brief_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageBriefRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/visual/house-specify":{"post":{"summary":"Visual House Specify","description":"house_specify, plus the rendered visual result and its download links.\n\nThe prose answer is unchanged and still comes from the model; this adds the\ncolour the payload always contained but never showed.","operationId":"visual_house_specify_visual_house_specify_post","parameters":[{"name":"x-api-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}},{"name":"origin","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HouseSpecifyRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/visual/export/{result_id}/{fmt}":{"get":{"summary":"Visual Export","description":"Download one export of a displayed result.\n\n`result_id` is matched against a strict pattern and then used only as a\ndict key; `fmt` is matched against a fixed allowlist. Neither ever becomes\na path, so no user input can address a server-side file.","operationId":"visual_export_visual_export__result_id___fmt__get","parameters":[{"name":"result_id","in":"path","required":true,"schema":{"type":"string","title":"Result Id"}},{"name":"fmt","in":"path","required":true,"schema":{"type":"string","title":"Fmt"}},{"name":"t","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"T"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/image/upload":{"post":{"summary":"Image Upload","description":"Binary in, opaque reference out. No image bytes in JSON.","operationId":"image_upload_image_upload_post","parameters":[{"name":"session_id","in":"query","required":false,"schema":{"type":"string","default":"","title":"Session Id"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_image_upload_image_upload_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/chat/session":{"post":{"summary":"Chat Session","description":"Issue a browser session. No secret ever reaches the page.","operationId":"chat_session_chat_session_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/chat":{"post":{"summary":"Chat","description":"One turn, one JSON body. Unchanged for callers that want that.","operationId":"chat_chat_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/chat/stream":{"post":{"summary":"Chat Stream","description":"One turn as a sequence of events, so the colour arrives first.\n\nThe blocking /chat runs tool, then a second model round for\ncommentary, then returns everything together -- so the customer waits\nthe full turn to see a palette that existed a third of the way in.\n\nThis yields the visual the moment the tool returns and streams the\ncommentary after it. Same tools, same metering, same entitlement\ncheck, same result object; only the delivery changed. /chat is\nuntouched for anything that wants one JSON body.","operationId":"chat_stream_chat_stream_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/chat/keep":{"post":{"summary":"Keep Current","description":"Keep the earlier result after a side-by-side comparison.\n\nTrying something must not cost the thing you already liked -- and until\nthis existed that promise was only kept in the browser. The page swapped\nthe DOM back; the server had already moved on, so Share froze the\nrejected palette and the next turn refined it.\n\nOne step of history, which is all the comparison offers.","operationId":"keep_current_chat_keep_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShareRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/share":{"post":{"summary":"Share Result","description":"Freeze the session's most recent result and mint a link for it.\n\nPRIVATE BY DEFAULT: nothing is published by asking a question. This is\nthe only way a result becomes reachable, and it needs the session that\nproduced it -- a result is not shareable by anyone who merely knows it\nexists.","operationId":"share_result_share_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShareRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/share/{share_id}/revoke":{"post":{"summary":"Revoke Share","description":"Pull a link: the owning session, or the token issued when it was made.\n\nThe session is not required when a token is presented -- sessions last\ntwo hours and the link lasts ninety days, so demanding one would mean\na link can only be withdrawn on the day it was created.","operationId":"revoke_share_share__share_id__revoke_post","parameters":[{"name":"share_id","in":"path","required":true,"schema":{"type":"string","title":"Share Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShareRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/r/{share_id}":{"get":{"summary":"Shared Result","description":"The shared page. No account, no session, no login to view.","operationId":"shared_result_r__share_id__get","parameters":[{"name":"share_id","in":"path","required":true,"schema":{"type":"string","title":"Share Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/r/{share_id}/download/{fmt}":{"get":{"summary":"Shared Download","description":"One export of a shared result. No account, no session, no token.\n\nRebuilt from the ColourResult frozen INTO the share, so it keeps\nworking for exactly as long as the link does.","operationId":"shared_download_r__share_id__download__fmt__get","parameters":[{"name":"share_id","in":"path","required":true,"schema":{"type":"string","title":"Share Id"}},{"name":"fmt","in":"path","required":true,"schema":{"type":"string","title":"Fmt"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/try":{"get":{"summary":"Try Colour Memory","description":"The customer experience, at a name a person can say.","operationId":"try_colour_memory_try_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"AccessibilityMatrixRequest":{"properties":{"palette":{"items":{"type":"string"},"type":"array","title":"Palette"}},"type":"object","required":["palette"],"title":"AccessibilityMatrixRequest"},"AccessibilityUsageRulesRequest":{"properties":{"palette":{"items":{"type":"string"},"type":"array","title":"Palette"}},"type":"object","required":["palette"],"title":"AccessibilityUsageRulesRequest"},"AgentBriefRequest":{"properties":{"task":{"type":"string","title":"Task"},"concept":{"type":"string","title":"Concept"},"palette_size":{"type":"integer","title":"Palette Size","default":5},"model":{"type":"string","title":"Model","default":"midjourney"},"style_notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Style Notes"},"locked_palette":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}],"title":"Locked Palette"},"archive":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Archive"},"allowed_archives":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}],"title":"Allowed Archives"},"avoid":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}],"title":"Avoid"},"minimum_claim_strength":{"type":"string","enum":["A","B","C","D","E"],"title":"Minimum Claim Strength","default":"C"}},"type":"object","required":["task","concept"],"title":"AgentBriefRequest"},"AgentVerifyRequest":{"properties":{"target_palette":{"items":{"type":"string"},"type":"array","title":"Target Palette"},"image_url":{"type":"string","title":"Image Url","default":""},"image_base64":{"type":"string","title":"Image Base64","default":""},"image":{"type":"string","title":"Image","default":""}},"type":"object","required":["target_palette"],"title":"AgentVerifyRequest"},"AnachronismGuardRequest":{"properties":{"entries":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Entries"},"target_period":{"type":"string","title":"Target Period","default":""},"period_start":{"type":"integer","title":"Period Start","default":0},"period_end":{"type":"integer","title":"Period End","default":9999}},"type":"object","required":["entries"],"title":"AnachronismGuardRequest"},"AnalyseImageRequest":{"properties":{"image_base64":{"type":"string","title":"Image Base64"},"k":{"type":"integer","title":"K","default":6},"exclude_neutrals":{"type":"boolean","title":"Exclude Neutrals","default":false},"min_area_pct":{"type":"number","title":"Min Area Pct","default":1.0}},"type":"object","required":["image_base64"],"title":"AnalyseImageRequest"},"ArchiveReportBriefRequest":{"properties":{"title":{"type":"string","title":"Title","default":""},"audience":{"type":"string","title":"Audience","default":""},"themes":{"items":{"type":"string"},"type":"array","title":"Themes","default":[]},"archives":{"items":{"type":"string"},"type":"array","title":"Archives","default":[]},"avoid":{"items":{"type":"string"},"type":"array","title":"Avoid","default":[]},"n_colours":{"type":"integer","title":"N Colours","default":8},"strict_sources":{"type":"boolean","title":"Strict Sources","default":true},"confidence_threshold":{"type":"number","title":"Confidence Threshold","default":0.5},"minimum_claim_strength":{"type":"string","title":"Minimum Claim Strength","default":""},"output_format":{"type":"string","title":"Output Format","default":"full"},"period_start":{"type":"integer","title":"Period Start","default":0},"period_end":{"type":"integer","title":"Period End","default":9999},"allow_partial":{"type":"boolean","title":"Allow Partial","default":false},"family_card_mode":{"type":"string","title":"Family Card Mode","default":"auto"},"max_family_card_share":{"type":"number","title":"Max Family Card Share","default":0.5},"strict_semantic_colour":{"type":"boolean","title":"Strict Semantic Colour","default":false}},"type":"object","title":"ArchiveReportBriefRequest"},"ArchiveSearchRequest":{"properties":{"query":{"type":"string","title":"Query"},"archive":{"type":"string","title":"Archive","default":""},"entity_mode":{"type":"string","title":"Entity Mode","default":"text"},"n_results":{"type":"integer","title":"N Results","default":10},"limit":{"type":"integer","title":"Limit","default":0},"offset":{"type":"integer","title":"Offset","default":0},"include_full":{"type":"boolean","title":"Include Full","default":true},"year_from":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Year From"},"year_to":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Year To"}},"type":"object","required":["query"],"title":"ArchiveSearchRequest"},"BatchPassportRequest":{"properties":{"hexes":{"items":{},"type":"array","title":"Hexes"},"include_physics":{"type":"boolean","title":"Include Physics","default":true},"include_cultural":{"type":"boolean","title":"Include Cultural","default":false},"n_archive":{"type":"integer","title":"N Archive","default":3}},"type":"object","required":["hexes"],"title":"BatchPassportRequest"},"Body_image_ingest_endpoint_image_ingest_post":{"properties":{"file":{"anyOf":[{"type":"string","format":"binary"},{"type":"null"}],"title":"File"}},"type":"object","title":"Body_image_ingest_endpoint_image_ingest_post"},"Body_image_upload_image_upload_post":{"properties":{"file":{"type":"string","format":"binary","title":"File"}},"type":"object","required":["file"],"title":"Body_image_upload_image_upload_post"},"Body_match_image_match_post":{"properties":{"file":{"type":"string","format":"binary","title":"File"},"n":{"type":"integer","title":"N","default":5},"archive":{"type":"string","title":"Archive","default":""}},"type":"object","required":["file"],"title":"Body_match_image_match_post"},"Body_palette_card_palette_card_post":{"properties":{"file":{"type":"string","format":"binary","title":"File"},"archive":{"type":"string","title":"Archive","default":""}},"type":"object","required":["file"],"title":"Body_palette_card_palette_card_post"},"BrandAuditRequest":{"properties":{"palette":{"items":{"type":"string"},"type":"array","title":"Palette"},"site_evidence":{"additionalProperties":true,"type":"object","title":"Site Evidence"},"market":{"type":"string","title":"Market","default":"global"},"use_case":{"type":"string","title":"Use Case","default":"brand identity"},"medium":{"type":"string","title":"Medium","default":"digital"},"brand_category":{"type":"string","title":"Brand Category","default":""},"logo_url":{"type":"string","title":"Logo Url","default":""},"logo_base64":{"type":"string","title":"Logo Base64","default":""},"roles":{"items":{"type":"string"},"type":"array","title":"Roles","default":[]}},"type":"object","required":["palette"],"title":"BrandAuditRequest"},"BrandBrief":{"properties":{"category":{"type":"string","title":"Category","default":""},"positioning":{"type":"string","title":"Positioning","default":""},"audience":{"type":"string","title":"Audience","default":""},"personality":{"items":{"type":"string"},"type":"array","title":"Personality"},"values":{"items":{"type":"string"},"type":"array","title":"Values"},"channels":{"items":{"type":"string"},"type":"array","title":"Channels"},"markets":{"items":{"type":"string"},"type":"array","title":"Markets"},"competitors":{"items":{"$ref":"#/components/schemas/CompetitorInput"},"type":"array","title":"Competitors"}},"type":"object","title":"BrandBrief"},"BrandCollisionRequest":{"properties":{"brand_hex":{"type":"string","title":"Brand Hex"},"brand_name":{"type":"string","title":"Brand Name","default":""},"competitor_hexes":{"items":{"type":"string"},"type":"array","title":"Competitor Hexes","default":[]},"competitor_names":{"items":{"type":"string"},"type":"array","title":"Competitor Names","default":[]},"competitor_provenance":{"items":{"type":"string"},"type":"array","title":"Competitor Provenance","default":[]},"market":{"type":"string","title":"Market","default":"global"},"region":{"type":"string","title":"Region","default":""}},"type":"object","required":["brand_hex"],"title":"BrandCollisionRequest"},"BrandConstraints":{"properties":{"avoid_concepts":{"items":{"type":"string"},"type":"array","title":"Avoid Concepts"},"preferred_families":{"items":{"type":"string"},"type":"array","title":"Preferred Families"}},"type":"object","title":"BrandConstraints","description":"Bug 2 fix (2026-08-06): confirmed live, the MCP schema had no field\nfor structured negative constraints at all -- a brief that says \"not\na generic pink pet salon\" in prose had no way to make that a real,\ntestable exclusion; the closest the system could do was infer\nsentiment from prose (fixed separately, see _RELEVANCE_NEGATION_CUES),\nwhich is inherently weaker than a structured field a caller can rely\non. avoid_concepts are checked as case-insensitive substring matches\nagainst each retrieved archive entry's own name/colour_notes/\narchive_source text during concept-mode retrieval (resolve_palette_\ncolours) -- structured constraints, not inferred sentiment, and they\ntake precedence: an avoid_concepts match is excluded outright,\nregardless of what the brief's prose might otherwise suggest.\npreferred_families is a soft ranking boost, not a hard filter --\nmatching entries are preferred, not the only ones allowed."},"BrandGuidelineClaimsRequest":{"properties":{"brand_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Brand Ref"},"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id"},"project_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Project Version"},"claim_ids":{"items":{"type":"string"},"type":"array","title":"Claim Ids"}},"type":"object","title":"BrandGuidelineClaimsRequest"},"BrandGuidelinePDFRequest":{"properties":{"brand_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Brand Ref"},"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id"},"project_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Project Version"},"delivery":{"type":"string","title":"Delivery","default":"url"}},"type":"object","title":"BrandGuidelinePDFRequest"},"BrandGuidelineSelectRequest":{"properties":{"brand_ref":{"type":"string","title":"Brand Ref","default":""},"project_id":{"type":"string","title":"Project Id","default":""},"selected_candidate_id":{"type":"string","title":"Selected Candidate Id"},"locked_colour_ids":{"items":{"type":"string"},"type":"array","title":"Locked Colour Ids"},"suppressed_claim_ids":{"items":{"type":"string"},"type":"array","title":"Suppressed Claim Ids"},"note":{"type":"string","title":"Note","default":""}},"type":"object","required":["selected_candidate_id"],"title":"BrandGuidelineSelectRequest"},"BrandGuidelineSpecifyRequest":{"properties":{"brand_name":{"type":"string","title":"Brand Name"},"continue_project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Continue Project Id"},"brand_brief":{"$ref":"#/components/schemas/BrandBrief"},"palette_input":{"$ref":"#/components/schemas/PaletteInput"},"preferences":{"$ref":"#/components/schemas/Preferences"},"identity_assets":{"$ref":"#/components/schemas/IdentityAssets"},"output_preferences":{"$ref":"#/components/schemas/OutputPreferences"},"constraints":{"$ref":"#/components/schemas/BrandConstraints"}},"type":"object","required":["brand_name","palette_input"],"title":"BrandGuidelineSpecifyRequest"},"BrandReportRequest":{"properties":{"hex":{"type":"string","title":"Hex"},"brand_context":{"additionalProperties":true,"type":"object","title":"Brand Context","default":{}},"markets":{"items":{},"type":"array","title":"Markets","default":[]},"medium":{"type":"string","title":"Medium","default":"general"},"concept":{"type":"string","title":"Concept","default":""},"product_type":{"type":"string","title":"Product Type","default":""},"target_model":{"type":"string","title":"Target Model","default":"midjourney"}},"type":"object","required":["hex"],"title":"BrandReportRequest"},"ChatRequest":{"properties":{"session_id":{"type":"string","title":"Session Id"},"message":{"type":"string","title":"Message"},"history":{"items":{},"type":"array","title":"History","default":[]},"image_ref":{"type":"string","title":"Image Ref","default":""}},"type":"object","required":["session_id","message"],"title":"ChatRequest"},"ChevreulMethodRequest":{"properties":{"hex":{"type":"string","title":"Hex"},"neighbour_hex":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Neighbour Hex"},"harmony":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Harmony"},"count":{"type":"integer","title":"Count","default":5}},"type":"object","required":["hex"],"title":"ChevreulMethodRequest"},"ClicheBreakerRequest":{"properties":{"concept":{"type":"string","title":"Concept"},"expected_colour":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expected Colour"},"n_results":{"type":"integer","title":"N Results","default":8}},"type":"object","required":["concept"],"title":"ClicheBreakerRequest"},"ColourCombinationRequest":{"properties":{"colours":{"items":{"type":"string"},"type":"array","title":"Colours"},"context":{"type":"string","title":"Context","default":"UI"}},"type":"object","required":["colours"],"title":"ColourCombinationRequest"},"ColourDNARequest":{"properties":{"hex":{"type":"string","title":"Hex"}},"type":"object","required":["hex"],"title":"ColourDNARequest"},"ColourForensicsRequest":{"properties":{"hex":{"type":"string","title":"Hex"},"substrate":{"type":"string","title":"Substrate"},"finish":{"type":"string","title":"Finish","default":"matt"},"orientation":{"type":"string","title":"Orientation","default":""},"use":{"type":"string","title":"Use","default":""}},"type":"object","required":["hex","substrate"],"title":"ColourForensicsRequest"},"ColourNameSlugsRequest":{"properties":{"hex":{"type":"string","title":"Hex"},"archive":{"type":"string","title":"Archive","default":""}},"type":"object","required":["hex"],"title":"ColourNameSlugsRequest"},"ColourPassportRequest":{"properties":{"hex":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hex"},"hexes":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}],"title":"Hexes"},"n_archive":{"type":"integer","title":"N Archive","default":5},"include_physics":{"type":"boolean","title":"Include Physics","default":true},"include_cultural":{"type":"boolean","title":"Include Cultural","default":true},"principal_archive":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Principal Archive"},"principal_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Principal Name"}},"type":"object","title":"ColourPassportRequest"},"ColourStrategyRequest":{"properties":{"hex":{"type":"string","title":"Hex"},"brand_context":{"additionalProperties":true,"type":"object","title":"Brand Context","default":{}},"constraints":{"additionalProperties":true,"type":"object","title":"Constraints","default":{}},"markets":{"items":{},"type":"array","title":"Markets","default":[]},"medium":{"type":"string","title":"Medium","default":"general"}},"type":"object","required":["hex"],"title":"ColourStrategyRequest"},"ColourTimelineRequest":{"properties":{"concept":{"type":"string","title":"Concept"},"n":{"type":"integer","title":"N","default":10}},"type":"object","required":["concept"],"title":"ColourTimelineRequest"},"ColourVerdictRequest":{"properties":{"hex":{"type":"string","title":"Hex"},"use_case":{"type":"string","title":"Use Case"},"markets":{"items":{},"type":"array","title":"Markets","default":[]},"medium":{"type":"string","title":"Medium","default":"general"},"audience":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Audience"}},"type":"object","required":["hex","use_case"],"title":"ColourVerdictRequest"},"CompareRequest":{"properties":{"hex_a":{"type":"string","title":"Hex A","default":""},"hex_b":{"type":"string","title":"Hex B","default":""},"hex":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hex"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"query":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Query"},"n_per_archive":{"type":"integer","title":"N Per Archive","default":2}},"type":"object","title":"CompareRequest"},"CompetitorInput":{"properties":{"name":{"type":"string","title":"Name","default":""},"colours":{"items":{"type":"string"},"type":"array","title":"Colours"}},"type":"object","title":"CompetitorInput"},"ConceptualQuery":{"properties":{"query":{"type":"string","title":"Query"},"full_query":{"type":"string","title":"Full Query","default":""},"n_results":{"type":"integer","title":"N Results","default":5},"archive":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Archive"},"archives":{"items":{},"type":"array","title":"Archives","default":[]},"conversation_history":{"items":{},"type":"array","title":"Conversation History","default":[]},"history":{"items":{},"type":"array","title":"History","default":[]},"used_names":{"items":{},"type":"array","title":"Used Names","default":[]},"system_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"System Prompt"},"include_narrative":{"type":"boolean","title":"Include Narrative","default":true}},"type":"object","required":["query"],"title":"ConceptualQuery"},"CoverageGapRequest":{"properties":{"themes":{"items":{"type":"string"},"type":"array","title":"Themes"},"archives":{"items":{"type":"string"},"type":"array","title":"Archives","default":[]},"period_start":{"type":"integer","title":"Period Start","default":0},"period_end":{"type":"integer","title":"Period End","default":9999}},"type":"object","required":["themes"],"title":"CoverageGapRequest"},"CulturalRiskRequest":{"properties":{"hex":{"type":"string","title":"Hex","default":""},"palette":{"items":{},"type":"array","title":"Palette","default":[]},"markets":{"items":{},"type":"array","title":"Markets","default":[]}},"type":"object","title":"CulturalRiskRequest"},"CulturalRiskV2Request":{"properties":{"hex":{"type":"string","title":"Hex","default":""},"palette":{"items":{},"type":"array","title":"Palette","default":[]},"markets":{"items":{},"type":"array","title":"Markets","default":[]},"context":{"type":"string","title":"Context","default":"general"},"colour_terms":{"additionalProperties":true,"type":"object","title":"Colour Terms","default":{}},"symbols":{"items":{},"type":"array","title":"Symbols","default":[]}},"type":"object","title":"CulturalRiskV2Request"},"DesignSessionRequest":{"properties":{"concept":{"type":"string","title":"Concept"},"medium":{"type":"string","title":"Medium","default":"general"},"n_colours":{"type":"integer","title":"N Colours","default":5},"include_accessibility":{"type":"boolean","title":"Include Accessibility","default":true},"include_paint_matches":{"type":"boolean","title":"Include Paint Matches","default":true},"include_prompt":{"type":"boolean","title":"Include Prompt","default":true},"avoid":{"items":{"type":"string"},"type":"array","title":"Avoid","default":[]}},"type":"object","required":["concept"],"title":"DesignSessionRequest"},"EcommerceProductCopyRequest":{"properties":{"hex":{"type":"string","title":"Hex"},"product_type":{"type":"string","title":"Product Type"},"tone":{"type":"string","title":"Tone","default":"premium but not pompous"},"channel":{"type":"string","title":"Channel","default":"shopify"},"brand_name":{"type":"string","title":"Brand Name","default":""}},"type":"object","required":["hex","product_type"],"title":"EcommerceProductCopyRequest"},"EvidenceGapRequest":{"properties":{"hex":{"type":"string","title":"Hex"},"proposed_claim":{"type":"string","title":"Proposed Claim"},"archive":{"type":"string","title":"Archive","default":""},"n_candidates":{"type":"integer","title":"N Candidates","default":5}},"type":"object","required":["hex","proposed_claim"],"title":"EvidenceGapRequest"},"FontColourAdvisorRequest":{"properties":{"background":{"type":"string","title":"Background"},"palette":{"items":{"type":"string"},"type":"array","title":"Palette"}},"type":"object","required":["background","palette"],"title":"FontColourAdvisorRequest"},"ForensicBriefRequest":{"properties":{"title":{"type":"string","title":"Title","default":""},"audience":{"type":"string","title":"Audience","default":""},"themes":{"items":{"type":"string"},"type":"array","title":"Themes","default":[]},"archives":{"items":{"type":"string"},"type":"array","title":"Archives","default":[]},"avoid":{"items":{"type":"string"},"type":"array","title":"Avoid","default":[]},"n_colours":{"type":"integer","title":"N Colours","default":8},"target_period":{"type":"string","title":"Target Period","default":""},"period_start":{"type":"integer","title":"Period Start","default":0},"period_end":{"type":"integer","title":"Period End","default":9999},"strict_sources":{"type":"boolean","title":"Strict Sources","default":false},"confidence_threshold":{"type":"number","title":"Confidence Threshold","default":0.3},"minimum_claim_strength":{"type":"string","title":"Minimum Claim Strength","default":""},"tone":{"type":"string","title":"Tone","default":"forensic"}},"type":"object","title":"ForensicBriefRequest"},"Gap4SeedRequest":{"properties":{"schema_sql":{"type":"string","title":"Schema Sql"}},"type":"object","required":["schema_sql"],"title":"Gap4SeedRequest"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HarmonyRequest":{"properties":{"hex":{"type":"string","title":"Hex"},"types":{"items":{"type":"string"},"type":"array","title":"Types","default":["complementary","analogous","triadic","split_complementary"]},"n_per_harmony":{"type":"integer","title":"N Per Harmony","default":1}},"type":"object","required":["hex"],"title":"HarmonyRequest"},"HeritageEvolutionRequest":{"properties":{"palette":{"items":{"type":"string"},"type":"array","title":"Palette"},"brand_name":{"type":"string","title":"Brand Name","default":""},"context":{"type":"string","title":"Context","default":""},"market":{"type":"string","title":"Market","default":"global"},"n_additions":{"type":"integer","title":"N Additions","default":3}},"type":"object","required":["palette"],"title":"HeritageEvolutionRequest"},"HexQuery":{"properties":{"hex":{"type":"string","title":"Hex"},"n_results":{"type":"integer","title":"N Results","default":5},"archive":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Archive"},"archives":{"items":{},"type":"array","title":"Archives","default":[]},"include_narrative":{"type":"boolean","title":"Include Narrative","default":true}},"type":"object","required":["hex"],"title":"HexQuery"},"HistoricalColourQuery":{"properties":{"query":{"type":"string","title":"Query"},"sources":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Sources"},"epistemologies":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Epistemologies"},"max_results":{"type":"integer","title":"Max Results","default":12},"mode":{"type":"string","title":"Mode","default":"user"},"high_confidence_only":{"type":"boolean","title":"High Confidence Only","default":false}},"type":"object","required":["query"],"title":"HistoricalColourQuery"},"HouseRoomSpec":{"properties":{"label":{"type":"string","title":"Label"},"room_type":{"type":"string","title":"Room Type","default":"living"},"orientation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Orientation","default":""},"function":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Function","default":""},"requested_character":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Requested Character","default":""},"surface_targets":{"items":{"$ref":"#/components/schemas/HouseSurfaceTarget"},"type":"array","title":"Surface Targets","default":[]},"surfaces":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Surfaces","default":[]}},"type":"object","required":["label"],"title":"HouseRoomSpec"},"HouseSpecifyRequest":{"properties":{"concept":{"type":"string","title":"Concept"},"output_format":{"type":"string","enum":["standard","scene_brief"],"title":"Output Format","default":"standard"},"archive":{"type":"string","title":"Archive"},"rooms":{"items":{"$ref":"#/components/schemas/HouseRoomSpec"},"type":"array","title":"Rooms"},"colours_per_room":{"type":"integer","title":"Colours Per Room","default":5},"shared_house_colours":{"type":"integer","title":"Shared House Colours","default":2},"minimum_claim_strength":{"type":"string","title":"Minimum Claim Strength","default":"B"},"guidance_level":{"type":"string","enum":["client","decorator"],"title":"Guidance Level","default":"client"},"avoid":{"items":{"type":"string"},"type":"array","title":"Avoid","default":[]},"narrative_mode":{"type":"string","title":"Narrative Mode","default":"evidence_only"},"strict_semantic_colour":{"type":"boolean","title":"Strict Semantic Colour","default":true},"colour_direction":{"type":"string","enum":["balanced","distinctive"],"title":"Colour Direction","description":"Experimental -- opt-in only, not part of the stable API surface. Colour direction for this scheme. balanced (default) preserves the existing evidence-led specification. distinctive pushes this scheme toward a clearer, more committed colour identity where the documented archive supports it. How far it can go depends on the surviving evidence; the response reports what was achieved.","default":"balanced"},"save":{"type":"boolean","title":"Save","default":false}},"type":"object","required":["concept","archive","rooms"],"title":"HouseSpecifyRequest"},"HouseSurfaceTarget":{"properties":{"surface_role":{"type":"string","title":"Surface Role"},"target_hex":{"type":"string","title":"Target Hex","default":""},"intent":{"type":"string","title":"Intent","default":""},"allow_contrast":{"type":"boolean","title":"Allow Contrast","default":false}},"type":"object","required":["surface_role"],"title":"HouseSurfaceTarget","description":"The colour the MODEL is aiming at for one surface in one room.\n\nA house draws its colours from one provenance-grouped pool and hands them\nout by list position -- dominant, secondary, joinery, textile, accent -- so\nnothing ever asked whether the colour landing on the walls was the colour\nthe room was described as needing. A warm sitting room kept a lilac textile\nbecause no part of the pipeline knew what warm meant here.\n\ntarget_hex is a DESIGN TARGET, not a claim. It is not a measured historical\ncolour, not an archive source and not evidence; it never appears as\nprovenance, and it never relaxes an evidence floor or a guidance hold. It\nexists so retrieval can be held to the colour family the model actually\nmeant, and the colour that ends up on the wall is still a real, sourced\narchive record carrying its own provenance."},"IdentityAssets":{"properties":{"logo_image_id":{"type":"string","title":"Logo Image Id","default":""},"wordmark_image_id":{"type":"string","title":"Wordmark Image Id","default":""},"logo_base64":{"type":"string","title":"Logo Base64","default":""},"wordmark_base64":{"type":"string","title":"Wordmark Base64","default":""}},"type":"object","title":"IdentityAssets"},"ImageBriefRequest":{"properties":{"image_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Image Url"},"image_base64":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Image Base64"},"k":{"type":"integer","title":"K","default":6},"grey_card_hex":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Grey Card Hex"},"style_context":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Style Context"},"archive":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Archive"},"product_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Product Type"},"model":{"type":"string","title":"Model","default":"midjourney"}},"type":"object","title":"ImageBriefRequest"},"ImagePaletteRequest":{"properties":{"image_base64":{"type":"string","title":"Image Base64","default":""},"image":{"type":"string","title":"Image","default":""},"base64":{"type":"string","title":"Base64","default":""},"image_url":{"type":"string","title":"Image Url","default":""},"media_type":{"type":"string","title":"Media Type","default":"image/jpeg"},"n_colours":{"type":"integer","title":"N Colours","default":5},"n_colors":{"type":"integer","title":"N Colors","default":0},"archive":{"type":"string","title":"Archive","default":""}},"type":"object","title":"ImagePaletteRequest"},"ImagePromptRequest":{"properties":{"colours":{"items":{},"type":"array","title":"Colours"},"generator":{"type":"string","title":"Generator","default":"midjourney"},"style":{"type":"string","title":"Style","default":"architectural"},"subject":{"type":"string","title":"Subject","default":""},"context":{"type":"string","title":"Context","default":""}},"type":"object","required":["colours"],"title":"ImagePromptRequest"},"InteriorRole":{"properties":{"role":{"type":"string","title":"Role"},"surfaces":{"items":{"type":"string"},"type":"array","title":"Surfaces","default":[]},"intent":{"type":"string","title":"Intent","default":""},"target_hex":{"type":"string","title":"Target Hex","default":""},"allow_contrast":{"type":"boolean","title":"Allow Contrast","default":false},"proportion":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Proportion"}},"type":"object","required":["role"],"title":"InteriorRole","description":"One role in a room's spatial hierarchy, decided by the MODEL.\n\nThe vocabulary is deliberately open: field / architectural / ground /\njoinery / material / textile / accent / signal are all reasonable, and a\nroom may need three of them or six. What matters is that the room's\nhierarchy is decided BEFORE colours are retrieved, so retrieval can be\nasked for candidates that suit a named job on a named surface -- rather\nthan five colours being found first and somewhere to put each one invented\nafterwards."},"InteriorSpecRequest":{"properties":{"concept":{"type":"string","title":"Concept"},"output_format":{"type":"string","enum":["standard","scene_brief"],"title":"Output Format","default":"standard"},"room_type":{"type":"string","title":"Room Type","default":"living"},"style":{"type":"string","title":"Style","default":"heritage"},"orientation":{"type":"string","title":"Orientation","default":""},"n_colours":{"type":"integer","title":"N Colours","default":5},"avoid":{"items":{"type":"string"},"type":"array","title":"Avoid","default":[]},"archive":{"type":"string","title":"Archive","default":""},"role_plan":{"items":{"$ref":"#/components/schemas/InteriorRole"},"type":"array","title":"Role Plan","default":[]}},"type":"object","required":["concept"],"title":"InteriorSpecRequest"},"MaterialResponse":{"properties":{"colour_name":{"type":"string","title":"Colour Name"},"archive":{"type":"string","title":"Archive"},"period":{"type":"string","title":"Period"},"albedo_daylight":{"type":"string","title":"Albedo Daylight"},"albedo_candlelight":{"type":"string","title":"Albedo Candlelight"},"albedo_daylight_note":{"type":"string","title":"Albedo Daylight Note"},"albedo_candlelight_note":{"type":"string","title":"Albedo Candlelight Note"},"illuminant_method":{"type":"string","title":"Illuminant Method"},"lrv":{"type":"number","title":"Lrv"},"substrate_class":{"type":"string","title":"Substrate Class"},"roughness_hint":{"type":"number","title":"Roughness Hint"},"source":{"type":"string","title":"Source"},"claim_strength":{"type":"string","title":"Claim Strength"},"period_coherent":{"type":"boolean","title":"Period Coherent"},"anachronism_risk":{"type":"string","title":"Anachronism Risk"},"drift_flag":{"type":"string","title":"Drift Flag"},"drift_note":{"type":"string","title":"Drift Note"},"css_variable":{"type":"string","title":"Css Variable"},"suggested_scene_note":{"type":"string","title":"Suggested Scene Note"}},"type":"object","required":["colour_name","archive","period","albedo_daylight","albedo_candlelight","albedo_daylight_note","albedo_candlelight_note","illuminant_method","lrv","substrate_class","roughness_hint","source","claim_strength","period_coherent","anachronism_risk","drift_flag","drift_note","css_variable","suggested_scene_note"],"title":"MaterialResponse"},"MemoryHooksRequest":{"properties":{"hex":{"type":"string","title":"Hex"},"audience":{"type":"string","title":"Audience","default":"general public"},"tone":{"type":"string","title":"Tone","default":"dinner party"}},"type":"object","required":["hex"],"title":"MemoryHooksRequest"},"MixRecipeRequest":{"properties":{"hex":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hex"},"colour_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Colour Name"},"medium":{"type":"string","title":"Medium","default":"oil"},"available_pigments":{"items":{},"type":"array","title":"Available Pigments","default":[]},"include_history":{"type":"boolean","title":"Include History","default":true}},"type":"object","title":"MixRecipeRequest"},"MixRequest":{"properties":{"hex_a":{"type":"string","title":"Hex A"},"hex_b":{"type":"string","title":"Hex B"},"ratio":{"type":"number","title":"Ratio","default":0.5}},"type":"object","required":["hex_a","hex_b"],"title":"MixRequest"},"NameGeneratorRequest":{"properties":{"hex":{"type":"string","title":"Hex"},"style":{"type":"string","title":"Style","default":"mixed"},"market":{"type":"string","title":"Market","default":"UK"},"product_type":{"type":"string","title":"Product Type","default":"general"},"n_names":{"type":"integer","title":"N Names","default":5}},"type":"object","required":["hex"],"title":"NameGeneratorRequest"},"OutputPreferences":{"properties":{"language":{"type":"string","title":"Language","default":"en-GB"},"tone":{"type":"string","title":"Tone","default":"authoritative"}},"type":"object","title":"OutputPreferences"},"PaletteAnalyseRequest":{"properties":{"colours":{"items":{"$ref":"#/components/schemas/PaletteColourInput"},"type":"array","title":"Colours"},"archive":{"type":"string","title":"Archive","default":""},"allowed_archives":{"items":{"type":"string"},"type":"array","title":"Allowed Archives","default":[]},"n":{"type":"integer","title":"N","default":1},"intent":{"type":"string","title":"Intent","default":""}},"type":"object","required":["colours"],"title":"PaletteAnalyseRequest"},"PaletteAuditRequest":{"properties":{"palette":{"items":{"type":"string"},"type":"array","title":"Palette"},"use_case":{"type":"string","title":"Use Case","default":"brand identity"},"market":{"type":"string","title":"Market","default":"global"},"medium":{"type":"string","title":"Medium","default":"digital"}},"type":"object","required":["palette"],"title":"PaletteAuditRequest"},"PaletteCollectionRequest":{"properties":{"title":{"type":"string","title":"Title","default":""},"archive":{"type":"string","title":"Archive","default":""},"themes":{"items":{"type":"string"},"type":"array","title":"Themes","default":[]},"n_palettes":{"type":"integer","title":"N Palettes","default":0},"colours_per_palette":{"type":"integer","title":"Colours Per Palette","default":5},"strict_sources":{"type":"boolean","title":"Strict Sources","default":true},"confidence_threshold":{"type":"number","title":"Confidence Threshold","default":0.5},"minimum_claim_strength":{"type":"string","title":"Minimum Claim Strength","default":""},"include_neutrals":{"type":"boolean","title":"Include Neutrals","default":true},"avoid":{"items":{"type":"string"},"type":"array","title":"Avoid","default":[]},"allow_partial":{"type":"boolean","title":"Allow Partial","default":false}},"type":"object","title":"PaletteCollectionRequest"},"PaletteColourInput":{"properties":{"hex":{"type":"string","title":"Hex"},"weight":{"type":"number","title":"Weight","default":1.0}},"type":"object","required":["hex"],"title":"PaletteColourInput"},"PaletteColourwaysRequest":{"properties":{"base_palette":{"items":{"type":"string"},"type":"array","title":"Base Palette"},"pattern_type":{"type":"string","title":"Pattern Type","default":"stripe"},"n_colourways":{"type":"integer","title":"N Colourways","default":2},"direction":{"type":"string","title":"Direction","default":"darker"},"archive":{"type":"string","title":"Archive","default":""},"use_case":{"type":"string","title":"Use Case","default":"luxury wallpaper collection"},"market":{"type":"string","title":"Market","default":"global"}},"type":"object","required":["base_palette"],"title":"PaletteColourwaysRequest"},"PaletteCompareRequest":{"properties":{"palette_a":{"items":{"type":"string"},"type":"array","title":"Palette A"},"palette_b":{"items":{"type":"string"},"type":"array","title":"Palette B"},"use_case":{"type":"string","title":"Use Case","default":"general"},"markets":{"items":{"type":"string"},"type":"array","title":"Markets","default":[]}},"type":"object","required":["palette_a","palette_b"],"title":"PaletteCompareRequest"},"PaletteConceptRequest":{"properties":{"concept":{"type":"string","title":"Concept"},"n_colours":{"type":"integer","title":"N Colours","default":5},"include_neutrals":{"type":"boolean","title":"Include Neutrals","default":true},"avoid":{"items":{"type":"string"},"type":"array","title":"Avoid","default":[]}},"type":"object","required":["concept"],"title":"PaletteConceptRequest"},"PaletteExportRequest":{"properties":{"palette":{"items":{"type":"string"},"type":"array","title":"Palette"},"format":{"type":"string","title":"Format","default":"css"},"names":{"items":{"type":"string"},"type":"array","title":"Names","default":[]},"prefix":{"type":"string","title":"Prefix","default":"cm"}},"type":"object","required":["palette"],"title":"PaletteExportRequest"},"PaletteExtractRequest":{"properties":{"image_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Image Id"},"image_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Image Url"},"image_base64":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Image Base64"},"k":{"type":"integer","title":"K","default":6},"grey_card_hex":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Grey Card Hex"},"analyse":{"type":"boolean","title":"Analyse","default":false},"style_context":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Style Context"},"archive":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Archive"}},"type":"object","title":"PaletteExtractRequest"},"PaletteGenerateRequest":{"properties":{"slots":{"items":{"$ref":"#/components/schemas/PaletteSlot"},"type":"array","title":"Slots"},"archive":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Archive"},"size":{"type":"integer","title":"Size","default":5}},"type":"object","required":["slots"],"title":"PaletteGenerateRequest"},"PaletteGradientRequest":{"properties":{"anchors":{"items":{"type":"string"},"type":"array","title":"Anchors"},"steps":{"type":"integer","title":"Steps","default":7},"path":{"type":"string","title":"Path","default":"chroma_preserved"},"snap_to_archive":{"type":"boolean","title":"Snap To Archive","default":true},"archive":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Archive"},"output_format":{"type":"string","title":"Output Format","default":"stops"}},"type":"object","required":["anchors"],"title":"PaletteGradientRequest"},"PaletteInput":{"properties":{"mode":{"type":"string","title":"Mode"},"colours":{"items":{"type":"string"},"type":"array","title":"Colours"},"locked_colours":{"items":{"type":"string"},"type":"array","title":"Locked Colours"},"concept":{"type":"string","title":"Concept","default":""},"archive":{"type":"string","title":"Archive","default":""},"image_id":{"type":"string","title":"Image Id","default":""}},"type":"object","required":["mode"],"title":"PaletteInput"},"PaletteIterateRequest":{"properties":{"palette":{"items":{"type":"string"},"type":"array","title":"Palette"},"feedback":{"type":"string","title":"Feedback","default":""},"direction":{"type":"string","title":"Direction","default":""},"refinement":{"type":"string","title":"Refinement","default":""},"style_goal":{"type":"string","title":"Style Goal","default":""},"use_case":{"type":"string","title":"Use Case","default":"general"},"markets":{"items":{"type":"string"},"type":"array","title":"Markets","default":[]},"n_results":{"type":"integer","title":"N Results","default":1}},"type":"object","required":["palette"],"title":"PaletteIterateRequest"},"PaletteLightDarkRequest":{"properties":{"palette":{"items":{"type":"string"},"type":"array","title":"Palette"},"use_case":{"type":"string","title":"Use Case","default":"UI"}},"type":"object","required":["palette"],"title":"PaletteLightDarkRequest"},"PaletteLutRequest":{"properties":{"colours":{"items":{"type":"string"},"type":"array","title":"Colours"},"weights":{"anyOf":[{"items":{"type":"number"},"type":"array"},{"type":"null"}],"title":"Weights"},"title":{"type":"string","title":"Title","default":"Colour Memory LUT"},"strength":{"type":"number","title":"Strength","default":1.0}},"type":"object","required":["colours"],"title":"PaletteLutRequest"},"PalettePDFRequest":{"properties":{"entries":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Entries","default":[]},"query":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Query","default":""},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source","default":""},"delivery":{"type":"string","title":"Delivery","default":"url"},"sections":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}],"title":"Sections"},"presentation":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Presentation"},"house":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"House"},"house_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"House Ref"},"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id"},"project_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Project Version"},"verify":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Verify"}},"type":"object","title":"PalettePDFRequest"},"PalettePatternRequest":{"properties":{"palette":{"items":{"type":"string"},"type":"array","title":"Palette"},"pattern_type":{"type":"string","title":"Pattern Type","default":"stripe"},"use_case":{"type":"string","title":"Use Case","default":"luxury wallpaper"},"market":{"type":"string","title":"Market","default":"global"}},"type":"object","required":["palette"],"title":"PalettePatternRequest"},"PaletteRecipeRequest":{"properties":{"seed_hex":{"type":"string","title":"Seed Hex"},"seed_role":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Seed Role"},"harmony":{"type":"string","title":"Harmony","default":"auto"},"strength":{"type":"integer","title":"Strength","default":0},"temperature":{"type":"integer","title":"Temperature","default":0},"contrast":{"type":"integer","title":"Contrast","default":0},"accent":{"type":"integer","title":"Accent","default":0},"locked":{"additionalProperties":{"type":"string"},"type":"object","title":"Locked","default":{}},"variant":{"type":"integer","title":"Variant","default":0},"seed_source":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Seed Source"},"algorithm_version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Algorithm Version"},"include_evidence":{"type":"boolean","title":"Include Evidence","default":false},"seed_record":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Seed Record"},"source_palette":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Source Palette"}},"type":"object","required":["seed_hex"],"title":"PaletteRecipeRequest"},"PaletteSlot":{"properties":{"index":{"type":"integer","title":"Index"},"hex":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hex"},"locked":{"type":"boolean","title":"Locked","default":false}},"type":"object","required":["index"],"title":"PaletteSlot"},"PaletteTranslateRequest":{"properties":{"palette":{"items":{"type":"string"},"type":"array","title":"Palette"},"target_archive":{"type":"string","title":"Target Archive"},"max_delta_e":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Delta E","default":40.0}},"type":"object","required":["palette","target_archive"],"title":"PaletteTranslateRequest"},"PaletteVerdictRequest":{"properties":{"palette":{"items":{},"type":"array","title":"Palette"},"use_case":{"type":"string","title":"Use Case"},"market":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Market"},"medium":{"type":"string","title":"Medium","default":"general"}},"type":"object","required":["palette","use_case"],"title":"PaletteVerdictRequest"},"PersonalColourJpegRequest":{"properties":{"image_base64":{"type":"string","title":"Image Base64"},"media_type":{"type":"string","title":"Media Type","default":"image/jpeg"},"name":{"type":"string","title":"Name","default":""}},"type":"object","required":["image_base64"],"title":"PersonalColourJpegRequest"},"PersonalColourRequest":{"properties":{"image_base64":{"type":"string","title":"Image Base64","default":""},"image_url":{"type":"string","title":"Image Url","default":""},"media_type":{"type":"string","title":"Media Type","default":"image/jpeg"},"name":{"type":"string","title":"Name","default":""}},"type":"object","title":"PersonalColourRequest"},"PigmentCheckRequest":{"properties":{"pigments":{"items":{"type":"string"},"type":"array","title":"Pigments"},"medium":{"type":"string","title":"Medium","default":"oil"}},"type":"object","required":["pigments"],"title":"PigmentCheckRequest"},"Preferences":{"properties":{"palette_size":{"type":"integer","title":"Palette Size","default":5},"accessibility_target":{"type":"string","title":"Accessibility Target","default":"AA"},"minimum_claim_strength":{"type":"string","title":"Minimum Claim Strength","default":"E"},"strict_semantic_colour":{"type":"boolean","title":"Strict Semantic Colour","default":false},"allow_unsourced_original_colours":{"type":"boolean","title":"Allow Unsourced Original Colours","default":true}},"type":"object","title":"Preferences"},"ProductLineNamerRequest":{"properties":{"hexes":{"items":{"type":"string"},"type":"array","title":"Hexes"},"product_category":{"type":"string","title":"Product Category","default":""},"brand_name":{"type":"string","title":"Brand Name","default":""},"style":{"type":"string","title":"Style","default":"mixed"},"max_dE":{"type":"number","title":"Max De","default":25.0},"exclude_archives":{"items":{"type":"string"},"type":"array","title":"Exclude Archives","default":[]},"include_sensitive":{"type":"boolean","title":"Include Sensitive","default":false}},"type":"object","required":["hexes"],"title":"ProductLineNamerRequest"},"ProjectDeleteRequest":{"properties":{"project_id":{"type":"string","title":"Project Id"},"deletion_token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Deletion Token"}},"type":"object","required":["project_id"],"title":"ProjectDeleteRequest"},"ProjectExportRequest":{"properties":{"house":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"House"},"house_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"House Ref"},"project_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Id"},"project_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Project Version"},"format":{"type":"string","title":"Format"},"delivery":{"type":"string","title":"Delivery","default":"url"}},"type":"object","required":["format"],"title":"ProjectExportRequest"},"ProjectGetRequest":{"properties":{"project_id":{"type":"string","title":"Project Id"},"version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Version"}},"type":"object","required":["project_id"],"title":"ProjectGetRequest"},"ProjectListRequest":{"properties":{"limit":{"type":"integer","title":"Limit","default":50},"cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"},"project_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Type"},"updated_since":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated Since"},"include_deleted":{"type":"boolean","title":"Include Deleted","default":false}},"type":"object","title":"ProjectListRequest"},"ProjectVersionsRequest":{"properties":{"project_id":{"type":"string","title":"Project Id"}},"type":"object","required":["project_id"],"title":"ProjectVersionsRequest"},"ProvenanceRequest":{"properties":{"colour_name":{"type":"string","title":"Colour Name"}},"type":"object","required":["colour_name"],"title":"ProvenanceRequest"},"ReportPDFRequest":{"properties":{"brief":{"additionalProperties":true,"type":"object","title":"Brief"},"title":{"type":"string","title":"Title","default":"Colour Memory"},"subtitle":{"type":"string","title":"Subtitle","default":""},"period":{"type":"string","title":"Period","default":""}},"type":"object","required":["brief"],"title":"ReportPDFRequest"},"ResonanceIndexRequest":{"properties":{"entries":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Entries"},"score_basis":{"type":"string","title":"Score Basis","default":"material_origin_to_social_consequence"}},"type":"object","required":["entries"],"title":"ResonanceIndexRequest"},"SceneMaterial":{"properties":{"surface":{"type":"string","title":"Surface"},"colour_name":{"type":"string","title":"Colour Name"},"albedo_daylight":{"type":"string","title":"Albedo Daylight"},"albedo_candlelight":{"type":"string","title":"Albedo Candlelight"},"lrv":{"type":"number","title":"Lrv"},"substrate_class":{"type":"string","title":"Substrate Class"},"roughness_hint":{"type":"number","title":"Roughness Hint"},"source":{"type":"string","title":"Source"},"claim_strength":{"type":"string","title":"Claim Strength"},"drift_flag":{"type":"string","title":"Drift Flag"}},"type":"object","required":["surface","colour_name","albedo_daylight","albedo_candlelight","lrv","substrate_class","roughness_hint","source","claim_strength","drift_flag"],"title":"SceneMaterial"},"SceneRequest":{"properties":{"period":{"type":"string","title":"Period"},"room_type":{"type":"string","title":"Room Type","default":"great_hall"},"style":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Style"},"surfaces":{"items":{"type":"string"},"type":"array","title":"Surfaces","default":["wall","floor","ceiling","wood","textile","metal"]}},"type":"object","required":["period"],"title":"SceneRequest"},"SceneResponse":{"properties":{"period":{"type":"string","title":"Period"},"room_type":{"type":"string","title":"Room Type"},"archive":{"type":"string","title":"Archive"},"period_coherent":{"type":"boolean","title":"Period Coherent"},"materials":{"items":{"$ref":"#/components/schemas/SceneMaterial"},"type":"array","title":"Materials"},"scene_note":{"type":"string","title":"Scene Note"},"css_variables":{"type":"string","title":"Css Variables"},"production_bible_note":{"type":"string","title":"Production Bible Note"}},"type":"object","required":["period","room_type","archive","period_coherent","materials","scene_note","css_variables","production_bible_note"],"title":"SceneResponse"},"ShareRequest":{"properties":{"session_id":{"type":"string","title":"Session Id","default":""},"include_image":{"type":"boolean","title":"Include Image","default":false},"revoke_token":{"type":"string","title":"Revoke Token","default":""}},"type":"object","title":"ShareRequest"},"SpecifyRequest":{"properties":{"colours":{"items":{"type":"string"},"type":"array","title":"Colours"},"room_type":{"type":"string","title":"Room Type","default":"living"},"style":{"type":"string","title":"Style","default":""}},"type":"object","required":["colours"],"title":"SpecifyRequest"},"StrictPaletteConceptRequest":{"properties":{"concept":{"type":"string","title":"Concept"},"allowed_archives":{"items":{"type":"string"},"type":"array","title":"Allowed Archives","default":[]},"n_colours":{"type":"integer","title":"N Colours","default":5},"min_relevance":{"type":"number","title":"Min Relevance","default":0.3},"include_neutrals":{"type":"boolean","title":"Include Neutrals","default":true}},"type":"object","required":["concept"],"title":"StrictPaletteConceptRequest"},"StyleMatchRequest":{"properties":{"items":{"items":{},"type":"array","title":"Items"},"occasion":{"type":"string","title":"Occasion","default":"general"},"ask":{"type":"string","title":"Ask","default":""}},"type":"object","required":["items"],"title":"StyleMatchRequest"},"SubscribeRequest":{"properties":{"email":{"type":"string","title":"Email"},"tier":{"type":"string","title":"Tier"},"payment_method_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payment Method Id","default":""},"purchase_attempt_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Purchase Attempt Id","default":""}},"type":"object","required":["email","tier"],"title":"SubscribeRequest"},"ToolGuideRequest":{"properties":{"goal":{"type":"string","title":"Goal"}},"type":"object","required":["goal"],"title":"ToolGuideRequest"},"UIStatePaletteRequest":{"properties":{"brand_hex":{"type":"string","title":"Brand Hex"},"background_hex":{"type":"string","title":"Background Hex","default":"#FFFFFF"},"dark_mode":{"type":"boolean","title":"Dark Mode","default":false}},"type":"object","required":["brand_hex"],"title":"UIStatePaletteRequest"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"VanderpoelMethodRequest":{"properties":{"hex":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hex"},"hexes":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Hexes"},"plate_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Plate Id"},"suggest":{"anyOf":[{"type":"integer"},{"type":"string"},{"type":"null"}],"title":"Suggest"},"mode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mode"}},"type":"object","title":"VanderpoelMethodRequest"},"VanderpoelPairingRequest":{"properties":{"hex":{"type":"string","title":"Hex"},"n_per_member":{"type":"integer","title":"N Per Member","default":1}},"type":"object","required":["hex"],"title":"VanderpoelPairingRequest"},"VerifierRequest":{"properties":{"hex":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hex"},"query":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Query"}},"type":"object","title":"VerifierRequest"}}}}