{"openapi":"3.1.0","info":{"title":"Plexa API","description":"Agentic business directory for Mexico/LATAM","version":"0.1.0"},"paths":{"/api/v1/health":{"get":{"tags":["health"],"summary":"Health Check","operationId":"health_check_api_v1_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/me":{"get":{"tags":["auth"],"summary":"Get Me","operationId":"get_me_api_v1_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/search":{"get":{"tags":["search"],"summary":"Search Businesses","operationId":"search_businesses_api_v1_search_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Q"}},{"name":"vertical","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vertical"}},{"name":"city","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"}},{"name":"state","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"State"}},{"name":"country","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country"}},{"name":"lat","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lat"}},{"name":"lng","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lng"}},{"name":"radius_km","in":"query","required":false,"schema":{"type":"number","default":15,"title":"Radius Km"}},{"name":"lang","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lang"}},{"name":"capabilities","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Capabilities"}},{"name":"min_trust_score","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Min Trust Score"}},{"name":"claimed","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Claimed"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"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":{"$ref":"#/components/schemas/SearchResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/verticals":{"get":{"tags":["verticals"],"summary":"List Verticals","operationId":"list_verticals_api_v1_verticals_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Response List Verticals Api V1 Verticals Get"}}}}}}},"/api/v1/directories/filters":{"get":{"tags":["directories"],"summary":"Directory Filters","operationId":"directory_filters_api_v1_directories_filters_get","parameters":[{"name":"vertical","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vertical"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/directories/combos":{"get":{"tags":["directories"],"summary":"Directory Combos","description":"Combos vertical×ciudad con al menos `min` negocios activos, con su conteo y la fecha de\nactualización más reciente. Para el sitemap: solo lista páginas de directorio NO vacías\n(≥min negocios reales) con `lastmod` real (max updated_at del combo). Read-only, cache 5 min.","operationId":"directory_combos_api_v1_directories_combos_get","parameters":[{"name":"min","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"default":3,"title":"Min"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/stats/public":{"get":{"tags":["stats"],"summary":"Public Stats","description":"Stats públicas para la landing. Cache Redis 5 min. Degradación graceful.","operationId":"public_stats_api_v1_stats_public_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/stats/crawler-visit":{"post":{"tags":["stats"],"summary":"Log Crawler Visit","description":"Registra visita de bot IA (llamado por el middleware de Next.js).\nRate limit 100/min por IP. Fire-and-forget: nunca rompe.","operationId":"log_crawler_visit_api_v1_stats_crawler_visit_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrawlerVisitRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/stats/crawler-activity":{"get":{"tags":["stats"],"summary":"Crawler Activity","description":"Actividad de bots IA en Plexa (últimos 30 días). Cache Redis 5 min.","operationId":"crawler_activity_api_v1_stats_crawler_activity_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/stats/crawler-activity/{bot_name}/details":{"get":{"tags":["stats"],"summary":"Crawler Activity Details","description":"Últimas visitas de un bot específico (para el dropdown del feed), sin filtro\nde fecha: siempre las N más recientes (hoy, ayer o la semana pasada). Máx 10 por default.","operationId":"crawler_activity_details_api_v1_stats_crawler_activity__bot_name__details_get","parameters":[{"name":"bot_name","in":"path","required":true,"schema":{"type":"string","title":"Bot Name"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"default":10,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/stats/crawler-activity/recent":{"get":{"tags":["stats"],"summary":"Crawler Activity Recent","description":"Últimas N lecturas GLOBALES (cualquier bot != unknown) para el live-log del feed terminal.\nAlimenta SOLO datos reales — si viene vacío, el front oculta el log (nunca inventa líneas).\nCache Redis corta (30s) para que el 'en vivo' sea creíble sin martillar la DB.","operationId":"crawler_activity_recent_api_v1_stats_crawler_activity_recent_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":20,"minimum":1,"default":8,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/study/latest":{"get":{"tags":["stats"],"summary":"Study Latest","description":"Última edición del Índice de Visibilidad IA (estudio agregado) — público, cacheado 300s.\nNúmeros REALES persistidos por el cron quincenal (study_snapshots). 404 si no hay ediciones.","operationId":"study_latest_api_v1_study_latest_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/stats/recent-listings":{"get":{"tags":["stats"],"summary":"Recent Listings","description":"Últimos N negocios INDEXADOS en el registro (created_at DESC, activos, sin artefactos de\nprueba) para el terminal 'el registro crece' del home. Es COBERTURA del directorio público\ncreciendo por el seeding (nosotros indexando) — NO negocios que se registran. Todo dato ya\npúblico (nombre/giro/ciudad). Cache 60s + rate-limit anónimo estándar.","operationId":"recent_listings_api_v1_stats_recent_listings_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":20,"minimum":1,"default":10,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/builders/register":{"post":{"tags":["builders"],"summary":"Register Builder","description":"Crea una API key gratuita (free tier: 5K queries/mes, 60 req/min).","operationId":"register_builder_api_v1_builders_register_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BuilderRegisterRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/builders/me":{"get":{"tags":["builders"],"summary":"My Builder Keys","description":"Lista las API keys del usuario (key enmascarada).","operationId":"my_builder_keys_api_v1_builders_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/builders/usage":{"get":{"tags":["builders"],"summary":"My Usage","description":"Uso del mes actual por API key.","operationId":"my_usage_api_v1_builders_usage_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/builders/api-keys/{key_id}":{"delete":{"tags":["builders"],"summary":"Revoke Key","description":"Revoca (desactiva) una API key del usuario.","operationId":"revoke_key_api_v1_builders_api_keys__key_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"string","title":"Key Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/businesses/{id}/queries":{"get":{"tags":["businesses"],"summary":"Get Business Queries","description":"Queries agénticas a este negocio (solo owner).","operationId":"get_business_queries_api_v1_businesses__id__queries_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":1,"default":30,"title":"Days"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"default":10,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/businesses/{id}/analytics":{"get":{"tags":["businesses"],"summary":"Business Analytics","description":"Visibilidad: consultas este mes vs anterior, agentes, recientes (solo owner).\n\nFuente = crawler_visits (NO agent_queries): la identidad real del agente que\nvisita la ficha vive ahí (capturada en el edge de Next por business_id).\nagent_queries está dominada por el SSR server-to-server de Next (UA node), que\nno es un agente externo. Se excluye bot_name='unknown' (curl/node/sin clasificar)\ndel conteo y de la lista para que el dueño solo vea agentes reales identificados.","operationId":"business_analytics_api_v1_businesses__id__analytics_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/businesses/{id}/recommendations":{"get":{"tags":["businesses"],"summary":"Get Recommendations","description":"Recomendaciones accionables para completar el perfil (solo owner).","operationId":"get_recommendations_api_v1_businesses__id__recommendations_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/businesses/{id}/action-plan":{"get":{"tags":["businesses"],"summary":"Get Action Plan","description":"Plan de Acción del negocio para el hub 'Mejora tu visibilidad' (solo owner). Gateado por\ntier DENTRO de build_action_plan_section (reusa _PAID_TIERS): connected/pro ve los items\n(why + mecanismo + queries), free ve solo gaps_count. Genera al vuelo si falta (lazy).","operationId":"get_action_plan_api_v1_businesses__id__action_plan_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/businesses/{id}/geo-audit":{"get":{"tags":["businesses"],"summary":"Get Geo Audit","description":"Auditoría de citabilidad (GEO Nivel 1) del negocio (solo owner). Devuelve el audit\nACTUAL (última fila persistida); si no existe todavía, lo calcula y persiste (lazy).\nEnriquecido para el panel: lecturas de IA reales (crawler_visits) + percentil del score.\n404 si el gate maestro está apagado.","operationId":"get_geo_audit_api_v1_businesses__id__geo_audit_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/businesses/{id}/crawler-visits":{"get":{"tags":["businesses"],"summary":"Get Crawler Visits","description":"Drill-down de las lecturas de crawler de IA de la ficha (solo owner): las visitas reales\n(URL, hora, IP, UA) con VERIFICACIÓN contra el rango oficial del crawler. `verified=true` SOLO\nsi la IP cae en un rango oficial publicado del bot — jamás un badge falso (honestidad = producto).\nFiltra por `bot` (nombre agrupado) opcional. Reusa run/agent_type='crawler', excluye 'unknown'.","operationId":"get_crawler_visits_api_v1_businesses__id__crawler_visits_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}},{"name":"bot","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bot"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":30,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/businesses/{slug}/ask":{"post":{"tags":["businesses"],"summary":"Ask Agent About Business","description":"Un LLM responde sobre el negocio, grounded SOLO en su ficha (cero alucinación por diseño).\n404 si CHAT_ASK_ENABLED está apagado (gate de rollout). Rate-limit por IP (protección de tokens).","operationId":"ask_agent_about_business_api_v1_businesses__slug__ask_post","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AskRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/businesses/import/places-lookup":{"get":{"tags":["businesses"],"summary":"Import Places Lookup","description":"Busca el negocio en Google Places (Text Search, misma infra que el seeding) para pre-llenar el\nalta. 'Esto es lo que la IA ya ve de ti' — el dueño elige el resultado correcto (resuelve\nhomónimos con selección humana). Auth + rate-limit por usuario (las búsquedas de Places cuestan).","operationId":"import_places_lookup_api_v1_businesses_import_places_lookup_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"name","in":"query","required":true,"schema":{"type":"string","title":"Name"}},{"name":"vertical","in":"query","required":false,"schema":{"type":"string","default":"other","title":"Vertical"}},{"name":"city","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/businesses/{id}/faqs":{"get":{"tags":["businesses"],"summary":"List My Faqs","description":"FAQs del negocio (solo owner): publicadas + pendientes de aprobar. `can_manage` =\nConnected (generar/aprobar). Para el hub de FAQs en el dashboard del dueño.","operationId":"list_my_faqs_api_v1_businesses__id__faqs_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/businesses/{id}/faqs/generate":{"post":{"tags":["businesses"],"summary":"Generate My Faqs","description":"Dispara la generación de FAQs para el negocio (on-demand, Connected). Corre en background\n(LLM); el dueño refresca para ver las sugeridas en pending_approval.","operationId":"generate_my_faqs_api_v1_businesses__id__faqs_generate_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/businesses/{id}/faqs/{faq_id}/approve":{"post":{"tags":["businesses"],"summary":"Approve My Faq","description":"El dueño aprueba su FAQ → published (Connected). La ficha emite FAQPage.","operationId":"approve_my_faq_api_v1_businesses__id__faqs__faq_id__approve_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}},{"name":"faq_id","in":"path","required":true,"schema":{"type":"string","title":"Faq Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/businesses/{id}/faqs/{faq_id}/reject":{"post":{"tags":["businesses"],"summary":"Reject My Faq","description":"El dueño rechaza su FAQ → rejected (no se publica).","operationId":"reject_my_faq_api_v1_businesses__id__faqs__faq_id__reject_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}},{"name":"faq_id","in":"path","required":true,"schema":{"type":"string","title":"Faq Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/businesses/{id}/faqs/{faq_id}":{"patch":{"tags":["businesses"],"summary":"Edit My Faq","description":"El dueño edita su FAQ antes de aprobar (solo pending_approval).","operationId":"edit_my_faq_api_v1_businesses__id__faqs__faq_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}},{"name":"faq_id","in":"path","required":true,"schema":{"type":"string","title":"Faq Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OwnerFaqEdit"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/businesses/{id}/competitive":{"get":{"tags":["businesses"],"summary":"Competitive Insights","description":"Comparación con la competencia del mismo vertical+ciudad (solo Connected).","operationId":"competitive_insights_api_v1_businesses__id__competitive_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/businesses/{id}/subscription":{"get":{"tags":["businesses"],"summary":"Get Subscription","description":"Estado de la suscripción del negocio (solo owner).","operationId":"get_subscription_api_v1_businesses__id__subscription_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["businesses"],"summary":"Cancel Subscription","description":"Cancela la suscripción en MP y baja el negocio a Free (solo owner).","operationId":"cancel_subscription_api_v1_businesses__id__subscription_delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/businesses/{id}/upgrade":{"post":{"tags":["businesses"],"summary":"Upgrade Business","description":"Crea una suscripción Connected en MercadoPago y retorna el checkout_url (solo owner).","operationId":"upgrade_business_api_v1_businesses__id__upgrade_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/businesses/me":{"get":{"tags":["businesses"],"summary":"Get My Businesses","operationId":"get_my_businesses_api_v1_businesses_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/BusinessResponse"},"type":"array","title":"Response Get My Businesses Api V1 Businesses Me Get"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/businesses/me/visibility-reports":{"get":{"tags":["businesses"],"summary":"Get My Visibility Reports","description":"Para el dashboard cliente: por cada negocio del usuario, indica si ya tiene\nReporte de Visibilidad generado (visibility_metrics) y su URL pública por token.\nNo genera token para negocios sin reporte.","operationId":"get_my_visibility_reports_api_v1_businesses_me_visibility_reports_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/businesses/me/espejos":{"get":{"tags":["businesses"],"summary":"Get My Espejos","description":"Para el dashboard cliente: por cada negocio del usuario con Espejo generado (radar_reports\nno-suppressed), su link a /reporte/[token] (el dueño claimed lo ve COMPLETO, sin blur). El Espejo\n(foto de mercado/outreach) es pipeline APARTE del Reporte de Visibilidad (panel mensual del\ndueño) — esto es solo ACCESO de lectura, no una fusión. Negocio sin Espejo → no aparece.","operationId":"get_my_espejos_api_v1_businesses_me_espejos_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/businesses/":{"post":{"tags":["businesses"],"summary":"Create Business","operationId":"create_business_api_v1_businesses__post","security":[{"HTTPBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["businesses"],"summary":"List Businesses","operationId":"list_businesses_api_v1_businesses__get","parameters":[{"name":"vertical","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vertical"}},{"name":"city","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"}},{"name":"claimed","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Claimed"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"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":{"$ref":"#/components/schemas/BusinessListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/businesses/{id}/claim":{"post":{"tags":["businesses"],"summary":"Claim Business","description":"Reclamar un negocio comprobando el teléfono registrado.\n\nEl usuario ingresa el teléfono completo del negocio; se normaliza a E.164 y\nse compara con el registrado. Si coincide, el claim es instantáneo. Máximo\n3 intentos fallidos por usuario+negocio; tras eso, bloqueo de 24h.","operationId":"claim_business_api_v1_businesses__id__claim_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClaimRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/businesses/{id}/verify/email":{"post":{"tags":["businesses"],"summary":"Verify Email Self","description":"Otorga verificación de email al dueño autenticado. Tener sesión Supabase\nválida implica email confirmado. Útil para negocios creados antes de Fase 4\n(cuando auto_verify_email aún no existía).","operationId":"verify_email_self_api_v1_businesses__id__verify_email_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/businesses/{id}":{"put":{"tags":["businesses"],"summary":"Update Business","operationId":"update_business_api_v1_businesses__id__put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["businesses"],"summary":"Delete Business","description":"Soft-delete del propio negocio. Cancela la suscripción activa (MP) y\ndesvincula la ficha del dueño. Restaurable desde admin.","operationId":"delete_business_api_v1_businesses__id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/businesses/{id}/publish":{"post":{"tags":["businesses"],"summary":"Publish Business","operationId":"publish_business_api_v1_businesses__id__publish_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/businesses/{id}/unlink":{"post":{"tags":["businesses"],"summary":"Unlink Business","description":"Desvincula el negocio de la cuenta del dueño SIN eliminarlo.\n\nVuelve a estado unclaimed: sigue visible públicamente en el directorio, pero\ndeja de estar asociado a la cuenta. Cancela la suscripción activa si tiene.","operationId":"unlink_business_api_v1_businesses__id__unlink_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/businesses/{id}/removal-request":{"post":{"tags":["businesses"],"summary":"Request Removal","description":"Solicitud pública de eliminación de una ficha (no requiere auth).\n\nNO elimina nada: crea un registro pendiente de revisión manual y notifica a\nPlexa. Rate-limit: 5 solicitudes por hora por IP.","operationId":"request_removal_api_v1_businesses__id__removal_request_post","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemovalRequestCreate"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/businesses/{id}/verify/domain/start":{"post":{"tags":["businesses"],"summary":"Start Domain Verification","description":"Genera código de verificación de dominio y devuelve instrucciones.","operationId":"start_domain_verification_api_v1_businesses__id__verify_domain_start_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/businesses/{id}/verify/domain/check":{"post":{"tags":["businesses"],"summary":"Check Domain Verification","description":"Verifica si el meta tag o DNS TXT está presente.","operationId":"check_domain_verification_api_v1_businesses__id__verify_domain_check_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/businesses/{id}/verify/google-maps":{"post":{"tags":["businesses"],"summary":"Verify Google Maps","description":"El dueño vincula su negocio en Google Maps pegando el link. Resuelve el place_id\ncanónico, lo guarda (enriquece la ficha) y otorga la verificación cross_platform (+10).\nSpeed bump: prueba que el negocio existe en Maps, no propiedad estricta.","operationId":"verify_google_maps_api_v1_businesses__id__verify_google_maps_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GoogleMapsLinkRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/businesses/sitemap":{"get":{"tags":["businesses"],"summary":"Sitemap Entries","description":"Entradas de sitemap para las fichas: slug + lastmod CONTENIDO-consciente (crawlers).\n\nlastmod = GREATEST(updated_at, places_data_fetched_at, última FAQ publicada). Así el sitemap\ndice la verdad de CUÁNDO cambió el contenido de la ficha (no 'now()' global), que es la señal\nque decide el crawl budget de los motores. Ligero a propósito (no hidrata la ficha completa\ncomo el listado): un solo SELECT para las ~10k fichas que el sitemap pide cada hora.","operationId":"sitemap_entries_api_v1_businesses_sitemap_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/businesses/id/{id}":{"get":{"tags":["businesses"],"summary":"Get Business By Id","description":"Fetch a business by its UUID (public).","operationId":"get_business_by_id_api_v1_businesses_id__id__get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/businesses/{id}/verifications":{"get":{"tags":["businesses"],"summary":"Get Verifications","description":"Lista todas las verificaciones de un negocio (público).","operationId":"get_verifications_api_v1_businesses__id__verifications_get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/businesses/featured":{"get":{"tags":["businesses"],"summary":"Get Featured Businesses","description":"Negocios destacados curados a mano (is_featured=true). El homepage solo\nmuestra estos; si no hay ninguno, la sección se oculta.","operationId":"get_featured_businesses_api_v1_businesses_featured_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":12,"minimum":1,"default":6,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BusinessResponse"},"title":"Response Get Featured Businesses Api V1 Businesses Featured Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/businesses/{slug}":{"get":{"tags":["businesses"],"summary":"Get Business By Slug","operationId":"get_business_by_slug_api_v1_businesses__slug__get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/businesses/{id}/trust":{"get":{"tags":["businesses"],"summary":"Get Trust Score","operationId":"get_trust_score_api_v1_businesses__id__trust_get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrustScoreResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/faqs/published":{"get":{"tags":["faqs"],"summary":"Published Faqs","description":"Q&A publicadas agrupadas por negocio, negocios con más FAQs primero. Solo published.","operationId":"published_faqs_api_v1_faqs_published_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"description":"Máximo de negocios","default":40,"title":"Limit"},"description":"Máximo de negocios"},{"name":"per_business","in":"query","required":false,"schema":{"type":"integer","maximum":20,"minimum":1,"description":"Máximo de FAQs por negocio","default":6,"title":"Per Business"},"description":"Máximo de FAQs por negocio"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/stats":{"get":{"tags":["admin"],"summary":"Get Admin Stats","description":"Stats globales de la plataforma.","operationId":"get_admin_stats_api_v1_admin_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/businesses":{"get":{"tags":["admin"],"summary":"Admin List Businesses","description":"Lista TODOS los negocios con filtros admin. `search` = fuzzy por nombre/slug.\n`only_with_email` = solo negocios con email no vacío en su ficha (para outreach).","operationId":"admin_list_businesses_api_v1_admin_businesses_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"vertical","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vertical"}},{"name":"city","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"}},{"name":"claimed","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Claimed"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}},{"name":"source","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source"}},{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Search"}},{"name":"only_with_email","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Only With Email"}},{"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/v1/admin/businesses/{id}/status":{"put":{"tags":["admin"],"summary":"Admin Update Business Status","description":"Cambiar status de cualquier negocio.","operationId":"admin_update_business_status_api_v1_admin_businesses__id__status_put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}},{"name":"status","in":"query","required":true,"schema":{"type":"string","pattern":"^(active|suspended|archived|draft)$","title":"Status"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/businesses/{id}/refresh-places":{"post":{"tags":["admin"],"summary":"Admin Refresh Places","description":"Fase 6: refresca manualmente los campos espejo de Google (reseñas, categoría, fotos) de un\nnegocio vinculado a Maps y recomputa su audit. UN Place Details call, respeta el tope diario.\nNunca batch/cron (eso es Hermes 3.5 futuro).","operationId":"admin_refresh_places_api_v1_admin_businesses__id__refresh_places_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/businesses/{id}/chain":{"put":{"tags":["admin"],"summary":"Admin Toggle Chain","description":"Toggle manual de is_chain (override de la detección automática).","operationId":"admin_toggle_chain_api_v1_admin_businesses__id__chain_put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}},{"name":"value","in":"query","required":true,"schema":{"type":"boolean","title":"Value"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/businesses/{id}/featured":{"put":{"tags":["admin"],"summary":"Admin Toggle Featured","description":"Toggle manual de is_featured (negocios destacados del homepage, curados).","operationId":"admin_toggle_featured_api_v1_admin_businesses__id__featured_put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}},{"name":"value","in":"query","required":true,"schema":{"type":"boolean","title":"Value"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/businesses/{id}/vertical":{"put":{"tags":["admin"],"summary":"Admin Reclassify Vertical","description":"Reclasifica un negocio mal categorizado: cambia vertical y RECONSTRUYE\ncapabilities + context_hints desde el template del nuevo vertical.","operationId":"admin_reclassify_vertical_api_v1_admin_businesses__id__vertical_put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}},{"name":"value","in":"query","required":true,"schema":{"type":"string","title":"Value"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/seeding/run":{"post":{"tags":["admin"],"summary":"Start Seeding Run","description":"Iniciar barrida de Apify en background.","operationId":"start_seeding_run_api_v1_admin_seeding_run_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeedingRunCreate"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeedingRunResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/seeding/google":{"post":{"tags":["admin"],"summary":"Seed Via Google Places","description":"Seeding síncrono vía Google Places API (New). Fuente de verdad para seeding.\nEl query incluye la ubicación (ej. 'turismo Los Cabos'). Mismo servicio que\nscripts/seed_google_places.py.","operationId":"seed_via_google_places_api_v1_admin_seeding_google_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GoogleSeedRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GoogleSeedResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/seeding/config":{"get":{"tags":["admin"],"summary":"Seeding Config","description":"Opciones para los dropdowns de la barrida masiva (lee los yaml).","operationId":"seeding_config_api_v1_admin_seeding_config_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/seeding/sweep":{"post":{"tags":["admin"],"summary":"Start Sweep","description":"Barrida masiva: sinónimos × subzonas en una corrida. Crea un SeedingRun y\nejecuta en background; el admin hace polling para el progreso.","operationId":"start_sweep_api_v1_admin_seeding_sweep_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SweepRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeedingRunResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/seeding/rejections":{"get":{"tags":["admin"],"summary":"List Rejections","description":"Negocios rechazados por el filtro de calidad, paginado (20/pág) + desglose por razón.\nPor defecto excluye los descartados (dismissed); dismissed=true muestra la pestaña de\ndescartados (revisables/reversibles). El desglose respeta el filtro de vertical + dismissed.","operationId":"list_rejections_api_v1_admin_seeding_rejections_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"reason","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason"}},{"name":"vertical","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vertical"}},{"name":"dismissed","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Dismissed"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/seeding/rejections/{rejection_id}/force-insert":{"post":{"tags":["admin"],"summary":"Force Insert Rejection","description":"Override manual: inserta un negocio rechazado (bypass del filtro) y borra\nel registro de rechazo.","operationId":"force_insert_rejection_api_v1_admin_seeding_rejections__rejection_id__force_insert_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"rejection_id","in":"path","required":true,"schema":{"type":"string","title":"Rejection Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/seeding/rejections/{rejection_id}/dismiss":{"post":{"tags":["admin"],"summary":"Dismiss Rejection","description":"Descarta (soft-delete) un rechazo revisado que se decidió NO forzar: sale de la vista pero\nel registro PERSISTE, así el dedup del seeding (por place_id) no lo vuelve a presentar. Reversible.","operationId":"dismiss_rejection_api_v1_admin_seeding_rejections__rejection_id__dismiss_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"rejection_id","in":"path","required":true,"schema":{"type":"string","title":"Rejection Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/seeding/rejections/{rejection_id}/undismiss":{"post":{"tags":["admin"],"summary":"Undismiss Rejection","description":"Revierte el descarte: el rechazo vuelve a la vista de pendientes.","operationId":"undismiss_rejection_api_v1_admin_seeding_rejections__rejection_id__undismiss_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"rejection_id","in":"path","required":true,"schema":{"type":"string","title":"Rejection Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/seeding/detect-chains":{"post":{"tags":["admin"],"summary":"Detect Chains Endpoint","description":"Detecta cadenas (nombre normalizado repetido N+ veces o en known_chains).\napply=False → preview (no modifica); apply=True → marca is_chain=True.","operationId":"detect_chains_endpoint_api_v1_admin_seeding_detect_chains_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"threshold","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":2,"default":5,"title":"Threshold"}},{"name":"apply","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Apply"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/seeding/inconsistencies":{"get":{"tags":["admin"],"summary":"List Inconsistencies","description":"Reporte (NO auto-fix) de negocios cuyo nombre sugiere un vertical distinto\nal asignado. Para revisión manual + reclasificación puntual.","operationId":"list_inconsistencies_api_v1_admin_seeding_inconsistencies_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":2000,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/seeding/runs":{"get":{"tags":["admin"],"summary":"List Seeding Runs","description":"Historial de barridas.","operationId":"list_seeding_runs_api_v1_admin_seeding_runs_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SeedingRunResponse"},"title":"Response List Seeding Runs Api V1 Admin Seeding Runs Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/seeding/runs/{id}":{"get":{"tags":["admin"],"summary":"Get Seeding Run","description":"Status de una barrida específica.","operationId":"get_seeding_run_api_v1_admin_seeding_runs__id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeedingRunResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/claim-invitations/send":{"post":{"tags":["admin"],"summary":"Send Claim Invitations","description":"Envía (o simula) invitaciones de claim a negocios unclaimed con email.","operationId":"send_claim_invitations_api_v1_admin_claim_invitations_send_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"vertical","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vertical"}},{"name":"city","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"default":10,"title":"Limit"}},{"name":"dry_run","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Dry Run"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/enrichment/run":{"post":{"tags":["admin"],"summary":"Run Enrichment","description":"Enriquece fichas desde sus websites con LLM. Síncrono para lotes pequeños.","operationId":"run_enrichment_api_v1_admin_enrichment_run_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"vertical","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vertical"}},{"name":"city","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"only_unenriched","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Only Unenriched"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/enrichment/reprocess":{"post":{"tags":["admin"],"summary":"Reprocess Enrichment","description":"Re-procesa enrichment (regex→LLM) en background. Solo negocios SIN email que\nSÍ tienen website (los candidatos a resolverse barato con regex).","operationId":"reprocess_enrichment_api_v1_admin_enrichment_reprocess_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"vertical","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vertical"}},{"name":"city","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"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"}}}}}}},"/api/v1/admin/enrichment/status":{"get":{"tags":["admin"],"summary":"Enrichment Runtime Status","description":"Estado live del job controlable (badge + progreso + log de los últimos 10).","operationId":"enrichment_runtime_status_api_v1_admin_enrichment_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/enrichment/start":{"post":{"tags":["admin"],"summary":"Enrichment Start","description":"Inicia un job controlable de enrichment (pendientes con website). Si ya hay\nun job corriendo/pausado, lo rechaza (detén primero).","operationId":"enrichment_start_api_v1_admin_enrichment_start_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"vertical","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vertical"}},{"name":"city","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":1000,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/enrichment/pause":{"post":{"tags":["admin"],"summary":"Enrichment Pause","operationId":"enrichment_pause_api_v1_admin_enrichment_pause_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/enrichment/resume":{"post":{"tags":["admin"],"summary":"Enrichment Resume","operationId":"enrichment_resume_api_v1_admin_enrichment_resume_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/enrichment/stop":{"post":{"tags":["admin"],"summary":"Enrichment Stop","operationId":"enrichment_stop_api_v1_admin_enrichment_stop_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/enrichment/stats":{"get":{"tags":["admin"],"summary":"Enrichment Stats","description":"Stats de enriquecimiento.","operationId":"enrichment_stats_api_v1_admin_enrichment_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/subscriptions":{"get":{"tags":["admin"],"summary":"Admin List Subscriptions","description":"Lista de suscripciones con nombre del negocio.","operationId":"admin_list_subscriptions_api_v1_admin_subscriptions_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":300,"minimum":1,"default":100,"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/v1/admin/subscriptions/{sub_id}/cancel":{"post":{"tags":["admin"],"summary":"Admin Cancel Subscription","description":"Cancela manualmente una suscripción (MP + DB + baja tier a free).","operationId":"admin_cancel_subscription_api_v1_admin_subscriptions__sub_id__cancel_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"sub_id","in":"path","required":true,"schema":{"type":"string","title":"Sub Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/outreach/send":{"post":{"tags":["admin"],"summary":"Send Outreach","description":"Envía emails de claim a negocios unclaimed con email (dry_run por default).\nEl filtro de calidad de email vive en `_outreach_base_query()` (email real regex-only + MX +\nno-rebotado). Reemplazó al viejo `freemail_only`, que era un proxy burdo y desalineado.","operationId":"send_outreach_api_v1_admin_outreach_send_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"vertical","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vertical"}},{"name":"city","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Limit"}},{"name":"dry_run","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Dry Run"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/outreach/lookup":{"get":{"tags":["admin"],"summary":"Outreach Lookup","description":"Busca negocios por nombre para el envío individual de outreach. Devuelve si tiene\nemail, si tiene Espejo generado, y si ya fue contactado por email (salvaguarda).","operationId":"outreach_lookup_api_v1_admin_outreach_lookup_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","title":"Q"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/outreach/send-individual":{"post":{"tags":["admin"],"summary":"Send Outreach Individual","description":"Envía el Espejo por email a UN negocio (no campaña masiva). Requiere email + Espejo.\nSi ya fue contactado por email, exige force=true (salvaguarda anti re-contacto).\n\nPREVISUALIZACIÓN: con test_mode=true + recipient_override (tu email), manda el Espejo\nEXACTO del negocio (su data real) a TU correo, SIN tocar al negocio — no aplica la\nsalvaguarda, no registra envío ni marca outreach_sent_at.","operationId":"send_outreach_individual_api_v1_admin_outreach_send_individual_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"business_id","in":"query","required":true,"schema":{"type":"string","title":"Business Id"}},{"name":"force","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Force"}},{"name":"test_mode","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Test Mode"}},{"name":"recipient_override","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recipient Override"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/outreach/send-batch-mirror":{"post":{"tags":["admin"],"summary":"Send Outreach Batch Mirror","description":"Envía el ESPEJO (reporte de visibilidad) EN LOTE a los negocios del filtro — NO el\nclaim. Reusa la lógica del envío individual (`send_report_mirror` con el token de cada\nnegocio), iterando sobre N inboxes. Reglas críticas:\n- Solo negocios con Espejo generado (RadarReport).\n- DEDUP POR EMAIL: una sola vez por inbox único (varios negocios comparten info@…; no\n  se manda 2-3× al mismo buzón). Cada negocio lleva SU propio token/reporte.\n- Calidad de email: la impone `_outreach_base_query()` (real regex-only + MX + no-rebotado).\n- `limit` = nº de inboxes ÚNICOS a contactar (manda por baches).\n- Marca `outreach_sent_at`; respeta unsubscribe y (salvo `force`) negocios ya contactados.\n`dry_run` (default True) devuelve el preview sin enviar nada.","operationId":"send_outreach_batch_mirror_api_v1_admin_outreach_send_batch_mirror_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"vertical","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vertical"}},{"name":"city","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Limit"}},{"name":"dry_run","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Dry Run"}},{"name":"force","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Force"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/outreach/stats":{"get":{"tags":["admin"],"summary":"Outreach Stats","description":"Stats de outreach.","operationId":"outreach_stats_api_v1_admin_outreach_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/removal-requests":{"get":{"tags":["admin"],"summary":"List Removal Requests","description":"Lista solicitudes de eliminación (default: pendientes), con datos del negocio.","operationId":"list_removal_requests_api_v1_admin_removal_requests_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","default":"pending","title":"Status"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/removal-requests/{request_id}/approve":{"post":{"tags":["admin"],"summary":"Approve Removal Request","description":"Aprueba la solicitud y hace soft-delete del negocio (status='archived').","operationId":"approve_removal_request_api_v1_admin_removal_requests__request_id__approve_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"request_id","in":"path","required":true,"schema":{"type":"string","title":"Request Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/removal-requests/{request_id}/reject":{"post":{"tags":["admin"],"summary":"Reject Removal Request","description":"Rechaza la solicitud; el negocio permanece publicado.","operationId":"reject_removal_request_api_v1_admin_removal_requests__request_id__reject_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"request_id","in":"path","required":true,"schema":{"type":"string","title":"Request Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/faqs":{"get":{"tags":["admin"],"summary":"List Faqs For Review","description":"Lista FAQs por status (default: pending_approval) con datos del negocio + search_volume\n+ grounded_fields + motivo de rechazo. Para la vista de revisión del admin. Ordena por mayor\nsearch_volume. En 'rejected' oculta las descartadas (dismissed) salvo include_dismissed=1.","operationId":"list_faqs_for_review_api_v1_admin_faqs_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","default":"pending_approval","title":"Status"}},{"name":"include_dismissed","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Dismissed"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/faqs/stats":{"get":{"tags":["admin"],"summary":"Faq Review Stats","description":"Conteos por status + nº de negocios con pending_approval (para el header de la vista).","operationId":"faq_review_stats_api_v1_admin_faqs_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/faqs/{faq_id}/approve":{"post":{"tags":["admin"],"summary":"Approve Faq","description":"Aprueba una FAQ → status='published' + published_at. A partir de ahí la ficha la emite\n(FAQPage schema + render visible; eso ya existe, solo se activa con published).","operationId":"approve_faq_api_v1_admin_faqs__faq_id__approve_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"faq_id","in":"path","required":true,"schema":{"type":"string","title":"Faq Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/faqs/{faq_id}/reject":{"post":{"tags":["admin"],"summary":"Reject Faq","description":"Rechaza una FAQ → status='rejected' (no se publica, no emite schema). Motivo opcional del\nadmin (se guarda para la vista de Rechazadas). Reversible: mueve de estado, no borra.","operationId":"reject_faq_api_v1_admin_faqs__faq_id__reject_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"faq_id","in":"path","required":true,"schema":{"type":"string","title":"Faq Id"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/FaqReject"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/faqs/{faq_id}/unpublish":{"post":{"tags":["admin"],"summary":"Unpublish Faq","description":"Despublica una FAQ published → pending_approval (vuelve a la cola de revisión). La ficha\ndeja de emitirla en el FAQPage schema (solo se emiten published). Reversible: re-aprobar.","operationId":"unpublish_faq_api_v1_admin_faqs__faq_id__unpublish_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"faq_id","in":"path","required":true,"schema":{"type":"string","title":"Faq Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/faqs/{faq_id}/dismiss":{"post":{"tags":["admin"],"summary":"Dismiss Faq","description":"Descarta definitivo un rejected → sale de la cola de revisión (dismissed=true). Reversible\n(dismissed=false). No borra; el registro queda para auditoría.","operationId":"dismiss_faq_api_v1_admin_faqs__faq_id__dismiss_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"faq_id","in":"path","required":true,"schema":{"type":"string","title":"Faq Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/faqs/{faq_id}/reevaluate":{"post":{"tags":["admin"],"summary":"Reevaluate Faq","description":"Re-evalúa un rejected: re-genera la respuesta con los datos ACTUALES de la ficha (útil si\nganó datos vía Fase 6). Reusa el motor existente (answer_one) SIN modificarlo. Si ahora\nresponde grounded → pending_approval; si sigue sin datos → queda rejected con motivo.","operationId":"reevaluate_faq_api_v1_admin_faqs__faq_id__reevaluate_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"faq_id","in":"path","required":true,"schema":{"type":"string","title":"Faq Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/faqs/{faq_id}":{"patch":{"tags":["admin"],"summary":"Edit Faq","description":"Edita pregunta/respuesta (ES/EN) en cualquier estado (pending/published/rejected). Con\napprove=true, además publica (override manual: el admin sabe la respuesta correcta). No toca\nel pipeline ni el grounding — es edición manual con la autoridad del admin.","operationId":"edit_faq_api_v1_admin_faqs__faq_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"faq_id","in":"path","required":true,"schema":{"type":"string","title":"Faq Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FaqEdit"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/outreach/emails":{"get":{"tags":["admin"],"summary":"Outreach Emails","description":"Historial paginado de emails de outreach (20/pág), con nombre del negocio.\nFiltro opcional por status (sent/delivered/opened/clicked/bounced/error).","operationId":"outreach_emails_api_v1_admin_outreach_emails_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/outreach/test":{"post":{"tags":["admin"],"summary":"Outreach Test","description":"Envía el template de outreach a una dirección arbitraria para QA.\nNO cuenta contra el límite diario ni se registra en outreach_emails.","operationId":"outreach_test_api_v1_admin_outreach_test_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"email","in":"query","required":true,"schema":{"type":"string","minLength":5,"maxLength":254,"title":"Email"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/users":{"get":{"tags":["admin"],"summary":"List Users","description":"Lista usuarios registrados (Supabase Auth via service_role) con su conteo\nde negocios activos asociados.","operationId":"list_users_api_v1_admin_users_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/reports/{token}/sends":{"get":{"tags":["admin"],"summary":"Report Send Prefill","description":"Prefill + historial para el modal de envío. 404 si el token no existe.","operationId":"report_send_prefill_api_v1_admin_reports__token__sends_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"token","in":"path","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"}}}}}}},"/api/v1/admin/businesses/{business_id}/report-summary":{"get":{"tags":["admin"],"summary":"Business Report Summary","description":"Resumen del reporte Espejo más reciente del negocio (para el panel de /admin/radar).\nhas_report=false si nunca se generó. Read-only, reusa build_report_payload.","operationId":"business_report_summary_api_v1_admin_businesses__business_id__report_summary_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"business_id","in":"path","required":true,"schema":{"type":"string","title":"Business Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/report-sends":{"get":{"tags":["admin"],"summary":"List Report Sends","description":"Ledger global de envíos del Reporte Espejo (todos los negocios).","operationId":"list_report_sends_api_v1_admin_report_sends_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/reports/{token}/send-email":{"post":{"tags":["admin"],"summary":"Send Report Email","description":"Envía el Reporte Espejo por email vía Resend y lo registra en report_sends.","operationId":"send_report_email_api_v1_admin_reports__token__send_email_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportSendRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/visibility-report/{business_id}/regenerate":{"post":{"tags":["admin"],"summary":"Regenerate Visibility Report","description":"Radar v2: recalcula las 6 métricas del Reporte de Visibilidad para un negocio\ndesde la evidencia del Radar (radar_responses/mentions). Persiste en visibility_metrics.","operationId":"regenerate_visibility_report_api_v1_admin_visibility_report__business_id__regenerate_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"business_id","in":"path","required":true,"schema":{"type":"string","title":"Business Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/visibility-report/{business_id}":{"get":{"tags":["admin"],"summary":"Get Visibility Report","description":"Payload agregado del Reporte de Visibilidad para el dashboard (6 métricas +\nbenchmark + co-mention + queries + oportunidades).","operationId":"get_visibility_report_api_v1_admin_visibility_report__business_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"business_id","in":"path","required":true,"schema":{"type":"string","title":"Business Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/visibility-report/{business_id}/send":{"post":{"tags":["admin"],"summary":"Send Visibility Report Single","description":"Envía el Reporte de Visibilidad por email a UN destinatario. Rate-limit 50/h.\nPor defecto test_mode=True. NO dispara nada masivo.","operationId":"send_visibility_report_single_api_v1_admin_visibility_report__business_id__send_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"business_id","in":"path","required":true,"schema":{"type":"string","title":"Business Id"}},{"name":"recipient_email","in":"query","required":true,"schema":{"type":"string","description":"Destinatario","title":"Recipient Email"},"description":"Destinatario"},{"name":"test_mode","in":"query","required":false,"schema":{"type":"boolean","description":"Marca [TEST] en el asunto","default":true,"title":"Test Mode"},"description":"Marca [TEST] en el asunto"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/visibility-report/batch-send":{"post":{"tags":["admin"],"summary":"Send Visibility Report Batch","description":"Envío a una LISTA EXPLÍCITA de business_ids (no hay filtro 'todos' para evitar\nmasivos accidentales). Cada uno usa el email del negocio salvo recipient_override.\nRate-limit 50/h compartido.","operationId":"send_visibility_report_batch_api_v1_admin_visibility_report_batch_send_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"recipient_override","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Si se da, todos van a este correo (test)","title":"Recipient Override"},"description":"Si se da, todos van a este correo (test)"},{"name":"test_mode","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Test Mode"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"array","items":{"type":"string"},"title":"Business Ids"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/visibility-report-sends":{"get":{"tags":["admin"],"summary":"List Visibility Sends","description":"Log de envíos del Reporte de Visibilidad (para el admin).","operationId":"list_visibility_sends_api_v1_admin_visibility_report_sends_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/webhooks/mercadopago":{"post":{"tags":["webhooks"],"summary":"Mercadopago Webhook","description":"Notificaciones de MercadoPago. Siempre 200.","operationId":"mercadopago_webhook_api_v1_webhooks_mercadopago_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/webhooks/resend":{"post":{"tags":["webhooks"],"summary":"Resend Webhook","description":"Tracking de emails de Resend (delivered/opened/clicked/bounced). Siempre 200.","operationId":"resend_webhook_api_v1_webhooks_resend_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/outreach/unsubscribe":{"post":{"tags":["outreach"],"summary":"Unsubscribe","description":"Marca todos los negocios con ese email como no-contactar (CAN-SPAM).","operationId":"unsubscribe_api_v1_outreach_unsubscribe_post","parameters":[{"name":"email","in":"query","required":true,"schema":{"type":"string","title":"Email"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/radar/combos":{"get":{"tags":["radar-admin"],"summary":"Radar Combos","operationId":"radar_combos_api_v1_admin_radar_combos_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/radar/reports":{"get":{"tags":["radar-admin"],"summary":"Radar List Reports","operationId":"radar_list_reports_api_v1_admin_radar_reports_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/radar/reports/{token}/dismiss":{"post":{"tags":["radar-admin"],"summary":"Radar Report Dismiss","description":"Descarta (soft-delete) el espejo del negocio: sale de la cola/vista, el registro persiste.","operationId":"radar_report_dismiss_api_v1_admin_radar_reports__token__dismiss_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"token","in":"path","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"}}}}}}},"/api/v1/admin/radar/reports/{token}/undismiss":{"post":{"tags":["radar-admin"],"summary":"Radar Report Undismiss","description":"Restaura un espejo descartado → vuelve a la vista.","operationId":"radar_report_undismiss_api_v1_admin_radar_reports__token__undismiss_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"token","in":"path","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"}}}}}}},"/api/v1/admin/radar/combos/generate":{"post":{"tags":["radar-admin"],"summary":"Radar Combo Generate","description":"Genera con el LLM un combo CANDIDATO (draft) para vertical×ciudad. `population` controla si\nes genérico ('vertical', default) o de sub-giro ('subgiro:X', con X un sub-giro REAL del\nvertical). El LLM solo PROPONE queries; queda draft (no corrible) hasta aprobación humana.","operationId":"radar_combo_generate_api_v1_admin_radar_combos_generate_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"vertical","in":"query","required":true,"schema":{"type":"string","title":"Vertical"}},{"name":"city","in":"query","required":true,"schema":{"type":"string","title":"City"}},{"name":"population","in":"query","required":false,"schema":{"type":"string","default":"vertical","title":"Population"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/radar/combos/draft":{"get":{"tags":["radar-admin"],"summary":"Radar Combo Draft","description":"Combo draft del vertical×ciudad (para revisar/aprobar), o 404 si no hay.","operationId":"radar_combo_draft_api_v1_admin_radar_combos_draft_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"vertical","in":"query","required":true,"schema":{"type":"string","title":"Vertical"}},{"name":"city","in":"query","required":true,"schema":{"type":"string","title":"City"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/radar/combos/drafts":{"get":{"tags":["radar-admin"],"summary":"Radar Combos Drafts","description":"Lista TODOS los combos draft (para la bandeja de pendientes del Inicio). Compacto:\nmetadata + población + nº de queries. El detalle con chips se trae por /combos/draft.","operationId":"radar_combos_drafts_api_v1_admin_radar_combos_drafts_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/radar/combos/overview":{"get":{"tags":["radar-admin"],"summary":"Radar Combos Overview","description":"Lista unificada para la vista de Combos: draft + approved (excluye archived), con población,\nnº de queries y last_run (último Radar completado del combo). Además zonas con densidad de\nnegocios pero SIN combo (status sintético 'none') para ver huecos de cobertura. Solo consolida\ndatos existentes — no toca la lógica de combos.","operationId":"radar_combos_overview_api_v1_admin_radar_combos_overview_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/radar/combos/{combo_id}":{"patch":{"tags":["radar-admin"],"summary":"Radar Combo Update","description":"Edita un combo DRAFT (queries/persona/idioma/location). Solo drafts.","operationId":"radar_combo_update_api_v1_admin_radar_combos__combo_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"combo_id","in":"path","required":true,"schema":{"type":"string","title":"Combo Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_radar_combo_update_api_v1_admin_radar_combos__combo_id__patch"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/radar/combos/{combo_id}/approve":{"post":{"tags":["radar-admin"],"summary":"Radar Combo Approve","description":"Aprueba un draft → status=approved → corrible (refresca el caché). El guard es por\n(vertical, ciudad, POBLACIÓN): distintos sub-giros (o genérico vs sub-giro) COEXISTEN en una\nciudad, cada uno midiendo su población. Solo dispara 409 si ya hay un aprobado de la MISMA\npoblación (salvo replace=true, que ARCHIVA el viejo — reversible).","operationId":"radar_combo_approve_api_v1_admin_radar_combos__combo_id__approve_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"combo_id","in":"path","required":true,"schema":{"type":"string","title":"Combo Id"}},{"name":"replace","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Replace"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/radar/combos/{combo_id}/archive":{"post":{"tags":["radar-admin"],"summary":"Radar Combo Archive","description":"Rechaza/retira un combo → status='archived'. Reversible (el registro queda; se puede\nreponer a draft). Saca el draft de /combos/drafts → baja el contador 'Requiere tu atención';\nsi estaba aprobado, sale del caché de corribles. Para el combo malo de raíz.","operationId":"radar_combo_archive_api_v1_admin_radar_combos__combo_id__archive_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"combo_id","in":"path","required":true,"schema":{"type":"string","title":"Combo Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/radar/combos/cities":{"get":{"tags":["radar-admin"],"summary":"Radar Combo Cities","description":"Ciudades del catálogo (seeding_cities) con su país, para el dropdown de 'Corregir ciudad':\nfuerza elegir una ciudad DESAMBIGUADA (city + region_code explícitos) en vez de un nombre a\nsecas que caiga al homónimo mexicano.","operationId":"radar_combo_cities_api_v1_admin_radar_combos_cities_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/radar/combos/{combo_id}/reassign-city":{"post":{"tags":["radar-admin"],"summary":"Radar Combo Reassign City","description":"Corrige la ciudad de un combo DRAFT: la reasigna a una ciudad EXPLÍCITA del catálogo\n(city + region_code, sin ambigüedad de topónimo) y re-genera sus queries con el país correcto\n— SIN ir a Radar (no corre medición paga). Reusa el generador ya fixeado con region_code\nexplícito. El resultado queda draft (para revisar/aprobar). Si el original persiste con otro\nkey (ciudad realmente distinta), lo archiva (reversible).","operationId":"radar_combo_reassign_city_api_v1_admin_radar_combos__combo_id__reassign_city_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"combo_id","in":"path","required":true,"schema":{"type":"string","title":"Combo Id"}},{"name":"city","in":"query","required":true,"schema":{"type":"string","title":"City"}},{"name":"region_code","in":"query","required":true,"schema":{"type":"string","title":"Region Code"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/radar/run":{"post":{"tags":["radar-admin"],"summary":"Radar Run","description":"Crea un run por superficie del combo y los corre en background. `surface` opcional: si se\nda (ej. 'google_ai'), corre SOLO esa superficie; si no, las configuradas del combo. NOTA: con\nSERP_API_KEY/OPENAI_API_KEY en placeholder, los runs corren completos pero las respuestas\nquedan con error (sin datos reales) — listo para cuando lleguen keys.","operationId":"radar_run_api_v1_admin_radar_run_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"combo","in":"query","required":true,"schema":{"type":"string","title":"Combo"}},{"name":"surface","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Surface"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/radar/runs":{"get":{"tags":["radar-admin"],"summary":"Radar Runs","operationId":"radar_runs_api_v1_admin_radar_runs_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/radar/runs/{run_id}":{"get":{"tags":["radar-admin"],"summary":"Radar Run Detail","description":"Detalle para el gate T2: respuestas + menciones (raw_name, matched, excerpt).","operationId":"radar_run_detail_api_v1_admin_radar_runs__run_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","title":"Run Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/radar/report":{"post":{"tags":["radar-admin"],"summary":"Radar Generate Report","description":"Genera un token de reporte para un negocio sobre un combo. Usa el último\nrun existente del combo (T3.3).","operationId":"radar_generate_report_api_v1_admin_radar_report_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"business_id","in":"query","required":true,"schema":{"type":"string","title":"Business Id"}},{"name":"combo","in":"query","required":true,"schema":{"type":"string","title":"Combo"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/radar/funnel":{"get":{"tags":["radar-admin"],"summary":"Outreach Funnel","description":"Embudo de outreach end-to-end por campaña: enviados → entregados → abiertos → clicados →\nEspejo visto → reclamado, con tasas entre saltos. Filtrable por vertical/ciudad para comparar\ncombos (dental-tijuana vs turismo-cabo). 'opened'/'clicked' dependen del tracking de Resend\n(open/click); si están en 0 globalmente, ese tracking no está activado en Resend.","operationId":"outreach_funnel_api_v1_admin_radar_funnel_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"vertical","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vertical"}},{"name":"city","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/reporte/{token}":{"get":{"tags":["radar-report"],"summary":"Get Report","operationId":"get_report_api_v1_reporte__token__get","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}},{"name":"preview","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Preview"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/radar/combo-teaser":{"get":{"tags":["radar-public"],"summary":"Combo Teaser Endpoint","description":"Teaser público del espejo para el alta (B1): resumen agregado del ÚLTIMO run completado del\ncombo (vertical, ciudad). Cacheado 1h en Redis; rate-limit ligero por IP. Sin combo/datos →\n{has_data: false}. Solo LEE las tablas del Radar; no toca el espejo ni el scoring.","operationId":"combo_teaser_endpoint_api_v1_radar_combo_teaser_get","parameters":[{"name":"vertical","in":"query","required":true,"schema":{"type":"string","maxLength":40,"title":"Vertical"}},{"name":"city","in":"query","required":true,"schema":{"type":"string","maxLength":80,"title":"City"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/reporte-visibilidad/{token}":{"get":{"tags":["visibility-report"],"summary":"Public Visibility Report","operationId":"public_visibility_report_api_v1_reporte_visibilidad__token__get","parameters":[{"name":"token","in":"path","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"}}}}}}},"/api/v1/reporte-visibilidad/{token}/abierto.gif":{"get":{"tags":["visibility-report"],"summary":"Open Pixel","description":"Pixel de apertura: marca opened_at en el último envío del token.","operationId":"open_pixel_api_v1_reporte_visibilidad__token__abierto_gif_get","parameters":[{"name":"token","in":"path","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"}}}}}}},"/api/v1/insights":{"get":{"tags":["insights"],"summary":"List Insights","operationId":"list_insights_api_v1_insights_get","parameters":[{"name":"lang","in":"query","required":false,"schema":{"type":"string","default":"es","title":"Lang"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/insights/{slug}":{"get":{"tags":["insights"],"summary":"Get Insight","operationId":"get_insight_api_v1_insights__slug__get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"lang","in":"query","required":false,"schema":{"type":"string","default":"es","title":"Lang"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/insights":{"get":{"tags":["admin-insights"],"summary":"Admin List","operationId":"admin_list_api_v1_admin_insights_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]},"post":{"tags":["admin-insights"],"summary":"Admin Create","operationId":"admin_create_api_v1_admin_insights_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArticleIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/admin/insights/{article_id}":{"get":{"tags":["admin-insights"],"summary":"Admin Get","operationId":"admin_get_api_v1_admin_insights__article_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"article_id","in":"path","required":true,"schema":{"type":"string","title":"Article Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["admin-insights"],"summary":"Admin Update","operationId":"admin_update_api_v1_admin_insights__article_id__put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"article_id","in":"path","required":true,"schema":{"type":"string","title":"Article Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArticleIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/insights/{article_id}/publish":{"post":{"tags":["admin-insights"],"summary":"Admin Publish","operationId":"admin_publish_api_v1_admin_insights__article_id__publish_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"article_id","in":"path","required":true,"schema":{"type":"string","title":"Article Id"}},{"name":"published","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Published"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/index":{"get":{"tags":["plexa-index"],"summary":"List Combos","operationId":"list_combos_api_v1_index_get","parameters":[{"name":"lang","in":"query","required":false,"schema":{"type":"string","default":"es","title":"Lang"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/index/{slug}":{"get":{"tags":["plexa-index"],"summary":"Get Index","operationId":"get_index_api_v1_index__slug__get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"lang","in":"query","required":false,"schema":{"type":"string","default":"es","title":"Lang"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/index/lead":{"post":{"tags":["plexa-index"],"summary":"Submit Lead","operationId":"submit_lead_api_v1_index_lead_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeadIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/index/snapshot":{"post":{"tags":["admin-index"],"summary":"Snapshot All","description":"Toma snapshot del ranking actual de TODOS los combos publicables (baseline del trend).\nLa cobertura sale de la DB (share-of-voice), no de un dict — crece con cada run del Radar.","operationId":"snapshot_all_api_v1_admin_index_snapshot_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/api/v1/aeo/verticals":{"get":{"tags":["aeo"],"summary":"List Verticals","description":"Verticales que hoy publican página AEO (sitemap + footer). Derivado de la DB.","operationId":"list_verticals_api_v1_aeo_verticals_get","parameters":[{"name":"lang","in":"query","required":false,"schema":{"type":"string","default":"es","title":"Lang"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/aeo/{vertical}":{"get":{"tags":["aeo"],"summary":"Get Vertical","operationId":"get_vertical_api_v1_aeo__vertical__get","parameters":[{"name":"vertical","in":"path","required":true,"schema":{"type":"string","title":"Vertical"}},{"name":"lang","in":"query","required":false,"schema":{"type":"string","default":"es","title":"Lang"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/espejo/self-serve":{"post":{"tags":["espejo-selfserve"],"summary":"Espejo Self Serve","description":"Entrega en pantalla lo que YA existe (o encola). Nunca corre Radar on-demand.","operationId":"espejo_self_serve_api_v1_espejo_self_serve_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SelfServeIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/espejo/self-serve/status":{"get":{"tags":["espejo-selfserve"],"summary":"Espejo Self Serve Status","description":"Polling de la sala de espera: estado de la solicitud + link cuando esté listo.\nready → redirect al reporte; generating/pending → seguir esperando; none → sin solicitud.","operationId":"espejo_self_serve_status_api_v1_espejo_self_serve_status_get","parameters":[{"name":"business_id","in":"query","required":true,"schema":{"type":"string","description":"business_id de la solicitud","title":"Business Id"},"description":"business_id de la solicitud"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/selfserve/requests":{"get":{"tags":["espejo-selfserve-admin"],"summary":"Selfserve Requests List","description":"Cola de solicitudes self-serve (Caso B) para envío MANUAL. El cron marca 'ready' + token;\nChristian revisa y manda a mano. Incluye nombre/ciudad del negocio y contacto capturado.","operationId":"selfserve_requests_list_api_v1_admin_selfserve_requests_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"pending | ready (default: todas)","title":"Status"},"description":"pending | ready (default: todas)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/selfserve/stats":{"get":{"tags":["espejo-selfserve-admin"],"summary":"Selfserve Stats","description":"Medición del canal inbound: solicitudes por caso (A/B/C, contadores Redis) + estado de la\ncola B (pending/ready) + conversión a claim de los negocios que llegaron por self-serve.","operationId":"selfserve_stats_api_v1_admin_selfserve_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/health":{"get":{"tags":["health"],"summary":"Health Check","operationId":"health_check_v1_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/me":{"get":{"tags":["auth"],"summary":"Get Me","operationId":"get_me_v1_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/search":{"get":{"tags":["search"],"summary":"Search Businesses","operationId":"search_businesses_v1_search_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Q"}},{"name":"vertical","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vertical"}},{"name":"city","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"}},{"name":"state","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"State"}},{"name":"country","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country"}},{"name":"lat","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lat"}},{"name":"lng","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lng"}},{"name":"radius_km","in":"query","required":false,"schema":{"type":"number","default":15,"title":"Radius Km"}},{"name":"lang","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lang"}},{"name":"capabilities","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Capabilities"}},{"name":"min_trust_score","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Min Trust Score"}},{"name":"claimed","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Claimed"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"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":{"$ref":"#/components/schemas/SearchResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/verticals":{"get":{"tags":["verticals"],"summary":"List Verticals","operationId":"list_verticals_v1_verticals_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Response List Verticals V1 Verticals Get"}}}}}}},"/v1/directories/filters":{"get":{"tags":["directories"],"summary":"Directory Filters","operationId":"directory_filters_v1_directories_filters_get","parameters":[{"name":"vertical","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vertical"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/directories/combos":{"get":{"tags":["directories"],"summary":"Directory Combos","description":"Combos vertical×ciudad con al menos `min` negocios activos, con su conteo y la fecha de\nactualización más reciente. Para el sitemap: solo lista páginas de directorio NO vacías\n(≥min negocios reales) con `lastmod` real (max updated_at del combo). Read-only, cache 5 min.","operationId":"directory_combos_v1_directories_combos_get","parameters":[{"name":"min","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"default":3,"title":"Min"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/stats/public":{"get":{"tags":["stats"],"summary":"Public Stats","description":"Stats públicas para la landing. Cache Redis 5 min. Degradación graceful.","operationId":"public_stats_v1_stats_public_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/stats/crawler-visit":{"post":{"tags":["stats"],"summary":"Log Crawler Visit","description":"Registra visita de bot IA (llamado por el middleware de Next.js).\nRate limit 100/min por IP. Fire-and-forget: nunca rompe.","operationId":"log_crawler_visit_v1_stats_crawler_visit_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrawlerVisitRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/stats/crawler-activity":{"get":{"tags":["stats"],"summary":"Crawler Activity","description":"Actividad de bots IA en Plexa (últimos 30 días). Cache Redis 5 min.","operationId":"crawler_activity_v1_stats_crawler_activity_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/stats/crawler-activity/{bot_name}/details":{"get":{"tags":["stats"],"summary":"Crawler Activity Details","description":"Últimas visitas de un bot específico (para el dropdown del feed), sin filtro\nde fecha: siempre las N más recientes (hoy, ayer o la semana pasada). Máx 10 por default.","operationId":"crawler_activity_details_v1_stats_crawler_activity__bot_name__details_get","parameters":[{"name":"bot_name","in":"path","required":true,"schema":{"type":"string","title":"Bot Name"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"default":10,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/stats/crawler-activity/recent":{"get":{"tags":["stats"],"summary":"Crawler Activity Recent","description":"Últimas N lecturas GLOBALES (cualquier bot != unknown) para el live-log del feed terminal.\nAlimenta SOLO datos reales — si viene vacío, el front oculta el log (nunca inventa líneas).\nCache Redis corta (30s) para que el 'en vivo' sea creíble sin martillar la DB.","operationId":"crawler_activity_recent_v1_stats_crawler_activity_recent_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":20,"minimum":1,"default":8,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/study/latest":{"get":{"tags":["stats"],"summary":"Study Latest","description":"Última edición del Índice de Visibilidad IA (estudio agregado) — público, cacheado 300s.\nNúmeros REALES persistidos por el cron quincenal (study_snapshots). 404 si no hay ediciones.","operationId":"study_latest_v1_study_latest_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/stats/recent-listings":{"get":{"tags":["stats"],"summary":"Recent Listings","description":"Últimos N negocios INDEXADOS en el registro (created_at DESC, activos, sin artefactos de\nprueba) para el terminal 'el registro crece' del home. Es COBERTURA del directorio público\ncreciendo por el seeding (nosotros indexando) — NO negocios que se registran. Todo dato ya\npúblico (nombre/giro/ciudad). Cache 60s + rate-limit anónimo estándar.","operationId":"recent_listings_v1_stats_recent_listings_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":20,"minimum":1,"default":10,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/builders/register":{"post":{"tags":["builders"],"summary":"Register Builder","description":"Crea una API key gratuita (free tier: 5K queries/mes, 60 req/min).","operationId":"register_builder_v1_builders_register_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BuilderRegisterRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/builders/me":{"get":{"tags":["builders"],"summary":"My Builder Keys","description":"Lista las API keys del usuario (key enmascarada).","operationId":"my_builder_keys_v1_builders_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/builders/usage":{"get":{"tags":["builders"],"summary":"My Usage","description":"Uso del mes actual por API key.","operationId":"my_usage_v1_builders_usage_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/builders/api-keys/{key_id}":{"delete":{"tags":["builders"],"summary":"Revoke Key","description":"Revoca (desactiva) una API key del usuario.","operationId":"revoke_key_v1_builders_api_keys__key_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"string","title":"Key Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/businesses/{id}/queries":{"get":{"tags":["businesses"],"summary":"Get Business Queries","description":"Queries agénticas a este negocio (solo owner).","operationId":"get_business_queries_v1_businesses__id__queries_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":1,"default":30,"title":"Days"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"default":10,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/businesses/{id}/analytics":{"get":{"tags":["businesses"],"summary":"Business Analytics","description":"Visibilidad: consultas este mes vs anterior, agentes, recientes (solo owner).\n\nFuente = crawler_visits (NO agent_queries): la identidad real del agente que\nvisita la ficha vive ahí (capturada en el edge de Next por business_id).\nagent_queries está dominada por el SSR server-to-server de Next (UA node), que\nno es un agente externo. Se excluye bot_name='unknown' (curl/node/sin clasificar)\ndel conteo y de la lista para que el dueño solo vea agentes reales identificados.","operationId":"business_analytics_v1_businesses__id__analytics_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/businesses/{id}/recommendations":{"get":{"tags":["businesses"],"summary":"Get Recommendations","description":"Recomendaciones accionables para completar el perfil (solo owner).","operationId":"get_recommendations_v1_businesses__id__recommendations_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/businesses/{id}/action-plan":{"get":{"tags":["businesses"],"summary":"Get Action Plan","description":"Plan de Acción del negocio para el hub 'Mejora tu visibilidad' (solo owner). Gateado por\ntier DENTRO de build_action_plan_section (reusa _PAID_TIERS): connected/pro ve los items\n(why + mecanismo + queries), free ve solo gaps_count. Genera al vuelo si falta (lazy).","operationId":"get_action_plan_v1_businesses__id__action_plan_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/businesses/{id}/geo-audit":{"get":{"tags":["businesses"],"summary":"Get Geo Audit","description":"Auditoría de citabilidad (GEO Nivel 1) del negocio (solo owner). Devuelve el audit\nACTUAL (última fila persistida); si no existe todavía, lo calcula y persiste (lazy).\nEnriquecido para el panel: lecturas de IA reales (crawler_visits) + percentil del score.\n404 si el gate maestro está apagado.","operationId":"get_geo_audit_v1_businesses__id__geo_audit_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/businesses/{id}/crawler-visits":{"get":{"tags":["businesses"],"summary":"Get Crawler Visits","description":"Drill-down de las lecturas de crawler de IA de la ficha (solo owner): las visitas reales\n(URL, hora, IP, UA) con VERIFICACIÓN contra el rango oficial del crawler. `verified=true` SOLO\nsi la IP cae en un rango oficial publicado del bot — jamás un badge falso (honestidad = producto).\nFiltra por `bot` (nombre agrupado) opcional. Reusa run/agent_type='crawler', excluye 'unknown'.","operationId":"get_crawler_visits_v1_businesses__id__crawler_visits_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}},{"name":"bot","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bot"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":30,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/businesses/{slug}/ask":{"post":{"tags":["businesses"],"summary":"Ask Agent About Business","description":"Un LLM responde sobre el negocio, grounded SOLO en su ficha (cero alucinación por diseño).\n404 si CHAT_ASK_ENABLED está apagado (gate de rollout). Rate-limit por IP (protección de tokens).","operationId":"ask_agent_about_business_v1_businesses__slug__ask_post","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AskRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/businesses/import/places-lookup":{"get":{"tags":["businesses"],"summary":"Import Places Lookup","description":"Busca el negocio en Google Places (Text Search, misma infra que el seeding) para pre-llenar el\nalta. 'Esto es lo que la IA ya ve de ti' — el dueño elige el resultado correcto (resuelve\nhomónimos con selección humana). Auth + rate-limit por usuario (las búsquedas de Places cuestan).","operationId":"import_places_lookup_v1_businesses_import_places_lookup_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"name","in":"query","required":true,"schema":{"type":"string","title":"Name"}},{"name":"vertical","in":"query","required":false,"schema":{"type":"string","default":"other","title":"Vertical"}},{"name":"city","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/businesses/{id}/faqs":{"get":{"tags":["businesses"],"summary":"List My Faqs","description":"FAQs del negocio (solo owner): publicadas + pendientes de aprobar. `can_manage` =\nConnected (generar/aprobar). Para el hub de FAQs en el dashboard del dueño.","operationId":"list_my_faqs_v1_businesses__id__faqs_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/businesses/{id}/faqs/generate":{"post":{"tags":["businesses"],"summary":"Generate My Faqs","description":"Dispara la generación de FAQs para el negocio (on-demand, Connected). Corre en background\n(LLM); el dueño refresca para ver las sugeridas en pending_approval.","operationId":"generate_my_faqs_v1_businesses__id__faqs_generate_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/businesses/{id}/faqs/{faq_id}/approve":{"post":{"tags":["businesses"],"summary":"Approve My Faq","description":"El dueño aprueba su FAQ → published (Connected). La ficha emite FAQPage.","operationId":"approve_my_faq_v1_businesses__id__faqs__faq_id__approve_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}},{"name":"faq_id","in":"path","required":true,"schema":{"type":"string","title":"Faq Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/businesses/{id}/faqs/{faq_id}/reject":{"post":{"tags":["businesses"],"summary":"Reject My Faq","description":"El dueño rechaza su FAQ → rejected (no se publica).","operationId":"reject_my_faq_v1_businesses__id__faqs__faq_id__reject_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}},{"name":"faq_id","in":"path","required":true,"schema":{"type":"string","title":"Faq Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/businesses/{id}/faqs/{faq_id}":{"patch":{"tags":["businesses"],"summary":"Edit My Faq","description":"El dueño edita su FAQ antes de aprobar (solo pending_approval).","operationId":"edit_my_faq_v1_businesses__id__faqs__faq_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}},{"name":"faq_id","in":"path","required":true,"schema":{"type":"string","title":"Faq Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OwnerFaqEdit"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/businesses/{id}/competitive":{"get":{"tags":["businesses"],"summary":"Competitive Insights","description":"Comparación con la competencia del mismo vertical+ciudad (solo Connected).","operationId":"competitive_insights_v1_businesses__id__competitive_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/businesses/{id}/subscription":{"get":{"tags":["businesses"],"summary":"Get Subscription","description":"Estado de la suscripción del negocio (solo owner).","operationId":"get_subscription_v1_businesses__id__subscription_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["businesses"],"summary":"Cancel Subscription","description":"Cancela la suscripción en MP y baja el negocio a Free (solo owner).","operationId":"cancel_subscription_v1_businesses__id__subscription_delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/businesses/{id}/upgrade":{"post":{"tags":["businesses"],"summary":"Upgrade Business","description":"Crea una suscripción Connected en MercadoPago y retorna el checkout_url (solo owner).","operationId":"upgrade_business_v1_businesses__id__upgrade_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/businesses/me":{"get":{"tags":["businesses"],"summary":"Get My Businesses","operationId":"get_my_businesses_v1_businesses_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/BusinessResponse"},"type":"array","title":"Response Get My Businesses V1 Businesses Me Get"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/businesses/me/visibility-reports":{"get":{"tags":["businesses"],"summary":"Get My Visibility Reports","description":"Para el dashboard cliente: por cada negocio del usuario, indica si ya tiene\nReporte de Visibilidad generado (visibility_metrics) y su URL pública por token.\nNo genera token para negocios sin reporte.","operationId":"get_my_visibility_reports_v1_businesses_me_visibility_reports_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/businesses/me/espejos":{"get":{"tags":["businesses"],"summary":"Get My Espejos","description":"Para el dashboard cliente: por cada negocio del usuario con Espejo generado (radar_reports\nno-suppressed), su link a /reporte/[token] (el dueño claimed lo ve COMPLETO, sin blur). El Espejo\n(foto de mercado/outreach) es pipeline APARTE del Reporte de Visibilidad (panel mensual del\ndueño) — esto es solo ACCESO de lectura, no una fusión. Negocio sin Espejo → no aparece.","operationId":"get_my_espejos_v1_businesses_me_espejos_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/businesses/":{"post":{"tags":["businesses"],"summary":"Create Business","operationId":"create_business_v1_businesses__post","security":[{"HTTPBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["businesses"],"summary":"List Businesses","operationId":"list_businesses_v1_businesses__get","parameters":[{"name":"vertical","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vertical"}},{"name":"city","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"}},{"name":"claimed","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Claimed"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"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":{"$ref":"#/components/schemas/BusinessListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/businesses/{id}/claim":{"post":{"tags":["businesses"],"summary":"Claim Business","description":"Reclamar un negocio comprobando el teléfono registrado.\n\nEl usuario ingresa el teléfono completo del negocio; se normaliza a E.164 y\nse compara con el registrado. Si coincide, el claim es instantáneo. Máximo\n3 intentos fallidos por usuario+negocio; tras eso, bloqueo de 24h.","operationId":"claim_business_v1_businesses__id__claim_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClaimRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/businesses/{id}/verify/email":{"post":{"tags":["businesses"],"summary":"Verify Email Self","description":"Otorga verificación de email al dueño autenticado. Tener sesión Supabase\nválida implica email confirmado. Útil para negocios creados antes de Fase 4\n(cuando auto_verify_email aún no existía).","operationId":"verify_email_self_v1_businesses__id__verify_email_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/businesses/{id}":{"put":{"tags":["businesses"],"summary":"Update Business","operationId":"update_business_v1_businesses__id__put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["businesses"],"summary":"Delete Business","description":"Soft-delete del propio negocio. Cancela la suscripción activa (MP) y\ndesvincula la ficha del dueño. Restaurable desde admin.","operationId":"delete_business_v1_businesses__id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/businesses/{id}/publish":{"post":{"tags":["businesses"],"summary":"Publish Business","operationId":"publish_business_v1_businesses__id__publish_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/businesses/{id}/unlink":{"post":{"tags":["businesses"],"summary":"Unlink Business","description":"Desvincula el negocio de la cuenta del dueño SIN eliminarlo.\n\nVuelve a estado unclaimed: sigue visible públicamente en el directorio, pero\ndeja de estar asociado a la cuenta. Cancela la suscripción activa si tiene.","operationId":"unlink_business_v1_businesses__id__unlink_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/businesses/{id}/removal-request":{"post":{"tags":["businesses"],"summary":"Request Removal","description":"Solicitud pública de eliminación de una ficha (no requiere auth).\n\nNO elimina nada: crea un registro pendiente de revisión manual y notifica a\nPlexa. Rate-limit: 5 solicitudes por hora por IP.","operationId":"request_removal_v1_businesses__id__removal_request_post","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemovalRequestCreate"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/businesses/{id}/verify/domain/start":{"post":{"tags":["businesses"],"summary":"Start Domain Verification","description":"Genera código de verificación de dominio y devuelve instrucciones.","operationId":"start_domain_verification_v1_businesses__id__verify_domain_start_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/businesses/{id}/verify/domain/check":{"post":{"tags":["businesses"],"summary":"Check Domain Verification","description":"Verifica si el meta tag o DNS TXT está presente.","operationId":"check_domain_verification_v1_businesses__id__verify_domain_check_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/businesses/{id}/verify/google-maps":{"post":{"tags":["businesses"],"summary":"Verify Google Maps","description":"El dueño vincula su negocio en Google Maps pegando el link. Resuelve el place_id\ncanónico, lo guarda (enriquece la ficha) y otorga la verificación cross_platform (+10).\nSpeed bump: prueba que el negocio existe en Maps, no propiedad estricta.","operationId":"verify_google_maps_v1_businesses__id__verify_google_maps_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GoogleMapsLinkRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/businesses/sitemap":{"get":{"tags":["businesses"],"summary":"Sitemap Entries","description":"Entradas de sitemap para las fichas: slug + lastmod CONTENIDO-consciente (crawlers).\n\nlastmod = GREATEST(updated_at, places_data_fetched_at, última FAQ publicada). Así el sitemap\ndice la verdad de CUÁNDO cambió el contenido de la ficha (no 'now()' global), que es la señal\nque decide el crawl budget de los motores. Ligero a propósito (no hidrata la ficha completa\ncomo el listado): un solo SELECT para las ~10k fichas que el sitemap pide cada hora.","operationId":"sitemap_entries_v1_businesses_sitemap_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/businesses/id/{id}":{"get":{"tags":["businesses"],"summary":"Get Business By Id","description":"Fetch a business by its UUID (public).","operationId":"get_business_by_id_v1_businesses_id__id__get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/businesses/{id}/verifications":{"get":{"tags":["businesses"],"summary":"Get Verifications","description":"Lista todas las verificaciones de un negocio (público).","operationId":"get_verifications_v1_businesses__id__verifications_get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/businesses/featured":{"get":{"tags":["businesses"],"summary":"Get Featured Businesses","description":"Negocios destacados curados a mano (is_featured=true). El homepage solo\nmuestra estos; si no hay ninguno, la sección se oculta.","operationId":"get_featured_businesses_v1_businesses_featured_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":12,"minimum":1,"default":6,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BusinessResponse"},"title":"Response Get Featured Businesses V1 Businesses Featured Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/businesses/{slug}":{"get":{"tags":["businesses"],"summary":"Get Business By Slug","operationId":"get_business_by_slug_v1_businesses__slug__get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/businesses/{id}/trust":{"get":{"tags":["businesses"],"summary":"Get Trust Score","operationId":"get_trust_score_v1_businesses__id__trust_get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrustScoreResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/faqs/published":{"get":{"tags":["faqs"],"summary":"Published Faqs","description":"Q&A publicadas agrupadas por negocio, negocios con más FAQs primero. Solo published.","operationId":"published_faqs_v1_faqs_published_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"description":"Máximo de negocios","default":40,"title":"Limit"},"description":"Máximo de negocios"},{"name":"per_business","in":"query","required":false,"schema":{"type":"integer","maximum":20,"minimum":1,"description":"Máximo de FAQs por negocio","default":6,"title":"Per Business"},"description":"Máximo de FAQs por negocio"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/stats":{"get":{"tags":["admin"],"summary":"Get Admin Stats","description":"Stats globales de la plataforma.","operationId":"get_admin_stats_v1_admin_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/businesses":{"get":{"tags":["admin"],"summary":"Admin List Businesses","description":"Lista TODOS los negocios con filtros admin. `search` = fuzzy por nombre/slug.\n`only_with_email` = solo negocios con email no vacío en su ficha (para outreach).","operationId":"admin_list_businesses_v1_admin_businesses_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"vertical","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vertical"}},{"name":"city","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"}},{"name":"claimed","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Claimed"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}},{"name":"source","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source"}},{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Search"}},{"name":"only_with_email","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Only With Email"}},{"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"}}}}}}},"/v1/admin/businesses/{id}/status":{"put":{"tags":["admin"],"summary":"Admin Update Business Status","description":"Cambiar status de cualquier negocio.","operationId":"admin_update_business_status_v1_admin_businesses__id__status_put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}},{"name":"status","in":"query","required":true,"schema":{"type":"string","pattern":"^(active|suspended|archived|draft)$","title":"Status"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/businesses/{id}/refresh-places":{"post":{"tags":["admin"],"summary":"Admin Refresh Places","description":"Fase 6: refresca manualmente los campos espejo de Google (reseñas, categoría, fotos) de un\nnegocio vinculado a Maps y recomputa su audit. UN Place Details call, respeta el tope diario.\nNunca batch/cron (eso es Hermes 3.5 futuro).","operationId":"admin_refresh_places_v1_admin_businesses__id__refresh_places_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/businesses/{id}/chain":{"put":{"tags":["admin"],"summary":"Admin Toggle Chain","description":"Toggle manual de is_chain (override de la detección automática).","operationId":"admin_toggle_chain_v1_admin_businesses__id__chain_put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}},{"name":"value","in":"query","required":true,"schema":{"type":"boolean","title":"Value"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/businesses/{id}/featured":{"put":{"tags":["admin"],"summary":"Admin Toggle Featured","description":"Toggle manual de is_featured (negocios destacados del homepage, curados).","operationId":"admin_toggle_featured_v1_admin_businesses__id__featured_put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}},{"name":"value","in":"query","required":true,"schema":{"type":"boolean","title":"Value"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/businesses/{id}/vertical":{"put":{"tags":["admin"],"summary":"Admin Reclassify Vertical","description":"Reclasifica un negocio mal categorizado: cambia vertical y RECONSTRUYE\ncapabilities + context_hints desde el template del nuevo vertical.","operationId":"admin_reclassify_vertical_v1_admin_businesses__id__vertical_put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}},{"name":"value","in":"query","required":true,"schema":{"type":"string","title":"Value"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/seeding/run":{"post":{"tags":["admin"],"summary":"Start Seeding Run","description":"Iniciar barrida de Apify en background.","operationId":"start_seeding_run_v1_admin_seeding_run_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeedingRunCreate"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeedingRunResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/seeding/google":{"post":{"tags":["admin"],"summary":"Seed Via Google Places","description":"Seeding síncrono vía Google Places API (New). Fuente de verdad para seeding.\nEl query incluye la ubicación (ej. 'turismo Los Cabos'). Mismo servicio que\nscripts/seed_google_places.py.","operationId":"seed_via_google_places_v1_admin_seeding_google_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GoogleSeedRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GoogleSeedResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/seeding/config":{"get":{"tags":["admin"],"summary":"Seeding Config","description":"Opciones para los dropdowns de la barrida masiva (lee los yaml).","operationId":"seeding_config_v1_admin_seeding_config_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/seeding/sweep":{"post":{"tags":["admin"],"summary":"Start Sweep","description":"Barrida masiva: sinónimos × subzonas en una corrida. Crea un SeedingRun y\nejecuta en background; el admin hace polling para el progreso.","operationId":"start_sweep_v1_admin_seeding_sweep_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SweepRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeedingRunResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/seeding/rejections":{"get":{"tags":["admin"],"summary":"List Rejections","description":"Negocios rechazados por el filtro de calidad, paginado (20/pág) + desglose por razón.\nPor defecto excluye los descartados (dismissed); dismissed=true muestra la pestaña de\ndescartados (revisables/reversibles). El desglose respeta el filtro de vertical + dismissed.","operationId":"list_rejections_v1_admin_seeding_rejections_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"reason","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason"}},{"name":"vertical","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vertical"}},{"name":"dismissed","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Dismissed"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/seeding/rejections/{rejection_id}/force-insert":{"post":{"tags":["admin"],"summary":"Force Insert Rejection","description":"Override manual: inserta un negocio rechazado (bypass del filtro) y borra\nel registro de rechazo.","operationId":"force_insert_rejection_v1_admin_seeding_rejections__rejection_id__force_insert_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"rejection_id","in":"path","required":true,"schema":{"type":"string","title":"Rejection Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/seeding/rejections/{rejection_id}/dismiss":{"post":{"tags":["admin"],"summary":"Dismiss Rejection","description":"Descarta (soft-delete) un rechazo revisado que se decidió NO forzar: sale de la vista pero\nel registro PERSISTE, así el dedup del seeding (por place_id) no lo vuelve a presentar. Reversible.","operationId":"dismiss_rejection_v1_admin_seeding_rejections__rejection_id__dismiss_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"rejection_id","in":"path","required":true,"schema":{"type":"string","title":"Rejection Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/seeding/rejections/{rejection_id}/undismiss":{"post":{"tags":["admin"],"summary":"Undismiss Rejection","description":"Revierte el descarte: el rechazo vuelve a la vista de pendientes.","operationId":"undismiss_rejection_v1_admin_seeding_rejections__rejection_id__undismiss_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"rejection_id","in":"path","required":true,"schema":{"type":"string","title":"Rejection Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/seeding/detect-chains":{"post":{"tags":["admin"],"summary":"Detect Chains Endpoint","description":"Detecta cadenas (nombre normalizado repetido N+ veces o en known_chains).\napply=False → preview (no modifica); apply=True → marca is_chain=True.","operationId":"detect_chains_endpoint_v1_admin_seeding_detect_chains_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"threshold","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":2,"default":5,"title":"Threshold"}},{"name":"apply","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Apply"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/seeding/inconsistencies":{"get":{"tags":["admin"],"summary":"List Inconsistencies","description":"Reporte (NO auto-fix) de negocios cuyo nombre sugiere un vertical distinto\nal asignado. Para revisión manual + reclasificación puntual.","operationId":"list_inconsistencies_v1_admin_seeding_inconsistencies_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":2000,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/seeding/runs":{"get":{"tags":["admin"],"summary":"List Seeding Runs","description":"Historial de barridas.","operationId":"list_seeding_runs_v1_admin_seeding_runs_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SeedingRunResponse"},"title":"Response List Seeding Runs V1 Admin Seeding Runs Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/seeding/runs/{id}":{"get":{"tags":["admin"],"summary":"Get Seeding Run","description":"Status de una barrida específica.","operationId":"get_seeding_run_v1_admin_seeding_runs__id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeedingRunResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/claim-invitations/send":{"post":{"tags":["admin"],"summary":"Send Claim Invitations","description":"Envía (o simula) invitaciones de claim a negocios unclaimed con email.","operationId":"send_claim_invitations_v1_admin_claim_invitations_send_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"vertical","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vertical"}},{"name":"city","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"default":10,"title":"Limit"}},{"name":"dry_run","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Dry Run"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/enrichment/run":{"post":{"tags":["admin"],"summary":"Run Enrichment","description":"Enriquece fichas desde sus websites con LLM. Síncrono para lotes pequeños.","operationId":"run_enrichment_v1_admin_enrichment_run_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"vertical","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vertical"}},{"name":"city","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"only_unenriched","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Only Unenriched"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/enrichment/reprocess":{"post":{"tags":["admin"],"summary":"Reprocess Enrichment","description":"Re-procesa enrichment (regex→LLM) en background. Solo negocios SIN email que\nSÍ tienen website (los candidatos a resolverse barato con regex).","operationId":"reprocess_enrichment_v1_admin_enrichment_reprocess_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"vertical","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vertical"}},{"name":"city","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"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"}}}}}}},"/v1/admin/enrichment/status":{"get":{"tags":["admin"],"summary":"Enrichment Runtime Status","description":"Estado live del job controlable (badge + progreso + log de los últimos 10).","operationId":"enrichment_runtime_status_v1_admin_enrichment_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/enrichment/start":{"post":{"tags":["admin"],"summary":"Enrichment Start","description":"Inicia un job controlable de enrichment (pendientes con website). Si ya hay\nun job corriendo/pausado, lo rechaza (detén primero).","operationId":"enrichment_start_v1_admin_enrichment_start_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"vertical","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vertical"}},{"name":"city","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":10000,"minimum":1,"default":1000,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/enrichment/pause":{"post":{"tags":["admin"],"summary":"Enrichment Pause","operationId":"enrichment_pause_v1_admin_enrichment_pause_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/enrichment/resume":{"post":{"tags":["admin"],"summary":"Enrichment Resume","operationId":"enrichment_resume_v1_admin_enrichment_resume_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/enrichment/stop":{"post":{"tags":["admin"],"summary":"Enrichment Stop","operationId":"enrichment_stop_v1_admin_enrichment_stop_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/enrichment/stats":{"get":{"tags":["admin"],"summary":"Enrichment Stats","description":"Stats de enriquecimiento.","operationId":"enrichment_stats_v1_admin_enrichment_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/subscriptions":{"get":{"tags":["admin"],"summary":"Admin List Subscriptions","description":"Lista de suscripciones con nombre del negocio.","operationId":"admin_list_subscriptions_v1_admin_subscriptions_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":300,"minimum":1,"default":100,"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"}}}}}}},"/v1/admin/subscriptions/{sub_id}/cancel":{"post":{"tags":["admin"],"summary":"Admin Cancel Subscription","description":"Cancela manualmente una suscripción (MP + DB + baja tier a free).","operationId":"admin_cancel_subscription_v1_admin_subscriptions__sub_id__cancel_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"sub_id","in":"path","required":true,"schema":{"type":"string","title":"Sub Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/outreach/send":{"post":{"tags":["admin"],"summary":"Send Outreach","description":"Envía emails de claim a negocios unclaimed con email (dry_run por default).\nEl filtro de calidad de email vive en `_outreach_base_query()` (email real regex-only + MX +\nno-rebotado). Reemplazó al viejo `freemail_only`, que era un proxy burdo y desalineado.","operationId":"send_outreach_v1_admin_outreach_send_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"vertical","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vertical"}},{"name":"city","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Limit"}},{"name":"dry_run","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Dry Run"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/outreach/lookup":{"get":{"tags":["admin"],"summary":"Outreach Lookup","description":"Busca negocios por nombre para el envío individual de outreach. Devuelve si tiene\nemail, si tiene Espejo generado, y si ya fue contactado por email (salvaguarda).","operationId":"outreach_lookup_v1_admin_outreach_lookup_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string","title":"Q"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/outreach/send-individual":{"post":{"tags":["admin"],"summary":"Send Outreach Individual","description":"Envía el Espejo por email a UN negocio (no campaña masiva). Requiere email + Espejo.\nSi ya fue contactado por email, exige force=true (salvaguarda anti re-contacto).\n\nPREVISUALIZACIÓN: con test_mode=true + recipient_override (tu email), manda el Espejo\nEXACTO del negocio (su data real) a TU correo, SIN tocar al negocio — no aplica la\nsalvaguarda, no registra envío ni marca outreach_sent_at.","operationId":"send_outreach_individual_v1_admin_outreach_send_individual_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"business_id","in":"query","required":true,"schema":{"type":"string","title":"Business Id"}},{"name":"force","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Force"}},{"name":"test_mode","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Test Mode"}},{"name":"recipient_override","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recipient Override"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/outreach/send-batch-mirror":{"post":{"tags":["admin"],"summary":"Send Outreach Batch Mirror","description":"Envía el ESPEJO (reporte de visibilidad) EN LOTE a los negocios del filtro — NO el\nclaim. Reusa la lógica del envío individual (`send_report_mirror` con el token de cada\nnegocio), iterando sobre N inboxes. Reglas críticas:\n- Solo negocios con Espejo generado (RadarReport).\n- DEDUP POR EMAIL: una sola vez por inbox único (varios negocios comparten info@…; no\n  se manda 2-3× al mismo buzón). Cada negocio lleva SU propio token/reporte.\n- Calidad de email: la impone `_outreach_base_query()` (real regex-only + MX + no-rebotado).\n- `limit` = nº de inboxes ÚNICOS a contactar (manda por baches).\n- Marca `outreach_sent_at`; respeta unsubscribe y (salvo `force`) negocios ya contactados.\n`dry_run` (default True) devuelve el preview sin enviar nada.","operationId":"send_outreach_batch_mirror_v1_admin_outreach_send_batch_mirror_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"vertical","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vertical"}},{"name":"city","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Limit"}},{"name":"dry_run","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Dry Run"}},{"name":"force","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Force"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/outreach/stats":{"get":{"tags":["admin"],"summary":"Outreach Stats","description":"Stats de outreach.","operationId":"outreach_stats_v1_admin_outreach_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/removal-requests":{"get":{"tags":["admin"],"summary":"List Removal Requests","description":"Lista solicitudes de eliminación (default: pendientes), con datos del negocio.","operationId":"list_removal_requests_v1_admin_removal_requests_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","default":"pending","title":"Status"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/removal-requests/{request_id}/approve":{"post":{"tags":["admin"],"summary":"Approve Removal Request","description":"Aprueba la solicitud y hace soft-delete del negocio (status='archived').","operationId":"approve_removal_request_v1_admin_removal_requests__request_id__approve_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"request_id","in":"path","required":true,"schema":{"type":"string","title":"Request Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/removal-requests/{request_id}/reject":{"post":{"tags":["admin"],"summary":"Reject Removal Request","description":"Rechaza la solicitud; el negocio permanece publicado.","operationId":"reject_removal_request_v1_admin_removal_requests__request_id__reject_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"request_id","in":"path","required":true,"schema":{"type":"string","title":"Request Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/faqs":{"get":{"tags":["admin"],"summary":"List Faqs For Review","description":"Lista FAQs por status (default: pending_approval) con datos del negocio + search_volume\n+ grounded_fields + motivo de rechazo. Para la vista de revisión del admin. Ordena por mayor\nsearch_volume. En 'rejected' oculta las descartadas (dismissed) salvo include_dismissed=1.","operationId":"list_faqs_for_review_v1_admin_faqs_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","default":"pending_approval","title":"Status"}},{"name":"include_dismissed","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Dismissed"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/faqs/stats":{"get":{"tags":["admin"],"summary":"Faq Review Stats","description":"Conteos por status + nº de negocios con pending_approval (para el header de la vista).","operationId":"faq_review_stats_v1_admin_faqs_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/faqs/{faq_id}/approve":{"post":{"tags":["admin"],"summary":"Approve Faq","description":"Aprueba una FAQ → status='published' + published_at. A partir de ahí la ficha la emite\n(FAQPage schema + render visible; eso ya existe, solo se activa con published).","operationId":"approve_faq_v1_admin_faqs__faq_id__approve_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"faq_id","in":"path","required":true,"schema":{"type":"string","title":"Faq Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/faqs/{faq_id}/reject":{"post":{"tags":["admin"],"summary":"Reject Faq","description":"Rechaza una FAQ → status='rejected' (no se publica, no emite schema). Motivo opcional del\nadmin (se guarda para la vista de Rechazadas). Reversible: mueve de estado, no borra.","operationId":"reject_faq_v1_admin_faqs__faq_id__reject_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"faq_id","in":"path","required":true,"schema":{"type":"string","title":"Faq Id"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/FaqReject"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/faqs/{faq_id}/unpublish":{"post":{"tags":["admin"],"summary":"Unpublish Faq","description":"Despublica una FAQ published → pending_approval (vuelve a la cola de revisión). La ficha\ndeja de emitirla en el FAQPage schema (solo se emiten published). Reversible: re-aprobar.","operationId":"unpublish_faq_v1_admin_faqs__faq_id__unpublish_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"faq_id","in":"path","required":true,"schema":{"type":"string","title":"Faq Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/faqs/{faq_id}/dismiss":{"post":{"tags":["admin"],"summary":"Dismiss Faq","description":"Descarta definitivo un rejected → sale de la cola de revisión (dismissed=true). Reversible\n(dismissed=false). No borra; el registro queda para auditoría.","operationId":"dismiss_faq_v1_admin_faqs__faq_id__dismiss_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"faq_id","in":"path","required":true,"schema":{"type":"string","title":"Faq Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/faqs/{faq_id}/reevaluate":{"post":{"tags":["admin"],"summary":"Reevaluate Faq","description":"Re-evalúa un rejected: re-genera la respuesta con los datos ACTUALES de la ficha (útil si\nganó datos vía Fase 6). Reusa el motor existente (answer_one) SIN modificarlo. Si ahora\nresponde grounded → pending_approval; si sigue sin datos → queda rejected con motivo.","operationId":"reevaluate_faq_v1_admin_faqs__faq_id__reevaluate_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"faq_id","in":"path","required":true,"schema":{"type":"string","title":"Faq Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/faqs/{faq_id}":{"patch":{"tags":["admin"],"summary":"Edit Faq","description":"Edita pregunta/respuesta (ES/EN) en cualquier estado (pending/published/rejected). Con\napprove=true, además publica (override manual: el admin sabe la respuesta correcta). No toca\nel pipeline ni el grounding — es edición manual con la autoridad del admin.","operationId":"edit_faq_v1_admin_faqs__faq_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"faq_id","in":"path","required":true,"schema":{"type":"string","title":"Faq Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FaqEdit"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/outreach/emails":{"get":{"tags":["admin"],"summary":"Outreach Emails","description":"Historial paginado de emails de outreach (20/pág), con nombre del negocio.\nFiltro opcional por status (sent/delivered/opened/clicked/bounced/error).","operationId":"outreach_emails_v1_admin_outreach_emails_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/outreach/test":{"post":{"tags":["admin"],"summary":"Outreach Test","description":"Envía el template de outreach a una dirección arbitraria para QA.\nNO cuenta contra el límite diario ni se registra en outreach_emails.","operationId":"outreach_test_v1_admin_outreach_test_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"email","in":"query","required":true,"schema":{"type":"string","minLength":5,"maxLength":254,"title":"Email"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/users":{"get":{"tags":["admin"],"summary":"List Users","description":"Lista usuarios registrados (Supabase Auth via service_role) con su conteo\nde negocios activos asociados.","operationId":"list_users_v1_admin_users_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/reports/{token}/sends":{"get":{"tags":["admin"],"summary":"Report Send Prefill","description":"Prefill + historial para el modal de envío. 404 si el token no existe.","operationId":"report_send_prefill_v1_admin_reports__token__sends_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"token","in":"path","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"}}}}}}},"/v1/admin/businesses/{business_id}/report-summary":{"get":{"tags":["admin"],"summary":"Business Report Summary","description":"Resumen del reporte Espejo más reciente del negocio (para el panel de /admin/radar).\nhas_report=false si nunca se generó. Read-only, reusa build_report_payload.","operationId":"business_report_summary_v1_admin_businesses__business_id__report_summary_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"business_id","in":"path","required":true,"schema":{"type":"string","title":"Business Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/report-sends":{"get":{"tags":["admin"],"summary":"List Report Sends","description":"Ledger global de envíos del Reporte Espejo (todos los negocios).","operationId":"list_report_sends_v1_admin_report_sends_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/reports/{token}/send-email":{"post":{"tags":["admin"],"summary":"Send Report Email","description":"Envía el Reporte Espejo por email vía Resend y lo registra en report_sends.","operationId":"send_report_email_v1_admin_reports__token__send_email_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportSendRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/visibility-report/{business_id}/regenerate":{"post":{"tags":["admin"],"summary":"Regenerate Visibility Report","description":"Radar v2: recalcula las 6 métricas del Reporte de Visibilidad para un negocio\ndesde la evidencia del Radar (radar_responses/mentions). Persiste en visibility_metrics.","operationId":"regenerate_visibility_report_v1_admin_visibility_report__business_id__regenerate_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"business_id","in":"path","required":true,"schema":{"type":"string","title":"Business Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/visibility-report/{business_id}":{"get":{"tags":["admin"],"summary":"Get Visibility Report","description":"Payload agregado del Reporte de Visibilidad para el dashboard (6 métricas +\nbenchmark + co-mention + queries + oportunidades).","operationId":"get_visibility_report_v1_admin_visibility_report__business_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"business_id","in":"path","required":true,"schema":{"type":"string","title":"Business Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/visibility-report/{business_id}/send":{"post":{"tags":["admin"],"summary":"Send Visibility Report Single","description":"Envía el Reporte de Visibilidad por email a UN destinatario. Rate-limit 50/h.\nPor defecto test_mode=True. NO dispara nada masivo.","operationId":"send_visibility_report_single_v1_admin_visibility_report__business_id__send_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"business_id","in":"path","required":true,"schema":{"type":"string","title":"Business Id"}},{"name":"recipient_email","in":"query","required":true,"schema":{"type":"string","description":"Destinatario","title":"Recipient Email"},"description":"Destinatario"},{"name":"test_mode","in":"query","required":false,"schema":{"type":"boolean","description":"Marca [TEST] en el asunto","default":true,"title":"Test Mode"},"description":"Marca [TEST] en el asunto"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/visibility-report/batch-send":{"post":{"tags":["admin"],"summary":"Send Visibility Report Batch","description":"Envío a una LISTA EXPLÍCITA de business_ids (no hay filtro 'todos' para evitar\nmasivos accidentales). Cada uno usa el email del negocio salvo recipient_override.\nRate-limit 50/h compartido.","operationId":"send_visibility_report_batch_v1_admin_visibility_report_batch_send_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"recipient_override","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Si se da, todos van a este correo (test)","title":"Recipient Override"},"description":"Si se da, todos van a este correo (test)"},{"name":"test_mode","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Test Mode"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"array","items":{"type":"string"},"title":"Business Ids"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/visibility-report-sends":{"get":{"tags":["admin"],"summary":"List Visibility Sends","description":"Log de envíos del Reporte de Visibilidad (para el admin).","operationId":"list_visibility_sends_v1_admin_visibility_report_sends_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/webhooks/mercadopago":{"post":{"tags":["webhooks"],"summary":"Mercadopago Webhook","description":"Notificaciones de MercadoPago. Siempre 200.","operationId":"mercadopago_webhook_v1_webhooks_mercadopago_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/webhooks/resend":{"post":{"tags":["webhooks"],"summary":"Resend Webhook","description":"Tracking de emails de Resend (delivered/opened/clicked/bounced). Siempre 200.","operationId":"resend_webhook_v1_webhooks_resend_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/outreach/unsubscribe":{"post":{"tags":["outreach"],"summary":"Unsubscribe","description":"Marca todos los negocios con ese email como no-contactar (CAN-SPAM).","operationId":"unsubscribe_v1_outreach_unsubscribe_post","parameters":[{"name":"email","in":"query","required":true,"schema":{"type":"string","title":"Email"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/radar/combos":{"get":{"tags":["radar-admin"],"summary":"Radar Combos","operationId":"radar_combos_v1_admin_radar_combos_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/radar/reports":{"get":{"tags":["radar-admin"],"summary":"Radar List Reports","operationId":"radar_list_reports_v1_admin_radar_reports_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/radar/reports/{token}/dismiss":{"post":{"tags":["radar-admin"],"summary":"Radar Report Dismiss","description":"Descarta (soft-delete) el espejo del negocio: sale de la cola/vista, el registro persiste.","operationId":"radar_report_dismiss_v1_admin_radar_reports__token__dismiss_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"token","in":"path","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"}}}}}}},"/v1/admin/radar/reports/{token}/undismiss":{"post":{"tags":["radar-admin"],"summary":"Radar Report Undismiss","description":"Restaura un espejo descartado → vuelve a la vista.","operationId":"radar_report_undismiss_v1_admin_radar_reports__token__undismiss_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"token","in":"path","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"}}}}}}},"/v1/admin/radar/combos/generate":{"post":{"tags":["radar-admin"],"summary":"Radar Combo Generate","description":"Genera con el LLM un combo CANDIDATO (draft) para vertical×ciudad. `population` controla si\nes genérico ('vertical', default) o de sub-giro ('subgiro:X', con X un sub-giro REAL del\nvertical). El LLM solo PROPONE queries; queda draft (no corrible) hasta aprobación humana.","operationId":"radar_combo_generate_v1_admin_radar_combos_generate_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"vertical","in":"query","required":true,"schema":{"type":"string","title":"Vertical"}},{"name":"city","in":"query","required":true,"schema":{"type":"string","title":"City"}},{"name":"population","in":"query","required":false,"schema":{"type":"string","default":"vertical","title":"Population"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/radar/combos/draft":{"get":{"tags":["radar-admin"],"summary":"Radar Combo Draft","description":"Combo draft del vertical×ciudad (para revisar/aprobar), o 404 si no hay.","operationId":"radar_combo_draft_v1_admin_radar_combos_draft_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"vertical","in":"query","required":true,"schema":{"type":"string","title":"Vertical"}},{"name":"city","in":"query","required":true,"schema":{"type":"string","title":"City"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/radar/combos/drafts":{"get":{"tags":["radar-admin"],"summary":"Radar Combos Drafts","description":"Lista TODOS los combos draft (para la bandeja de pendientes del Inicio). Compacto:\nmetadata + población + nº de queries. El detalle con chips se trae por /combos/draft.","operationId":"radar_combos_drafts_v1_admin_radar_combos_drafts_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/radar/combos/overview":{"get":{"tags":["radar-admin"],"summary":"Radar Combos Overview","description":"Lista unificada para la vista de Combos: draft + approved (excluye archived), con población,\nnº de queries y last_run (último Radar completado del combo). Además zonas con densidad de\nnegocios pero SIN combo (status sintético 'none') para ver huecos de cobertura. Solo consolida\ndatos existentes — no toca la lógica de combos.","operationId":"radar_combos_overview_v1_admin_radar_combos_overview_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/radar/combos/{combo_id}":{"patch":{"tags":["radar-admin"],"summary":"Radar Combo Update","description":"Edita un combo DRAFT (queries/persona/idioma/location). Solo drafts.","operationId":"radar_combo_update_v1_admin_radar_combos__combo_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"combo_id","in":"path","required":true,"schema":{"type":"string","title":"Combo Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_radar_combo_update_v1_admin_radar_combos__combo_id__patch"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/radar/combos/{combo_id}/approve":{"post":{"tags":["radar-admin"],"summary":"Radar Combo Approve","description":"Aprueba un draft → status=approved → corrible (refresca el caché). El guard es por\n(vertical, ciudad, POBLACIÓN): distintos sub-giros (o genérico vs sub-giro) COEXISTEN en una\nciudad, cada uno midiendo su población. Solo dispara 409 si ya hay un aprobado de la MISMA\npoblación (salvo replace=true, que ARCHIVA el viejo — reversible).","operationId":"radar_combo_approve_v1_admin_radar_combos__combo_id__approve_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"combo_id","in":"path","required":true,"schema":{"type":"string","title":"Combo Id"}},{"name":"replace","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Replace"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/radar/combos/{combo_id}/archive":{"post":{"tags":["radar-admin"],"summary":"Radar Combo Archive","description":"Rechaza/retira un combo → status='archived'. Reversible (el registro queda; se puede\nreponer a draft). Saca el draft de /combos/drafts → baja el contador 'Requiere tu atención';\nsi estaba aprobado, sale del caché de corribles. Para el combo malo de raíz.","operationId":"radar_combo_archive_v1_admin_radar_combos__combo_id__archive_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"combo_id","in":"path","required":true,"schema":{"type":"string","title":"Combo Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/radar/combos/cities":{"get":{"tags":["radar-admin"],"summary":"Radar Combo Cities","description":"Ciudades del catálogo (seeding_cities) con su país, para el dropdown de 'Corregir ciudad':\nfuerza elegir una ciudad DESAMBIGUADA (city + region_code explícitos) en vez de un nombre a\nsecas que caiga al homónimo mexicano.","operationId":"radar_combo_cities_v1_admin_radar_combos_cities_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/radar/combos/{combo_id}/reassign-city":{"post":{"tags":["radar-admin"],"summary":"Radar Combo Reassign City","description":"Corrige la ciudad de un combo DRAFT: la reasigna a una ciudad EXPLÍCITA del catálogo\n(city + region_code, sin ambigüedad de topónimo) y re-genera sus queries con el país correcto\n— SIN ir a Radar (no corre medición paga). Reusa el generador ya fixeado con region_code\nexplícito. El resultado queda draft (para revisar/aprobar). Si el original persiste con otro\nkey (ciudad realmente distinta), lo archiva (reversible).","operationId":"radar_combo_reassign_city_v1_admin_radar_combos__combo_id__reassign_city_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"combo_id","in":"path","required":true,"schema":{"type":"string","title":"Combo Id"}},{"name":"city","in":"query","required":true,"schema":{"type":"string","title":"City"}},{"name":"region_code","in":"query","required":true,"schema":{"type":"string","title":"Region Code"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/radar/run":{"post":{"tags":["radar-admin"],"summary":"Radar Run","description":"Crea un run por superficie del combo y los corre en background. `surface` opcional: si se\nda (ej. 'google_ai'), corre SOLO esa superficie; si no, las configuradas del combo. NOTA: con\nSERP_API_KEY/OPENAI_API_KEY en placeholder, los runs corren completos pero las respuestas\nquedan con error (sin datos reales) — listo para cuando lleguen keys.","operationId":"radar_run_v1_admin_radar_run_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"combo","in":"query","required":true,"schema":{"type":"string","title":"Combo"}},{"name":"surface","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Surface"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/radar/runs":{"get":{"tags":["radar-admin"],"summary":"Radar Runs","operationId":"radar_runs_v1_admin_radar_runs_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/radar/runs/{run_id}":{"get":{"tags":["radar-admin"],"summary":"Radar Run Detail","description":"Detalle para el gate T2: respuestas + menciones (raw_name, matched, excerpt).","operationId":"radar_run_detail_v1_admin_radar_runs__run_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","title":"Run Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/radar/report":{"post":{"tags":["radar-admin"],"summary":"Radar Generate Report","description":"Genera un token de reporte para un negocio sobre un combo. Usa el último\nrun existente del combo (T3.3).","operationId":"radar_generate_report_v1_admin_radar_report_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"business_id","in":"query","required":true,"schema":{"type":"string","title":"Business Id"}},{"name":"combo","in":"query","required":true,"schema":{"type":"string","title":"Combo"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/radar/funnel":{"get":{"tags":["radar-admin"],"summary":"Outreach Funnel","description":"Embudo de outreach end-to-end por campaña: enviados → entregados → abiertos → clicados →\nEspejo visto → reclamado, con tasas entre saltos. Filtrable por vertical/ciudad para comparar\ncombos (dental-tijuana vs turismo-cabo). 'opened'/'clicked' dependen del tracking de Resend\n(open/click); si están en 0 globalmente, ese tracking no está activado en Resend.","operationId":"outreach_funnel_v1_admin_radar_funnel_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"vertical","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vertical"}},{"name":"city","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/reporte/{token}":{"get":{"tags":["radar-report"],"summary":"Get Report","operationId":"get_report_v1_reporte__token__get","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}},{"name":"preview","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Preview"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/radar/combo-teaser":{"get":{"tags":["radar-public"],"summary":"Combo Teaser Endpoint","description":"Teaser público del espejo para el alta (B1): resumen agregado del ÚLTIMO run completado del\ncombo (vertical, ciudad). Cacheado 1h en Redis; rate-limit ligero por IP. Sin combo/datos →\n{has_data: false}. Solo LEE las tablas del Radar; no toca el espejo ni el scoring.","operationId":"combo_teaser_endpoint_v1_radar_combo_teaser_get","parameters":[{"name":"vertical","in":"query","required":true,"schema":{"type":"string","maxLength":40,"title":"Vertical"}},{"name":"city","in":"query","required":true,"schema":{"type":"string","maxLength":80,"title":"City"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/reporte-visibilidad/{token}":{"get":{"tags":["visibility-report"],"summary":"Public Visibility Report","operationId":"public_visibility_report_v1_reporte_visibilidad__token__get","parameters":[{"name":"token","in":"path","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"}}}}}}},"/v1/reporte-visibilidad/{token}/abierto.gif":{"get":{"tags":["visibility-report"],"summary":"Open Pixel","description":"Pixel de apertura: marca opened_at en el último envío del token.","operationId":"open_pixel_v1_reporte_visibilidad__token__abierto_gif_get","parameters":[{"name":"token","in":"path","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"}}}}}}},"/v1/insights":{"get":{"tags":["insights"],"summary":"List Insights","operationId":"list_insights_v1_insights_get","parameters":[{"name":"lang","in":"query","required":false,"schema":{"type":"string","default":"es","title":"Lang"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/insights/{slug}":{"get":{"tags":["insights"],"summary":"Get Insight","operationId":"get_insight_v1_insights__slug__get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"lang","in":"query","required":false,"schema":{"type":"string","default":"es","title":"Lang"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/insights":{"get":{"tags":["admin-insights"],"summary":"Admin List","operationId":"admin_list_v1_admin_insights_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]},"post":{"tags":["admin-insights"],"summary":"Admin Create","operationId":"admin_create_v1_admin_insights_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArticleIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/insights/{article_id}":{"get":{"tags":["admin-insights"],"summary":"Admin Get","operationId":"admin_get_v1_admin_insights__article_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"article_id","in":"path","required":true,"schema":{"type":"string","title":"Article Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["admin-insights"],"summary":"Admin Update","operationId":"admin_update_v1_admin_insights__article_id__put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"article_id","in":"path","required":true,"schema":{"type":"string","title":"Article Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArticleIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/insights/{article_id}/publish":{"post":{"tags":["admin-insights"],"summary":"Admin Publish","operationId":"admin_publish_v1_admin_insights__article_id__publish_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"article_id","in":"path","required":true,"schema":{"type":"string","title":"Article Id"}},{"name":"published","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Published"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/index":{"get":{"tags":["plexa-index"],"summary":"List Combos","operationId":"list_combos_v1_index_get","parameters":[{"name":"lang","in":"query","required":false,"schema":{"type":"string","default":"es","title":"Lang"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/index/{slug}":{"get":{"tags":["plexa-index"],"summary":"Get Index","operationId":"get_index_v1_index__slug__get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"lang","in":"query","required":false,"schema":{"type":"string","default":"es","title":"Lang"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/index/lead":{"post":{"tags":["plexa-index"],"summary":"Submit Lead","operationId":"submit_lead_v1_index_lead_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeadIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/index/snapshot":{"post":{"tags":["admin-index"],"summary":"Snapshot All","description":"Toma snapshot del ranking actual de TODOS los combos publicables (baseline del trend).\nLa cobertura sale de la DB (share-of-voice), no de un dict — crece con cada run del Radar.","operationId":"snapshot_all_v1_admin_index_snapshot_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/aeo/verticals":{"get":{"tags":["aeo"],"summary":"List Verticals","description":"Verticales que hoy publican página AEO (sitemap + footer). Derivado de la DB.","operationId":"list_verticals_v1_aeo_verticals_get","parameters":[{"name":"lang","in":"query","required":false,"schema":{"type":"string","default":"es","title":"Lang"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/aeo/{vertical}":{"get":{"tags":["aeo"],"summary":"Get Vertical","operationId":"get_vertical_v1_aeo__vertical__get","parameters":[{"name":"vertical","in":"path","required":true,"schema":{"type":"string","title":"Vertical"}},{"name":"lang","in":"query","required":false,"schema":{"type":"string","default":"es","title":"Lang"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/espejo/self-serve":{"post":{"tags":["espejo-selfserve"],"summary":"Espejo Self Serve","description":"Entrega en pantalla lo que YA existe (o encola). Nunca corre Radar on-demand.","operationId":"espejo_self_serve_v1_espejo_self_serve_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SelfServeIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/espejo/self-serve/status":{"get":{"tags":["espejo-selfserve"],"summary":"Espejo Self Serve Status","description":"Polling de la sala de espera: estado de la solicitud + link cuando esté listo.\nready → redirect al reporte; generating/pending → seguir esperando; none → sin solicitud.","operationId":"espejo_self_serve_status_v1_espejo_self_serve_status_get","parameters":[{"name":"business_id","in":"query","required":true,"schema":{"type":"string","description":"business_id de la solicitud","title":"Business Id"},"description":"business_id de la solicitud"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/selfserve/requests":{"get":{"tags":["espejo-selfserve-admin"],"summary":"Selfserve Requests List","description":"Cola de solicitudes self-serve (Caso B) para envío MANUAL. El cron marca 'ready' + token;\nChristian revisa y manda a mano. Incluye nombre/ciudad del negocio y contacto capturado.","operationId":"selfserve_requests_list_v1_admin_selfserve_requests_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"pending | ready (default: todas)","title":"Status"},"description":"pending | ready (default: todas)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/selfserve/stats":{"get":{"tags":["espejo-selfserve-admin"],"summary":"Selfserve Stats","description":"Medición del canal inbound: solicitudes por caso (A/B/C, contadores Redis) + estado de la\ncola B (pending/ready) + conversión a claim de los negocios que llegaron por self-serve.","operationId":"selfserve_stats_v1_admin_selfserve_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/ard/":{"get":{"tags":["ard-registry"],"summary":"Ard Root","description":"Descriptor GET de la base del registry.\n\nExiste porque `ai-catalog.json` (entrada `urn:air:joinplexa.com:registry:local-business`) y\n`llms.txt` anuncian `https://api.joinplexa.com/ard/` como la base del registry — y esa URL\ndaba 404: una URL anunciada que no responde es una promesa rota para el agente que la sigue.\nNo cambia el contenido del ARD; lo vuelve cierto. Los endpoints reales son POST (§7.2/§7.3),\nasí que este GET es el único punto navegable de la base.","operationId":"ard_root_ard__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/ard/search":{"post":{"tags":["ard-registry"],"summary":"Ard Search","description":"ARD §7.2 — `text` requerido. Devuelve negocios rankeados por el motor existente.","operationId":"ard_search_ard_search_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/ard/explore":{"post":{"tags":["ard-registry"],"summary":"Ard Explore","description":"ARD §7.3 — facetas del índice (vertical, city). `text`/`filter` ambos opcionales.","operationId":"ard_explore_ard_explore_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExploreBody"}}},"required":true},"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":{}}}}}}},"/api/v1":{"get":{"summary":"Api V1 Root","description":"Descriptor GET de la base de la API REST.\n\nMisma razón que `GET /ard/`: anunciamos `https://api.joinplexa.com/api/v1` como la base del\nservicio (el `anchor` de la entrada REST del api-catalog RFC 9727 y la línea \"Base:\" de\nllms-full.txt), y daba 404. Una URL que declaramos y no responde es una promesa rota para el\nagente que la sigue. No cambia ningún endpoint: solo vuelve navegable la base que ya anunciábamos.","operationId":"api_v1_root_api_v1_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/.well-known/ai-catalog.json":{"get":{"summary":"Ai Catalog Mirror","description":"Espeja el ARD del apex — MISMA fuente de verdad, servido también aquí.\n\nEl catálogo se GENERA en el web (apps/web/app/well-known/ai-catalog.json/route.ts). Un agente\nno debería tener que adivinar el host, así que la API lo sirve consumiéndolo del apex (cache\n1h en proceso). NO se usa redirect cross-host: muchos clientes/agentes no siguen redirecciones\nentre hosts. Jamás se copia el JSON a mano: dos fuentes de verdad divergen.\nSi el apex falla y no hay copia cacheada, 502 honesto (mejor que servir algo inventado).","operationId":"ai_catalog_mirror__well_known_ai_catalog_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/.well-known/mcp/server-card.json":{"get":{"summary":"Mcp Server Card","description":"Server card para registries MCP (Smithery, etc.). FUENTE DE VERDAD del server-card:\nel apex lo espeja desde aquí (apps/web/app/well-known/mcp/server-card.json/route.ts).\n\nTRANSPORTES — declaramos los DOS que el server realmente sirve (mcp/server.py:667-678).\nAntes esta card declaraba como única `url` el `/mcp/sse` deprecado: respondía 200 y mentía,\nescondiendo Streamable HTTP a todo agente que la leyera.\n\nShape: `remotes[]` con `type`+`url`, copiado del server.json del registro MCP — es la única\nconvención real (schema 2025-12-11: `StreamableHttpTransport.type.enum == [\"streamable-http\"]`,\n`SseTransport.type.enum == [\"sse\"]`; \"http\"/\"streamable_http\" son inválidos). No existe un\n\"server card\" normativo: el WG (charter 2026-03-26) pide explícitamente que el formato \"stay as\nclose as possible to a subset of server.json\". No declaramos `$schema` porque esta card lleva\ncampos extra (tools, author) y no validamos conformidad con server.json.\n\nURL con BARRA FINAL (`/mcp/`), verificado por efecto y coincidente con nuestra entrada del\nregistro oficial (com.joinplexa/plexa v1.0.0): POST /mcp/ → 200 con handshake real; POST /mcp\n→ 307, y un 307 en POST no todos los clientes MCP lo siguen bien.","operationId":"mcp_server_card__well_known_mcp_server_card_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"ARDQuery":{"properties":{"text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Text"},"filter":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Filter"}},"type":"object","title":"ARDQuery"},"ArticleIn":{"properties":{"slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Slug"},"slug_en":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Slug En"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"title_en":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title En"},"subtitle":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subtitle"},"subtitle_en":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subtitle En"},"content_md":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content Md"},"content_md_en":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content Md En"},"author_agent":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Author Agent"},"supervisor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Supervisor"},"citations":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}],"title":"Citations"},"faq_items":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}],"title":"Faq Items"},"hero_image_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hero Image Url"}},"type":"object","title":"ArticleIn"},"AskRequest":{"properties":{"question":{"type":"string","title":"Question"}},"type":"object","required":["question"],"title":"AskRequest"},"Body_radar_combo_update_api_v1_admin_radar_combos__combo_id__patch":{"properties":{"queries":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Queries"},"language":{"type":"string","title":"Language","default":"es"},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location"},"surfaces":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Surfaces"}},"type":"object","required":["queries"],"title":"Body_radar_combo_update_api_v1_admin_radar_combos__combo_id__patch"},"Body_radar_combo_update_v1_admin_radar_combos__combo_id__patch":{"properties":{"queries":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Queries"},"language":{"type":"string","title":"Language","default":"es"},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location"},"surfaces":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Surfaces"}},"type":"object","required":["queries"],"title":"Body_radar_combo_update_v1_admin_radar_combos__combo_id__patch"},"BuilderRegisterRequest":{"properties":{"name":{"type":"string","maxLength":100,"minLength":1,"title":"Name"}},"type":"object","required":["name"],"title":"BuilderRegisterRequest"},"BusinessCreate":{"properties":{"name":{"type":"string","maxLength":200,"minLength":2,"title":"Name"},"vertical":{"type":"string","title":"Vertical"},"city":{"type":"string","title":"City"},"state":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"State"},"country":{"type":"string","title":"Country","default":"MX"},"street_address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Street Address"},"postal_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postal Code"},"latitude":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Latitude"},"longitude":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Longitude"},"phone_e164":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone E164"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"website":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Website"},"whatsapp_e164":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Whatsapp E164"},"description_short":{"anyOf":[{"type":"string","maxLength":150},{"type":"null"}],"title":"Description Short"},"languages":{"items":{"type":"string"},"type":"array","title":"Languages","default":["es"]}},"type":"object","required":["name","vertical","city"],"title":"BusinessCreate"},"BusinessListResponse":{"properties":{"results":{"items":{"$ref":"#/components/schemas/BusinessResponse"},"type":"array","title":"Results"},"total":{"type":"integer","title":"Total"},"limit":{"type":"integer","title":"Limit"},"offset":{"type":"integer","title":"Offset"}},"type":"object","required":["results","total","limit","offset"],"title":"BusinessListResponse"},"BusinessResponse":{"properties":{"id":{"type":"string","title":"Id"},"slug":{"type":"string","title":"Slug"},"name":{"type":"string","title":"Name"},"vertical":{"type":"string","title":"Vertical"},"city":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"},"state":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"State"},"country":{"type":"string","title":"Country"},"street_address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Street Address"},"latitude":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Latitude"},"longitude":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Longitude"},"phone_e164":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone E164"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"website":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Website"},"google_place_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Google Place Id"},"whatsapp_e164":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Whatsapp E164"},"description_short":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description Short"},"description_long":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description Long"},"languages":{"items":{"type":"string"},"type":"array","title":"Languages","default":[]},"opening_hours":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Opening Hours","default":[]},"hours_confidence":{"type":"string","title":"Hours Confidence","default":"ok"},"payment_accepted":{"items":{"type":"string"},"type":"array","title":"Payment Accepted","default":[]},"insurance_accepted":{"items":{"type":"string"},"type":"array","title":"Insurance Accepted","default":[]},"capabilities":{"items":{"$ref":"#/components/schemas/CapabilityAction"},"type":"array","title":"Capabilities","default":[]},"mcp_endpoint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mcp Endpoint"},"mcp_endpoint_status":{"type":"string","title":"Mcp Endpoint Status","default":"none"},"tier":{"type":"string","title":"Tier"},"status":{"type":"string","title":"Status"},"claimed":{"type":"boolean","title":"Claimed"},"source":{"type":"string","title":"Source"},"aggregate_rating_human":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Aggregate Rating Human"},"review_count_human":{"type":"integer","title":"Review Count Human","default":0},"price_level":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Price Level"},"services":{"items":{"$ref":"#/components/schemas/ServiceItem"},"type":"array","title":"Services","default":[]},"faqs":{"items":{"$ref":"#/components/schemas/FaqItem"},"type":"array","title":"Faqs","default":[]},"specialties":{"items":{"type":"string"},"type":"array","title":"Specialties","default":[]},"areas_served":{"items":{"type":"string"},"type":"array","title":"Areas Served","default":[]},"social_media":{"additionalProperties":true,"type":"object","title":"Social Media","default":{}},"booking_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Booking Url"},"preferred_contact_method":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Preferred Contact Method"},"response_time":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Response Time"},"agent_instructions":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Agent Instructions"},"context_hints":{"items":{"type":"string"},"type":"array","title":"Context Hints","default":[]},"whatsapp_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Whatsapp Url"},"profile_completeness":{"type":"integer","title":"Profile Completeness","default":0},"onboarding_completed":{"type":"boolean","title":"Onboarding Completed","default":false},"is_chain":{"type":"boolean","title":"Is Chain","default":false},"is_featured":{"type":"boolean","title":"Is Featured","default":false},"trust_score":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Trust Score"},"verifications":{"items":{"type":"string"},"type":"array","title":"Verifications","default":[]},"created_at":{"type":"string","title":"Created At"},"updated_at":{"type":"string","title":"Updated At"}},"type":"object","required":["id","slug","name","vertical","country","tier","status","claimed","source","created_at","updated_at"],"title":"BusinessResponse"},"BusinessSearchResult":{"properties":{"id":{"type":"string","title":"Id"},"slug":{"type":"string","title":"Slug"},"name":{"type":"string","title":"Name"},"vertical":{"type":"string","title":"Vertical"},"city":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"},"state":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"State"},"country":{"type":"string","title":"Country"},"description_short":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description Short"},"phone_e164":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone E164"},"languages":{"items":{"type":"string"},"type":"array","title":"Languages","default":[]},"capabilities":{"items":{"$ref":"#/components/schemas/CapabilityAction"},"type":"array","title":"Capabilities","default":[]},"trust_score":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Trust Score"},"claimed":{"type":"boolean","title":"Claimed"},"tier":{"type":"string","title":"Tier"},"mcp_endpoint_status":{"type":"string","title":"Mcp Endpoint Status"},"aggregate_rating_human":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Aggregate Rating Human"},"review_count_human":{"type":"integer","title":"Review Count Human","default":0},"price_level":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Price Level"},"specialties":{"items":{"type":"string"},"type":"array","title":"Specialties","default":[]},"context_hints":{"items":{"type":"string"},"type":"array","title":"Context Hints","default":[]},"booking_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Booking Url"},"whatsapp_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Whatsapp Url"},"profile_completeness":{"type":"integer","title":"Profile Completeness","default":0},"distance_km":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Distance Km"}},"type":"object","required":["id","slug","name","vertical","country","claimed","tier","mcp_endpoint_status"],"title":"BusinessSearchResult"},"BusinessUpdate":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":200,"minLength":2},{"type":"null"}],"title":"Name"},"vertical":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vertical"},"city":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City"},"state":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"State"},"street_address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Street Address"},"postal_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Postal Code"},"latitude":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Latitude"},"longitude":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Longitude"},"phone_e164":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone E164"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"website":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Website"},"whatsapp_e164":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Whatsapp E164"},"description_short":{"anyOf":[{"type":"string","maxLength":150},{"type":"null"}],"title":"Description Short"},"description_long":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description Long"},"languages":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Languages"},"opening_hours":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Opening Hours"},"payment_accepted":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Payment Accepted"},"insurance_accepted":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Insurance Accepted"},"capabilities":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}],"title":"Capabilities"},"services":{"anyOf":[{"items":{"$ref":"#/components/schemas/ServiceInput"},"type":"array"},{"type":"null"}],"title":"Services"},"specialties":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Specialties"},"social_media":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Social Media"},"booking_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Booking Url"},"preferred_contact_method":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Preferred Contact Method"},"response_time":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Response Time"},"areas_served":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Areas Served"},"agent_instructions":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Agent Instructions"},"context_hints":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Context Hints"},"onboarding_completed":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Onboarding Completed"}},"type":"object","title":"BusinessUpdate"},"CapabilityAction":{"properties":{"name":{"type":"string","title":"Name"},"label":{"type":"string","title":"Label"},"action_type":{"type":"string","title":"Action Type"},"action_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Action Url"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},"type":"object","required":["name","label","action_type"],"title":"CapabilityAction"},"ClaimRequest":{"properties":{"phone_verification":{"type":"string","maxLength":25,"minLength":6,"title":"Phone Verification"}},"type":"object","required":["phone_verification"],"title":"ClaimRequest"},"CrawlerVisitRequest":{"properties":{"bot_name":{"type":"string","title":"Bot Name"},"path":{"type":"string","title":"Path"},"user_agent":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Agent"},"ip_address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ip Address"}},"type":"object","required":["bot_name","path"],"title":"CrawlerVisitRequest"},"ExploreBody":{"properties":{"query":{"anyOf":[{"$ref":"#/components/schemas/ARDQuery"},{"type":"null"}]},"resultType":{"anyOf":[{"$ref":"#/components/schemas/ResultTypeSpec"},{"type":"null"}]}},"type":"object","title":"ExploreBody"},"FacetField":{"properties":{"field":{"type":"string","title":"Field"},"limit":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Limit"}},"type":"object","required":["field"],"title":"FacetField"},"FaqEdit":{"properties":{"question_es":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Question Es"},"question_en":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Question En"},"answer_es":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Answer Es"},"answer_en":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Answer En"},"approve":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Approve"}},"type":"object","title":"FaqEdit"},"FaqItem":{"properties":{"question":{"type":"string","title":"Question"},"answer":{"type":"string","title":"Answer"},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At"}},"type":"object","required":["question","answer"],"title":"FaqItem"},"FaqReject":{"properties":{"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason"}},"type":"object","title":"FaqReject"},"GoogleMapsLinkRequest":{"properties":{"maps_url":{"type":"string","title":"Maps Url"}},"type":"object","required":["maps_url"],"title":"GoogleMapsLinkRequest"},"GoogleSeedRequest":{"properties":{"query":{"type":"string","maxLength":200,"minLength":2,"title":"Query"},"vertical":{"type":"string","title":"Vertical"},"limit":{"type":"integer","maximum":100.0,"minimum":1.0,"title":"Limit","default":50}},"type":"object","required":["query","vertical"],"title":"GoogleSeedRequest"},"GoogleSeedResponse":{"properties":{"imported":{"type":"integer","title":"Imported"},"duplicates":{"type":"integer","title":"Duplicates"},"errors":{"type":"integer","title":"Errors"}},"type":"object","required":["imported","duplicates","errors"],"title":"GoogleSeedResponse"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"LeadIn":{"properties":{"email":{"type":"string","title":"Email"},"combo_slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Combo Slug"},"business_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Business Name"},"kind":{"type":"string","title":"Kind","default":"report"},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source"}},"type":"object","required":["email"],"title":"LeadIn"},"OwnerFaqEdit":{"properties":{"question_es":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Question Es"},"question_en":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Question En"},"answer_es":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Answer Es"},"answer_en":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Answer En"}},"type":"object","title":"OwnerFaqEdit"},"RemovalRequestCreate":{"properties":{"email":{"type":"string","maxLength":254,"minLength":5,"title":"Email"},"reason":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"title":"Reason"}},"type":"object","required":["email"],"title":"RemovalRequestCreate"},"ReportSendRequest":{"properties":{"recipient_email":{"type":"string","title":"Recipient Email"},"recipient_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recipient Name"},"reply_to":{"type":"string","title":"Reply To"},"test_mode":{"type":"boolean","title":"Test Mode","default":false}},"type":"object","required":["recipient_email","reply_to"],"title":"ReportSendRequest"},"ResultTypeSpec":{"properties":{"facets":{"items":{"$ref":"#/components/schemas/FacetField"},"type":"array","title":"Facets","default":[]}},"type":"object","title":"ResultTypeSpec"},"SearchBody":{"properties":{"query":{"$ref":"#/components/schemas/ARDQuery"},"federation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Federation"},"pageSize":{"type":"integer","maximum":100.0,"minimum":1.0,"title":"Pagesize","default":10},"pageToken":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pagetoken"}},"type":"object","required":["query"],"title":"SearchBody"},"SearchResponse":{"properties":{"results":{"items":{"$ref":"#/components/schemas/BusinessSearchResult"},"type":"array","title":"Results"},"total":{"type":"integer","title":"Total"},"limit":{"type":"integer","title":"Limit"},"offset":{"type":"integer","title":"Offset"},"filters_applied":{"additionalProperties":true,"type":"object","title":"Filters Applied"}},"type":"object","required":["results","total","limit","offset","filters_applied"],"title":"SearchResponse"},"SeedingRunCreate":{"properties":{"vertical":{"type":"string","title":"Vertical"},"city":{"type":"string","title":"City"},"state":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"State"},"country":{"type":"string","title":"Country","default":"MX"},"max_results":{"type":"integer","maximum":500.0,"minimum":10.0,"title":"Max Results","default":150}},"type":"object","required":["vertical","city"],"title":"SeedingRunCreate"},"SeedingRunResponse":{"properties":{"id":{"type":"string","title":"Id"},"vertical":{"type":"string","title":"Vertical"},"city":{"type":"string","title":"City"},"state":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"State"},"search_query":{"type":"string","title":"Search Query"},"status":{"type":"string","title":"Status"},"imported":{"type":"integer","title":"Imported"},"duplicates":{"type":"integer","title":"Duplicates"},"errors":{"type":"integer","title":"Errors"},"queries_total":{"type":"integer","title":"Queries Total","default":0},"queries_done":{"type":"integer","title":"Queries Done","default":0},"raw_results":{"type":"integer","title":"Raw Results","default":0},"rejected":{"type":"integer","title":"Rejected","default":0},"started_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Started At"},"completed_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Completed At"}},"type":"object","required":["id","vertical","city","state","search_query","status","imported","duplicates","errors","started_at","completed_at"],"title":"SeedingRunResponse"},"SelfServeIn":{"properties":{"business_id":{"type":"string","title":"Business Id"},"contact":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contact"},"contact_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contact Type"}},"type":"object","required":["business_id"],"title":"SelfServeIn"},"ServiceInput":{"properties":{"name_es":{"type":"string","maxLength":200,"minLength":1,"title":"Name Es"},"name_en":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name En"},"description_es":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description Es"},"price_amount":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Price Amount"},"price_currency":{"type":"string","title":"Price Currency","default":"MXN"},"duration_minutes":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Duration Minutes"}},"type":"object","required":["name_es"],"title":"ServiceInput"},"ServiceItem":{"properties":{"name_es":{"type":"string","maxLength":200,"minLength":1,"title":"Name Es"},"name_en":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name En"},"description_es":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description Es"},"price_amount":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Price Amount"},"price_currency":{"type":"string","title":"Price Currency","default":"MXN"},"duration_minutes":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Duration Minutes"},"id":{"type":"string","title":"Id"}},"type":"object","required":["name_es","id"],"title":"ServiceItem"},"SweepRequest":{"properties":{"vertical":{"type":"string","title":"Vertical"},"city":{"type":"string","title":"City"},"include_english":{"type":"boolean","title":"Include English","default":false}},"type":"object","required":["vertical","city"],"title":"SweepRequest"},"TrustScoreResponse":{"properties":{"business_id":{"type":"string","title":"Business Id"},"score":{"type":"integer","title":"Score"},"breakdown":{"additionalProperties":true,"type":"object","title":"Breakdown"},"max_possible":{"type":"integer","title":"Max Possible","default":100},"computed_at":{"type":"string","title":"Computed At"},"recommendations":{"items":{"type":"string"},"type":"array","title":"Recommendations","default":[]}},"type":"object","required":["business_id","score","breakdown","computed_at"],"title":"TrustScoreResponse"},"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"}},"securitySchemes":{"HTTPBearer":{"type":"http","scheme":"bearer"}}}}