{"openapi":"3.1.0","info":{"title":"Farm Intel API","version":"0.1.0"},"paths":{"/api/auth/me":{"get":{"tags":["auth"],"summary":"Get Me","description":"Check if the current user has a farm membership.\nReturns {has_farm, farm_id, farm_name, role} so the frontend\nknows whether to show /setup or /knowledge.","operationId":"get_me_api_auth_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/auth/onboard":{"post":{"tags":["auth"],"summary":"Onboard","description":"Create a new farm and link the authenticated user as admin.\nCalled from the /setup page after signup.","operationId":"onboard_api_auth_onboard_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/workers":{"get":{"tags":["workers"],"summary":"List Workers","description":"List all workers for the current farm with message stats. Admin only.","operationId":"list_workers_api_workers_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"post":{"tags":["workers"],"summary":"Create Worker","description":"Admin enters a worker's name → we generate a unique token.","operationId":"create_worker_api_workers_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWorkerRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/workers/me":{"get":{"tags":["workers"],"summary":"Worker Me","description":"Worker validates their token and gets their own info.\nCalled by /chat/[token] page to confirm access and get the worker's name.","operationId":"worker_me_api_workers_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/workers/me/messages":{"get":{"tags":["workers"],"summary":"Worker Own Messages","description":"Worker fetches their own conversation history via their token.","operationId":"worker_own_messages_api_workers_me_messages_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":200,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["workers"],"summary":"Worker Clear Messages","description":"Worker clears their own conversation history.","operationId":"worker_clear_messages_api_workers_me_messages_delete","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/workers/{worker_id}/messages":{"get":{"tags":["workers"],"summary":"Get Worker Messages","description":"View a worker's conversation history. Admin only, scoped to farm.","operationId":"get_worker_messages_api_workers__worker_id__messages_get","parameters":[{"name":"worker_id","in":"path","required":true,"schema":{"type":"string","title":"Worker Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/workers/{worker_id}/regenerate":{"post":{"tags":["workers"],"summary":"Regenerate Token","description":"Generate a new token for a worker. Old link stops working immediately.","operationId":"regenerate_token_api_workers__worker_id__regenerate_post","parameters":[{"name":"worker_id","in":"path","required":true,"schema":{"type":"string","title":"Worker Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/workers/{worker_id}":{"delete":{"tags":["workers"],"summary":"Remove Worker","description":"Revoke a worker's access. Admin only.","operationId":"remove_worker_api_workers__worker_id__delete","parameters":[{"name":"worker_id","in":"path","required":true,"schema":{"type":"string","title":"Worker Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/knowledge/sources":{"get":{"summary":"List Sources","description":"Return all knowledge sources for the farm, newest first.","operationId":"list_sources_api_knowledge_sources_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnowledgeSourcesResponse"}}}}}},"delete":{"summary":"Delete All Sources","description":"Delete every knowledge source for this farm.","operationId":"delete_all_sources_api_knowledge_sources_delete","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/knowledge/sources/{source_id}/preview":{"get":{"summary":"Preview Source","description":"Return the extracted text stored for a source. Used by the preview modal.","operationId":"preview_source_api_knowledge_sources__source_id__preview_get","parameters":[{"name":"source_id","in":"path","required":true,"schema":{"type":"string","title":"Source Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/knowledge/sources/{source_id}":{"put":{"summary":"Update Source","description":"Update the extracted text of a source and re-index it in OpenAI.\nSteps: update DB text → remove old OpenAI file → upload new one → update source record.","operationId":"update_source_api_knowledge_sources__source_id__put","parameters":[{"name":"source_id","in":"path","required":true,"schema":{"type":"string","title":"Source Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnowledgeUpdateSourceRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Delete Source","description":"Delete a single knowledge source and clean up from OpenAI.","operationId":"delete_source_api_knowledge_sources__source_id__delete","parameters":[{"name":"source_id","in":"path","required":true,"schema":{"type":"string","title":"Source Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/knowledge/chat":{"post":{"summary":"Chat","description":"Ask a question against the farm's knowledge base. Works for both admins and workers.","operationId":"chat_api_knowledge_chat_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnowledgeChatRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnowledgeChatResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/knowledge/extract":{"post":{"summary":"Extract Preview","description":"Extract text from image/audio/PDF files without indexing.\nUsed by the frontend review-before-indexing flow — the user can\nedit the extracted text before clicking \"Index\".","operationId":"extract_preview_api_knowledge_extract_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_extract_preview_api_knowledge_extract_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/knowledge/ingest":{"post":{"summary":"Ingest","description":"Ingest text notes and/or files into the farm's knowledge base.\n\nTwo paths:\n1. text + optional title  → ingest as a text note directly (no extraction needed)\n2. files                  → extract text, dedup, index into OpenAI vector store\n\nFor files that need human review (image/audio/PDF), the frontend calls /extract\nfirst, lets the user edit the text, then re-submits via /ingest with text + source_type.","operationId":"ingest_api_knowledge_ingest_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_ingest_api_knowledge_ingest_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnowledgeIngestResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/knowledge/transcribe":{"post":{"summary":"Transcribe Audio","description":"Transcribe a short audio clip via whisper-1 (fastest model for live voice input).","operationId":"transcribe_audio_api_knowledge_transcribe_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_transcribe_audio_api_knowledge_transcribe_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/knowledge/tts":{"post":{"summary":"Text To Speech","description":"Convert an AI response to speech via ElevenLabs. Available to admins and workers.","operationId":"text_to_speech_api_knowledge_tts_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TTSRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/packs":{"get":{"summary":"List Packs","description":"Return all available packs with an `enabled` flag for the user's farm.","operationId":"list_packs_api_packs_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/packs/farm":{"get":{"summary":"List Farm Packs","description":"Return only the packs enabled for this farm.","operationId":"list_farm_packs_api_packs_farm_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/packs/farm/{pack_slug}/enable":{"post":{"summary":"Enable Pack","description":"Enable a knowledge pack for the farm.","operationId":"enable_pack_api_packs_farm__pack_slug__enable_post","parameters":[{"name":"pack_slug","in":"path","required":true,"schema":{"type":"string","title":"Pack Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/packs/farm/{pack_slug}/disable":{"delete":{"summary":"Disable Pack","description":"Disable a knowledge pack for the farm.","operationId":"disable_pack_api_packs_farm__pack_slug__disable_delete","parameters":[{"name":"pack_slug","in":"path","required":true,"schema":{"type":"string","title":"Pack Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/packs/{pack_slug}/ingest":{"post":{"summary":"Ingest Pack Pdf","description":"Ingest a PDF into a knowledge pack using pypdf (no Vision OCR).\nAdmin-only. Creates the pack's vector store if needed.","operationId":"ingest_pack_pdf_api_packs__pack_slug__ingest_post","parameters":[{"name":"pack_slug","in":"path","required":true,"schema":{"type":"string","title":"Pack Slug"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_ingest_pack_pdf_api_packs__pack_slug__ingest_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/health":{"get":{"summary":"Health","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"Body_extract_preview_api_knowledge_extract_post":{"properties":{"files":{"anyOf":[{"items":{"type":"string","contentMediaType":"application/octet-stream"},"type":"array"},{"type":"null"}],"title":"Files"}},"type":"object","title":"Body_extract_preview_api_knowledge_extract_post"},"Body_ingest_api_knowledge_ingest_post":{"properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Text"},"source_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Type"},"files":{"anyOf":[{"items":{"type":"string","contentMediaType":"application/octet-stream"},"type":"array"},{"type":"null"}],"title":"Files"}},"type":"object","title":"Body_ingest_api_knowledge_ingest_post"},"Body_ingest_pack_pdf_api_packs__pack_slug__ingest_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"}},"type":"object","required":["file"],"title":"Body_ingest_pack_pdf_api_packs__pack_slug__ingest_post"},"Body_transcribe_audio_api_knowledge_transcribe_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_transcribe_audio_api_knowledge_transcribe_post"},"ChatMessage":{"properties":{"role":{"type":"string","enum":["user","assistant"],"title":"Role"},"content":{"type":"string","title":"Content"}},"type":"object","required":["role","content"],"title":"ChatMessage"},"CreateWorkerRequest":{"properties":{"name":{"type":"string","title":"Name"}},"type":"object","required":["name"],"title":"CreateWorkerRequest"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"KnowledgeChatRequest":{"properties":{"question":{"type":"string","title":"Question"},"language":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Language","default":"en"},"history":{"items":{"$ref":"#/components/schemas/ChatMessage"},"type":"array","title":"History"}},"type":"object","required":["question"],"title":"KnowledgeChatRequest"},"KnowledgeChatResponse":{"properties":{"answer":{"type":"string","title":"Answer"},"citations":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Citations"}},"type":"object","required":["answer"],"title":"KnowledgeChatResponse"},"KnowledgeIngestResponse":{"properties":{"sources_created":{"type":"integer","title":"Sources Created","default":0},"documents_created":{"type":"integer","title":"Documents Created","default":0},"openai_indexed":{"type":"boolean","title":"Openai Indexed","default":false},"warnings":{"items":{"type":"string"},"type":"array","title":"Warnings"}},"type":"object","title":"KnowledgeIngestResponse"},"KnowledgeSourcesResponse":{"properties":{"sources":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Sources"}},"type":"object","required":["sources"],"title":"KnowledgeSourcesResponse"},"KnowledgeUpdateSourceRequest":{"properties":{"text":{"type":"string","title":"Text"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"}},"type":"object","required":["text"],"title":"KnowledgeUpdateSourceRequest"},"OnboardRequest":{"properties":{"farm_name":{"type":"string","title":"Farm Name"}},"type":"object","required":["farm_name"],"title":"OnboardRequest"},"TTSRequest":{"properties":{"text":{"type":"string","title":"Text"},"language":{"type":"string","title":"Language","default":"en"}},"type":"object","required":["text"],"title":"TTSRequest"},"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"}}}}