{"openapi":"3.1.0","info":{"title":"Tivar API Pública","version":"1.0.0","description":"API pública do Tivar para envio de mensagens via WhatsApp (Oficial, UAZAPI, WAHA), Telegram e Live Chat, mais webhooks outbound. Gerado a partir de docs/API-PUBLICA.md — qualquer mudança de comportamento real deve atualizar os dois arquivos juntos.\n","contact":{"name":"Suporte Tivar"}},"externalDocs":{"description":"Documentação em markdown (fonte deste spec) e página navegável","url":"https://app.tivar.com.br/docs"},"servers":[{"url":"https://{dominio}","variables":{"dominio":{"default":"app.tivar.com.br","description":"Domínio do seu workspace (ou domínio próprio, em white label)"}}}],"security":[{"bearerAuth":[]}],"paths":{"/api/v1/send-message":{"post":{"operationId":"sendMessage","summary":"Enviar mensagem de texto para um número","description":"Envia uma mensagem de texto para um número de telefone. Cria o contato e a conversa automaticamente se ainda não existirem. Rate limit: 60 requisições/minuto por workspace.\n","tags":["Mensagens"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendMessageRequest"},"examples":{"default":{"value":{"phone":"5511999998888","message":"Olá! Seu pedido foi confirmado.","channel":"whatsapp-official","contactName":"João Silva"}}}}}},"responses":{"200":{"description":"Mensagem enviada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendMessageResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"502":{"description":"Falha no provedor de envio (WAHA/WhatsApp Oficial/UAZAPI)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/send-template":{"post":{"operationId":"sendTemplate","summary":"Enviar template HSM (WhatsApp Oficial)","description":"Envia um template HSM (mensagem estruturada pré-aprovada pela Meta) via WhatsApp Oficial. Único método válido para iniciar contato com números que não interagiram nas últimas 24 horas. Rate limit: 60/min.\n","tags":["Mensagens"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendTemplateRequest"},"examples":{"default":{"value":{"phone":"5511999998888","channel":"whatsapp-official","templateName":"confirmacao_pedido","language":"pt_BR","variables":["João","Pedido #1234","R$ 150,00"],"contactName":"João Silva"}}}}}},"responses":{"200":{"description":"Template enviado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendTemplateResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/external/messages/send":{"post":{"operationId":"sendToExistingConversation","summary":"Responder numa conversa já existente","description":"Envia uma mensagem em uma conversa já existente no Tivar. Não cria contato nem conversa — ideal para agentes externos (n8n, Typebot, Voiceflow) que recebem `conversation_id` via webhook `message.received` e querem responder na mesma conversa. Sem rate limit próprio.\n","tags":["Mensagens"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendExternalMessageRequest"},"examples":{"default":{"value":{"conversation_id":"uuid-da-conversa","text":"Olá! Em que posso ajudar?","sender_type":"agent","sender_name":"Bot Atendimento"}}}}}},"responses":{"200":{"description":"Mensagem enviada na conversa existente","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendExternalMessageResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"502":{"description":"Falha no provedor de envio (WhatsApp/WAHA/UAZAPI/Telegram)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/leads/{id}":{"patch":{"operationId":"moveLeadStage","summary":"Mover contato de etapa no funil (sem agente de IA)","description":"Move um contato para outra etapa de um funil (Kanban) via API, sem depender de um agente de IA rodando na conversa. Pensado para integrações externas (n8n, Make) que já decidem o roteamento sozinhas — evita dois sistemas respondendo o mesmo lead. Rate limit: 60/min.\n","tags":["Leads"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"ID do contato no Tivar."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MoveLeadStageRequest"},"examples":{"default":{"value":{"pipeline_id":"uuid-do-funil","stage":"Qualificado","conversation_id":"uuid-da-conversa"}}}}}},"responses":{"200":{"description":"Contato movido de etapa","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MoveLeadStageResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}}},"webhooks":{"message.received":{"post":{"summary":"Nova mensagem recebida de um contato","description":"Disparado quando uma nova mensagem chega de um contato externo.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookMessageReceived"}}}},"responses":{"200":{"description":"Confirmação de recebimento (qualquer 2xx é aceito)"}}}},"message.sent":{"post":{"summary":"Mensagem enviada pelo Tivar","description":"Disparado quando o Tivar envia uma mensagem (painel, API ou agente de IA).","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookMessageSent"}}}},"responses":{"200":{"description":"Confirmação de recebimento (qualquer 2xx é aceito)"}}}},"conversation.assigned":{"post":{"summary":"Conversa atribuída ou reatribuída","description":"Disparado quando uma conversa é atribuída/reatribuída a um humano ou agente de IA, ou quando a atribuição é removida (`assigned_to_id: null`).\n","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookConversationAssigned"}}}},"responses":{"200":{"description":"Confirmação de recebimento (qualquer 2xx é aceito)"}}}},"conversation.resolved":{"post":{"summary":"Conversa marcada como resolvida","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookConversationResolved"}}}},"responses":{"200":{"description":"Confirmação de recebimento (qualquer 2xx é aceito)"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"`Authorization: Bearer <workspace_api_key>` — obtenha em Configurações → Workspace → API Key.\n"}},"responses":{"BadRequest":{"description":"Parâmetro obrigatório ausente ou inválido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Unauthorized":{"description":"API Key ausente ou inválida","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Forbidden":{"description":"Workspace inativo/suspenso","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"NotFound":{"description":"Integração ou conversa não encontrada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"RateLimited":{"description":"Limite de 60 requisições/minuto por workspace excedido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"schemas":{"ErrorResponse":{"type":"object","properties":{"error":{"type":"string","description":"Mensagem de erro legível"},"requires_template":{"type":"boolean","description":"Presente (`true`) quando o erro é a janela de 24h da Meta (código 131047) — nesse caso use `/api/v1/send-template` em vez de tentar de novo.\n"},"meta_error_code":{"type":"integer","description":"Código de erro específico da Meta (ex.: 132001, 132000), quando aplicável"}},"required":["error"]},"SendMessageRequest":{"type":"object","required":["phone","message","channel"],"properties":{"phone":{"type":"string","description":"E.164 (+5511999998888) ou só dígitos com DDD (5511999998888). Mínimo 10 dígitos.","example":"5511999998888"},"message":{"type":"string","minLength":1,"maxLength":4096},"channel":{"type":"string","enum":["whatsapp-official","uazapi","waha"]},"integrationId":{"type":"string","format":"uuid","description":"Se omitido, usa a integração conectada mais recente do canal."},"agentId":{"type":"string","format":"uuid","description":"Atribui a conversa a um agente de IA."},"contactName":{"type":"string","description":"Recomendado sempre enviar — sem ele o contato fica sem nome (só telefone) no painel.\n"}}},"SendMessageResponse":{"type":"object","properties":{"success":{"type":"boolean"},"conversationId":{"type":"string","format":"uuid"},"contactId":{"type":"string","format":"uuid"},"messageId":{"type":"string","format":"uuid"},"waMessageId":{"type":"string","description":"ID da mensagem retornado pelo provedor (ex. wamid.xxxxx)"},"contactCreated":{"type":"boolean"},"conversationCreated":{"type":"boolean"},"sent_at":{"type":"string","format":"date-time"}}},"SendTemplateRequest":{"type":"object","required":["phone","channel","templateName"],"properties":{"phone":{"type":"string","example":"5511999998888"},"channel":{"type":"string","enum":["whatsapp-official"]},"templateName":{"type":"string","description":"Nome exato do template aprovado no Meta Business Manager."},"language":{"type":"string","default":"pt_BR"},"variables":{"type":"array","description":"Substituem {{1}}, {{2}}... na ordem do array (só o corpo do template).","items":{"oneOf":[{"type":"string"},{"type":"number"}]}},"headerMedia":{"type":"object","description":"Necessário só se o template tiver header de mídia (imagem/vídeo/documento).","required":["type","link"],"properties":{"type":{"type":"string","enum":["image","video","document"]},"link":{"type":"string","description":"URL pública (sem autenticação) — a Meta baixa direto dessa URL no envio."},"filename":{"type":"string","description":"Só para type \"document\" — nome exibido pro destinatário."}}},"buttons":{"type":"array","description":"Só necessário pra botão com parte DINÂMICA (URL com sufixo variável, ou quick_reply com payload variável). Botão estático (telefone, quick_reply fixo) não precisa disso.\n","items":{"type":"object","required":["index","type"],"properties":{"index":{"type":"integer","minimum":0,"description":"Posição do botão no template (0-based, ordem aprovada na Meta)."},"type":{"type":"string","enum":["url","quick_reply"]},"text":{"type":"string","description":"Obrigatório se type \"url\" — substitui a parte variável do link do botão."},"payload":{"type":"string","description":"Obrigatório se type \"quick_reply\" — valor dinâmico do payload."}}}},"integrationId":{"type":"string","format":"uuid"},"agentId":{"type":"string","format":"uuid"},"contactName":{"type":"string"}}},"SendTemplateResponse":{"type":"object","properties":{"success":{"type":"boolean"},"conversationId":{"type":"string","format":"uuid"},"contactId":{"type":"string","format":"uuid"},"messageId":{"type":"string","format":"uuid"},"waMessageId":{"type":"string"},"contactCreated":{"type":"boolean"},"conversationCreated":{"type":"boolean"},"template":{"type":"object","properties":{"name":{"type":"string"},"language":{"type":"string"},"variables":{"type":"array","items":{"oneOf":[{"type":"string"},{"type":"number"}]}},"headerMedia":{"type":["object","null"]},"buttons":{"type":["array","null"]}}},"sent_at":{"type":"string","format":"date-time"}}},"SendExternalMessageRequest":{"type":"object","required":["conversation_id","text"],"properties":{"conversation_id":{"type":"string","format":"uuid"},"text":{"type":"string"},"sender_type":{"type":"string","enum":["agent","system"],"default":"agent"},"sender_name":{"type":"string","maxLength":120}}},"SendExternalMessageResponse":{"type":"object","properties":{"success":{"type":"boolean"},"message_id":{"type":"string","format":"uuid"},"conversation_id":{"type":"string","format":"uuid"},"workspace_id":{"type":"string","format":"uuid"},"sent_at":{"type":"string","format":"date-time"}}},"MoveLeadStageRequest":{"type":"object","required":["pipeline_id","stage"],"properties":{"pipeline_id":{"type":"string","format":"uuid","description":"Precisa pertencer ao mesmo workspace da API Key."},"stage":{"type":"string","description":"Chave da etapa dentro do funil (a mesma usada em pipelines.stages_config, ex.: \"Aquecendo\", \"Novo Lead\").\n"},"conversation_id":{"type":"string","format":"uuid","description":"Se informado, registra um evento interno (type: system) nessa conversa — visível só pra equipe, nunca enviado ao lead.\n"}}},"MoveLeadStageResponse":{"type":"object","properties":{"success":{"type":"boolean"},"contact_id":{"type":"string","format":"uuid"},"pipeline_id":{"type":"string","format":"uuid"},"stage":{"type":"string"}}},"WebhookContact":{"type":"object","properties":{"id":{"type":["string","null"],"format":"uuid"},"phone":{"type":["string","null"]},"name":{"type":["string","null"]}}},"WebhookIntegration":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"provider":{"type":"string","enum":["whatsapp-official","whatsapp","telegram","instagram","messenger","livechat","mercado_livre"]}}},"WebhookMessageReceived":{"type":"object","properties":{"event":{"type":"string","const":"message.received"},"workspace_id":{"type":"string","format":"uuid"},"conversation_id":{"type":"string","format":"uuid"},"contact":{"$ref":"#/components/schemas/WebhookContact"},"message":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"text":{"type":"string"},"type":{"type":"string","description":"text, image, audio, video, document, location, etc."}}},"status":{"type":"object","properties":{"assigned_to_type":{"type":["string","null"],"enum":["human","agent",null]},"assigned_to_id":{"type":["string","null"],"format":"uuid"}}},"integration":{"$ref":"#/components/schemas/WebhookIntegration"}}},"WebhookMessageSent":{"type":"object","properties":{"event":{"type":"string","const":"message.sent"},"workspace_id":{"type":"string","format":"uuid"},"conversation_id":{"type":"string","format":"uuid"},"message":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"text":{"type":"string"},"type":{"type":"string"}}},"status":{"type":"object","properties":{"sender_type":{"type":"string","enum":["human","agent","system"]}}},"integration":{"$ref":"#/components/schemas/WebhookIntegration"}}},"WebhookConversationAssigned":{"type":"object","properties":{"event":{"type":"string","const":"conversation.assigned"},"workspace_id":{"type":"string","format":"uuid"},"conversation_id":{"type":"string","format":"uuid"},"status":{"type":"object","properties":{"assigned_to_type":{"type":["string","null"],"enum":["human","agent",null]},"assigned_to_id":{"type":["string","null"],"format":"uuid"}}}}},"WebhookConversationResolved":{"type":"object","properties":{"event":{"type":"string","const":"conversation.resolved"},"workspace_id":{"type":"string","format":"uuid"},"conversation_id":{"type":"string","format":"uuid"},"status":{"type":"object","properties":{"value":{"type":"string","const":"resolved"}}}}}}}}