{"openapi":"3.0.3","info":{"title":"Hosthy API","description":"API oficial da Hosthy para integrações com WhatsApp Business. Permite gerenciar contatos, conversas, enviar mensagens e receber eventos via webhooks.\n\n**Autenticação:** API Key via header `Authorization: Bearer <chave>` ou `X-API-Key: <chave>`. A chave é um token de 56 caracteres hexadecimais, sem prefixo.\n\n**Modelo de cobrança:**\n- Hosthy cobra a mensalidade da plataforma\n- Custos de mensagens WhatsApp são cobrados pela Meta diretamente na conta Business do cliente\n- A Hosthy não cobra por templates ou mensagens Meta\n\n**Janela 24h:** Texto livre só pode ser enviado dentro da janela de 24h após o cliente responder. Fora da janela, use templates aprovados.","version":"1.4.0","contact":{"name":"Hosthy","url":"https://hosthy.com.br"},"license":{"name":"Proprietary"}},"servers":[{"url":"https://api.hosthy.com.br/public-api/v1","description":"Produção"}],"tags":[{"name":"Auth","description":"Verificação de identidade da API Key"},{"name":"Contacts","description":"Gerenciamento de contatos"},{"name":"Conversations","description":"Conversas e histórico de mensagens"},{"name":"Messages","description":"Envio de mensagens"},{"name":"Tags","description":"Tags para organização de contatos"}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"http","scheme":"bearer","bearerFormat":"<chave-56-hex>","description":"API Key gerada no painel Hosthy. Formato: token de 56 caracteres hexadecimais sem prefixo. Use o header `Authorization: Bearer SUA_CHAVE` ou `X-API-Key: SUA_CHAVE`."}},"schemas":{"Contact":{"type":"object","properties":{"id":{"type":"string","example":"a3f8c2d1-4e5b-6789-abcd-ef0123456789"},"name":{"type":"string","nullable":true,"example":"João Silva"},"phone":{"type":"string","description":"Telefone no formato canonical wa_id (sem + ou caracteres especiais)","example":"5551992371100"},"email":{"type":"string","nullable":true,"example":"joao@exemplo.com"},"notes":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CreateContactBody":{"type":"object","required":["name","phone"],"properties":{"name":{"type":"string","minLength":1,"maxLength":200,"example":"Maria Souza"},"phone":{"type":"string","minLength":7,"maxLength":30,"description":"Aceita formatos variados. Normalizado automaticamente. Ex: +55 51 99237-1100 → 555192371100","example":"5541991392989"},"email":{"type":"string","format":"email","example":"maria@exemplo.com"},"notes":{"type":"string","maxLength":2000}}},"Conversation":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["open","pending","closed"]},"stage":{"type":"string","example":"em_atendimento"},"unreadCount":{"type":"integer"},"lastMessage":{"type":"string","nullable":true},"lastMessageAt":{"type":"string","format":"date-time","nullable":true},"contact":{"$ref":"#/components/schemas/ContactSummary"},"createdAt":{"type":"string","format":"date-time"}}},"ContactSummary":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","nullable":true},"phone":{"type":"string"}}},"Message":{"type":"object","properties":{"id":{"type":"string"},"content":{"type":"string","nullable":true},"direction":{"type":"string","enum":["in","out"]},"type":{"type":"string","enum":["text","image","audio","video","document","template"]},"status":{"type":"string","enum":["sent","delivered","read","failed"]},"sendStatus":{"type":"string","enum":["pending","sending","sent","retrying","failed"]},"waMessageId":{"type":"string","nullable":true,"description":"ID da mensagem no sistema Meta"},"createdAt":{"type":"string","format":"date-time"}}},"Tag":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"color":{"type":"string","example":"#6366f1"},"description":{"type":"string","nullable":true}}},"MeResponse":{"type":"object","properties":{"keyId":{"type":"string"},"tenantId":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"},"example":["contacts.read","messages.send"]},"tenant":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"subdomain":{"type":"string"},"plan":{"type":"string"},"active":{"type":"boolean"}}}}},"Pagination":{"type":"object","properties":{"total":{"type":"integer"},"page":{"type":"integer"},"limit":{"type":"integer"},"pages":{"type":"integer"}}},"Error":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"object"}}}}},"security":[{"ApiKeyAuth":[]}],"paths":{"/me":{"get":{"tags":["Auth"],"summary":"Verificar identidade da API Key","description":"Retorna informações da API Key e do tenant. Use para verificar se a chave é válida e quais scopes possui.","operationId":"getMe","responses":{"200":{"description":"API Key válida","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeResponse"},"example":{"keyId":"a3f8c2d1-4e5b-6789-abcd-ef0123456789","tenantId":"b9e7d6c5-3f2a-1098-dcba-fedcba987654","scopes":["contacts.read","messages.send"],"tenant":{"id":"b9e7d6c5-3f2a-1098-dcba-fedcba987654","name":"Minha Empresa","subdomain":"minhaempresa","plan":"business","active":true}}}}},"401":{"description":"API Key ausente ou inválida","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/contacts":{"get":{"tags":["Contacts"],"summary":"Listar contatos","description":"Lista contatos do tenant com suporte a busca e paginação.","operationId":"listContacts","security":[{"ApiKeyAuth":["contacts.read"]}],"parameters":[{"name":"search","in":"query","schema":{"type":"string"},"description":"Busca por nome, telefone ou e-mail"},{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":100}}],"responses":{"200":{"description":"Lista de contatos","content":{"application/json":{"schema":{"type":"object","properties":{"contacts":{"type":"array","items":{"$ref":"#/components/schemas/Contact"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"401":{"description":"Não autorizado"},"403":{"description":"Scope contacts.read não concedido"}}},"post":{"tags":["Contacts"],"summary":"Criar contato","description":"Cria um novo contato. O telefone é normalizado automaticamente para o formato wa_id da Meta. Retorna 409 se o telefone já existir.","operationId":"createContact","security":[{"ApiKeyAuth":["contacts.write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateContactBody"},"example":{"name":"Maria Souza","phone":"5541991392989","email":"maria@exemplo.com"}}}},"responses":{"201":{"description":"Contato criado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"}}}},"400":{"description":"Dados inválidos"},"409":{"description":"Telefone já cadastrado"}}}},"/contacts/{id}":{"get":{"tags":["Contacts"],"summary":"Buscar contato por ID","operationId":"getContact","security":[{"ApiKeyAuth":["contacts.read"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"ID do contato"}],"responses":{"200":{"description":"Contato encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"}}}},"404":{"description":"Contato não encontrado"}}}},"/contacts/{id}/tags/{tagId}":{"post":{"tags":["Tags"],"summary":"Adicionar tag a contato","operationId":"addTagToContact","security":[{"ApiKeyAuth":["tags.write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"tagId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"Tag adicionada"},"404":{"description":"Contato ou tag não encontrado"}}},"delete":{"tags":["Tags"],"summary":"Remover tag de contato","operationId":"removeTagFromContact","security":[{"ApiKeyAuth":["tags.write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"tagId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tag removida"},"404":{"description":"Contato ou tag não encontrado"}}}},"/conversations":{"get":{"tags":["Conversations"],"summary":"Listar conversas","operationId":"listConversations","security":[{"ApiKeyAuth":["conversations.read"]}],"parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["open","pending","closed"]}},{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":100}}],"responses":{"200":{"description":"Lista de conversas","content":{"application/json":{"schema":{"type":"object","properties":{"conversations":{"type":"array","items":{"$ref":"#/components/schemas/Conversation"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}}}}},"/conversations/{id}":{"get":{"tags":["Conversations"],"summary":"Buscar conversa com mensagens","description":"Retorna a conversa com as últimas 20 mensagens.","operationId":"getConversation","security":[{"ApiKeyAuth":["conversations.read"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Conversa com mensagens","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Conversation"},{"type":"object","properties":{"messages":{"type":"array","items":{"$ref":"#/components/schemas/Message"}}}}]}}}},"404":{"description":"Conversa não encontrada"}}}},"/conversations/{id}/messages":{"post":{"tags":["Messages"],"summary":"Enviar mensagem em uma conversa","description":"Envia uma mensagem de texto em uma conversa existente. **Importante:** só funciona dentro da janela de atendimento de 24h (quando o cliente enviou uma mensagem nos últimos 24h). Fora da janela, retorna 422 — use templates aprovados no painel autenticado.","operationId":"sendMessage","security":[{"ApiKeyAuth":["messages.send"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"ID da conversa"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["content"],"properties":{"content":{"type":"string","minLength":1,"maxLength":4096,"example":"Olá! Como posso ajudar?"}}}}}},"responses":{"201":{"description":"Mensagem criada e enfileirada para envio","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"},"example":{"id":"a3f8c2d1-4e5b-6789-abcd-ef0123456789","content":"Olá! Como posso ajudar?","direction":"out","type":"text","status":"sent","sendStatus":"pending","waMessageId":null,"createdAt":"2024-01-15T14:30:00Z"}}}},"400":{"description":"Dados inválidos ou conversa sem número associado"},"404":{"description":"Conversa não encontrada"},"422":{"description":"Fora da janela de atendimento de 24h","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Fora da janela de atendimento de 24h. Use um template aprovado."},"code":{"type":"string","example":"OUTSIDE_24H_WINDOW"},"requiresTemplate":{"type":"boolean","example":true}}}}}}}}},"/tags":{"get":{"tags":["Tags"],"summary":"Listar tags disponíveis","description":"Retorna todas as tags ativas do tenant.","operationId":"listTags","security":[{"ApiKeyAuth":["tags.read"]}],"responses":{"200":{"description":"Lista de tags","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Tag"}}}}}}}}}}