# LYMOS CRM: API REST

> API do LYMOS CRM (atendimento e vendas pelo WhatsApp) para integrar sites, formulários, lojas, ERPs, n8n, Make e scripts. Atualizada em 12 de outubro de 2026.

## Essencial

- URL base: `https://crm.lymos.com.br/api/v1`
- Autenticação: cabeçalho `Authorization: Bearer <token>` (ou `X-API-Key: <token>`). O token começa com `crm_`.
- Onde criar o token: no CRM, Ajustes > Integrações > API > Gerar token. Ele aparece uma vez só; guarde num lugar seguro.
- Cada token é de uma conta (empresa) e enxerga só os dados dela. Apague o token em Ajustes > Integrações se vazar.
- Corpo e respostas em JSON (`Content-Type: application/json`). Datas em milissegundos desde 1970 (Unix ms), salvo onde indicado.
- Erros: status HTTP + `{ "error": "mensagem em português" }`.
- Telefones: só dígitos, com DDI e DDD (ex.: 5511999990000).

## Contatos

### GET /contacts

Listar e buscar contatos. Devolve os contatos não arquivados, do mais recente para o mais antigo.

Parâmetros de consulta:

- `q` (texto): Busca no nome, nome do WhatsApp, empresa e e-mail
- `phone` (texto): Telefone (só os dígitos contam; acha pelo final do número)
- `tag` (texto ou número): Nome ou id de uma etiqueta
- `limit` (número): Quantos devolver (padrão 50, máximo 500)
- `offset` (número): Pular os primeiros N (paginação)

Exemplo:

```bash
curl -X GET 'https://crm.lymos.com.br/api/v1/contacts?tag=Lead%20quente&limit=20' \
  -H 'Authorization: Bearer crm_SEU_TOKEN'
```

Resposta:

```json
{
  "items": [
    {
      "id": 128,
      "name": "Ana Souza",
      "display_name": "Ana Souza",
      "phone": "5511999990000",
      "email": "ana@exemplo.com.br",
      "company": "Loja da Ana",
      "role": "Sócia",
      "city": "São Paulo",
      "birthday": "1990-05-14",
      "how_met": "Instagram",
      "stage_id": 3,
      "deal_value": 49700,
      "cadence_days": 15,
      "starred": false,
      "archived": false,
      "custom": {
        "plano_interesse": "Profissional"
      },
      "tags": [
        {
          "id": 7,
          "name": "Lead quente",
          "color": "#e5484d"
        }
      ],
      "last_message_at": 1791846000000,
      "created_at": 1791800000000,
      "updated_at": 1791846000000
    }
  ]
}
```

### GET /contacts/{id}

Ver um contato. Ficha completa do contato, com etiquetas e campos personalizados.

Exemplo:

```bash
curl -X GET 'https://crm.lymos.com.br/api/v1/contacts/128' \
  -H 'Authorization: Bearer crm_SEU_TOKEN'
```

Resposta:

```json
{
  "id": 128,
  "name": "Ana Souza",
  "display_name": "Ana Souza",
  "phone": "5511999990000",
  "email": "ana@exemplo.com.br",
  "company": "Loja da Ana",
  "role": "Sócia",
  "city": "São Paulo",
  "birthday": "1990-05-14",
  "how_met": "Instagram",
  "stage_id": 3,
  "deal_value": 49700,
  "cadence_days": 15,
  "starred": false,
  "archived": false,
  "custom": {
    "plano_interesse": "Profissional"
  },
  "tags": [
    {
      "id": 7,
      "name": "Lead quente",
      "color": "#e5484d"
    }
  ],
  "last_message_at": 1791846000000,
  "created_at": 1791800000000,
  "updated_at": 1791846000000
}
```

### POST /contacts

Criar ou atualizar pelo telefone. Se já existe um contato com esse WhatsApp, ele é atualizado (resposta 200); senão, é criado (201) e as automações de "Contato novo" rodam. Mande phone com DDI e DDD. Sem phone, name é obrigatório e o contato é criado sem WhatsApp.

Corpo (JSON):

- `phone` (texto): WhatsApp com DDI, ex.: 5511999990000
- `name` (texto): Nome
- `email` (texto): E-mail
- `company` (texto): Empresa
- `role` (texto): Cargo
- `city` (texto): Cidade
- `birthday` (texto): Aniversário: AAAA-MM-DD ou --MM-DD
- `how_met` (texto): Como conheceu / origem
- `deal_value` (número): Valor do negócio em centavos (49700 = R$ 497,00)
- `cadence_days` (número): Falar com ele a cada N dias
- `stage_id` (número): Etapa do funil (veja GET /stages)
- `tags` (lista): Etiquetas por nome (cria se não existir) ou id
- `custom` (objeto): Campos personalizados: { "campo": "valor" }

Exemplo:

```bash
curl -X POST 'https://crm.lymos.com.br/api/v1/contacts' \
  -H 'Authorization: Bearer crm_SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"phone":"5511999990000","name":"Ana Souza","company":"Loja da Ana","tags":["Site","Lead quente"],"custom":{"plano_interesse":"Profissional"}}'
```

Resposta:

```json
{
  "id": 128,
  "name": "Ana Souza",
  "display_name": "Ana Souza",
  "phone": "5511999990000",
  "email": "ana@exemplo.com.br",
  "company": "Loja da Ana",
  "role": "Sócia",
  "city": "São Paulo",
  "birthday": "1990-05-14",
  "how_met": "Instagram",
  "stage_id": 3,
  "deal_value": 49700,
  "cadence_days": 15,
  "starred": false,
  "archived": false,
  "custom": {
    "plano_interesse": "Profissional"
  },
  "tags": [
    {
      "id": 7,
      "name": "Lead quente",
      "color": "#e5484d"
    }
  ],
  "last_message_at": 1791846000000,
  "created_at": 1791800000000,
  "updated_at": 1791846000000
}
```

### PATCH /contacts/{id}

Atualizar um contato. Mude só os campos que mandar (os mesmos do POST, menos phone). Mandar "" apaga o campo.

Exemplo:

```bash
curl -X PATCH 'https://crm.lymos.com.br/api/v1/contacts/128' \
  -H 'Authorization: Bearer crm_SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"stage_id":4,"deal_value":99700}'
```

Resposta:

```json
{
  "id": 128,
  "name": "Ana Souza",
  "display_name": "Ana Souza",
  "phone": "5511999990000",
  "email": "ana@exemplo.com.br",
  "company": "Loja da Ana",
  "role": "Sócia",
  "city": "São Paulo",
  "birthday": "1990-05-14",
  "how_met": "Instagram",
  "stage_id": 3,
  "deal_value": 49700,
  "cadence_days": 15,
  "starred": false,
  "archived": false,
  "custom": {
    "plano_interesse": "Profissional"
  },
  "tags": [
    {
      "id": 7,
      "name": "Lead quente",
      "color": "#e5484d"
    }
  ],
  "last_message_at": 1791846000000,
  "created_at": 1791800000000,
  "updated_at": 1791846000000
}
```

## Etiquetas

### POST /contacts/{id}/tags

Pôr uma etiqueta. Por nome (cria a etiqueta se não existir) ou por id. Pode disparar automações de "Tag adicionada".

Corpo (JSON):

- `name` (texto): Nome da etiqueta
- `tag_id` (número): Ou o id de uma etiqueta existente

Exemplo:

```bash
curl -X POST 'https://crm.lymos.com.br/api/v1/contacts/128/tags' \
  -H 'Authorization: Bearer crm_SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"name":"Cliente"}'
```

Resposta:

```json
{
  "id": 128,
  "name": "Ana Souza",
  "display_name": "Ana Souza",
  "phone": "5511999990000",
  "email": "ana@exemplo.com.br",
  "company": "Loja da Ana",
  "role": "Sócia",
  "city": "São Paulo",
  "birthday": "1990-05-14",
  "how_met": "Instagram",
  "stage_id": 3,
  "deal_value": 49700,
  "cadence_days": 15,
  "starred": false,
  "archived": false,
  "custom": {
    "plano_interesse": "Profissional"
  },
  "tags": [
    {
      "id": 7,
      "name": "Lead quente",
      "color": "#e5484d"
    }
  ],
  "last_message_at": 1791846000000,
  "created_at": 1791800000000,
  "updated_at": 1791846000000
}
```

### DELETE /contacts/{id}/tags/{tagId}

Tirar uma etiqueta.

Exemplo:

```bash
curl -X DELETE 'https://crm.lymos.com.br/api/v1/contacts/128/tags/7' \
  -H 'Authorization: Bearer crm_SEU_TOKEN'
```

Resposta:

```json
{
  "id": 128,
  "name": "Ana Souza",
  "display_name": "Ana Souza",
  "phone": "5511999990000",
  "email": "ana@exemplo.com.br",
  "company": "Loja da Ana",
  "role": "Sócia",
  "city": "São Paulo",
  "birthday": "1990-05-14",
  "how_met": "Instagram",
  "stage_id": 3,
  "deal_value": 49700,
  "cadence_days": 15,
  "starred": false,
  "archived": false,
  "custom": {
    "plano_interesse": "Profissional"
  },
  "tags": [
    {
      "id": 7,
      "name": "Lead quente",
      "color": "#e5484d"
    }
  ],
  "last_message_at": 1791846000000,
  "created_at": 1791800000000,
  "updated_at": 1791846000000
}
```

### GET /tags

Listar etiquetas.

Exemplo:

```bash
curl -X GET 'https://crm.lymos.com.br/api/v1/tags' \
  -H 'Authorization: Bearer crm_SEU_TOKEN'
```

Resposta:

```json
{
  "items": [
    {
      "id": 7,
      "name": "Lead quente",
      "color": "#e5484d"
    }
  ]
}
```

## Funil

### GET /stages

Listar etapas do funil. kind: open (em andamento), won (ganho) ou lost (perdido).

Exemplo:

```bash
curl -X GET 'https://crm.lymos.com.br/api/v1/stages' \
  -H 'Authorization: Bearer crm_SEU_TOKEN'
```

Resposta:

```json
{
  "items": [
    {
      "id": 3,
      "name": "Proposta",
      "kind": "open"
    }
  ]
}
```

## Conversa

### POST /contacts/{id}/messages

Enviar mensagem de WhatsApp. Manda um texto pelo WhatsApp conectado, como se fosse você. Respeita os limites de envio da conta. No WhatsApp oficial (API da Meta), fora da janela de 24 horas só modelos aprovados são entregues: use um fluxo ou automação com modelo.

Corpo (JSON):

- `text` (texto, obrigatório): Mensagem

Exemplo:

```bash
curl -X POST 'https://crm.lymos.com.br/api/v1/contacts/128/messages' \
  -H 'Authorization: Bearer crm_SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"text":"Oi, Ana! Seu pedido saiu para entrega."}'
```

Resposta:

```json
{
  "id": 5521,
  "contact_id": 128,
  "from_me": true,
  "type": "text",
  "body": "Oi, Ana! Seu pedido saiu para entrega.",
  "sent_by": "api",
  "status": "pending"
}
```

### GET /contacts/{id}/messages

Ler as últimas mensagens. Da mais nova para a mais antiga. ts em milissegundos.

Parâmetros de consulta:

- `limit` (número): Quantas (padrão 50, máximo 500)

Exemplo:

```bash
curl -X GET 'https://crm.lymos.com.br/api/v1/contacts/128/messages?limit=10' \
  -H 'Authorization: Bearer crm_SEU_TOKEN'
```

Resposta:

```json
{
  "items": [
    {
      "id": 5520,
      "wa_id": "3EB0…",
      "from_me": false,
      "type": "text",
      "body": "Qual o prazo de entrega?",
      "status": null,
      "sent_by": null,
      "ts": 1791845900000
    }
  ]
}
```

### POST /contacts/{id}/notes

Anotar na ficha.

Corpo (JSON):

- `body` (texto, obrigatório): Texto da nota

Exemplo:

```bash
curl -X POST 'https://crm.lymos.com.br/api/v1/contacts/128/notes' \
  -H 'Authorization: Bearer crm_SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"body":"Pediu orçamento pelo site: 3 usuários."}'
```

Resposta:

```json
{
  "id": 902,
  "contact_id": 128,
  "body": "Pediu orçamento pelo site: 3 usuários.",
  "pinned": 0
}
```

### POST /contacts/{id}/reminders

Criar tarefa / lembrete.

Corpo (JSON):

- `title` (texto, obrigatório): O que fazer
- `due_at` (número ou data, obrigatório): Quando: milissegundos ou data ISO (2026-10-20T14:00:00-03:00)

Exemplo:

```bash
curl -X POST 'https://crm.lymos.com.br/api/v1/contacts/128/reminders' \
  -H 'Authorization: Bearer crm_SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"title":"Ligar para fechar","due_at":"2026-10-20T14:00:00-03:00"}'
```

Resposta:

```json
{
  "id": 77,
  "contact_id": 128,
  "title": "Ligar para fechar",
  "due_at": 1792515600000
}
```

## Fluxos e automações

### POST /contacts/{id}/flows/{flowId}

Iniciar um fluxo de atendimento. O id do fluxo aparece no endereço da tela do fluxo. Responde 409 com o motivo quando o contato não pode entrar (ex.: já está nesse fluxo).

Corpo (JSON):

- `force` (sim/não): Iniciar mesmo se ele já passou por esse fluxo

Exemplo:

```bash
curl -X POST 'https://crm.lymos.com.br/api/v1/contacts/128/flows/12' \
  -H 'Authorization: Bearer crm_SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{}'
```

Resposta:

```json
{
  "ok": true
}
```

### POST /automations/{id}/run

Rodar uma automação para um contato. Roda as ações da automação agora. O que mandar em data fica disponível nas mensagens como {{dados.campo}}. status volta ok, ou skipped com o motivo em detail (ex.: condições não atendidas).

Corpo (JSON):

- `contact_id` (número, obrigatório): Contato
- `data` (objeto): Dados extras para as mensagens
- `force` (sim/não): Ignorar condições e limite de repetição

Exemplo:

```bash
curl -X POST 'https://crm.lymos.com.br/api/v1/automations/5/run' \
  -H 'Authorization: Bearer crm_SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"contact_id":128,"data":{"pedido":"1043"}}'
```

Resposta:

```json
{
  "status": "ok",
  "detail": "Enviou a mensagem \"Seu pedido 1043 foi confirmado\""
}
```

## Webhooks de saída (o CRM avisa o seu sistema)

Cadastre a URL em Ajustes > Integrações > Webhooks e escolha os eventos (ou todos). O CRM faz POST em JSON:

```json
{
  "event": "contact.tag_added",
  "sent_at": "2026-10-12T20:15:00.000Z",
  "tagId": 7,
  "contact": {
    "id": 128,
    "name": "Ana Souza",
    "display_name": "Ana Souza",
    "phone": "5511999990000",
    "email": "ana@exemplo.com.br",
    "company": "Loja da Ana",
    "role": "Sócia",
    "city": "São Paulo",
    "birthday": "1990-05-14",
    "how_met": "Instagram",
    "stage_id": 3,
    "deal_value": 49700,
    "cadence_days": 15,
    "starred": false,
    "archived": false,
    "custom": {
      "plano_interesse": "Profissional"
    },
    "tags": [
      {
        "id": 7,
        "name": "Lead quente",
        "color": "#e5484d"
      }
    ],
    "last_message_at": 1791846000000,
    "created_at": 1791800000000,
    "updated_at": 1791846000000
  }
}
```

Cabeçalhos: `X-CRM-Event` (o evento) e `X-CRM-Signature: sha256=<hmac>` (HMAC-SHA256 do corpo cru com o segredo do webhook). Responda 2xx em até 15 s. Falhas de rede, 5xx e 429 são tentadas de novo até 3 vezes.

Eventos:

- `message.received`: Chegou mensagem de um contato
- `message.sent`: Uma mensagem foi enviada
- `contact.created`: Contato novo
- `contact.updated`: Ficha alterada
- `contact.stage_changed`: Mudou de etapa no funil
- `contact.tag_added`: Ganhou etiqueta
- `contact.tag_removed`: Perdeu etiqueta
- `contact.assigned`: Conversa atribuída a alguém da equipe
- `reminder.created`: Tarefa criada
- `reminder.done`: Tarefa concluída
- `flow.completed`: Contato terminou um fluxo
- `flow.handoff`: Fluxo ou IA pediu atendimento humano

Conferir a assinatura (Node.js):

```js
import crypto from 'node:crypto';

// corpo = o texto cru recebido (antes do JSON.parse); segredo = o do webhook no CRM
function assinaturaOk(corpo, cabecalho, segredo) {
  const esperado = 'sha256=' + crypto.createHmac('sha256', segredo).update(corpo).digest('hex');
  return cabecalho && crypto.timingSafeEqual(Buffer.from(cabecalho), Buffer.from(esperado));
}
```

## Webhook de entrada (seu sistema dispara uma automação)

Em Automação > Automações, crie uma automação com o gatilho "Outro sistema chamou". Ela ganha uma URL secreta (`https://crm.lymos.com.br/hooks/in/<segredo>`) que não precisa de token. Faça POST em JSON com `phone` (ou `contact_id`), `name` e o que mais quiser: cada campo vira `{{dados.campo}}` nas mensagens. Contato que não existe é criado (dá para desligar na automação). Mande `dedupe_key` para não rodar duas vezes o mesmo evento. Resposta 200 com o resultado, ou 202 `{ "status": "queued" }` quando o envio ainda está acontecendo.

```bash
curl -X POST 'https://crm.lymos.com.br/hooks/in/SEU_SEGREDO' -H 'Content-Type: application/json' -d '{"phone":"5511999990000","name":"Ana Souza","pedido":"1043","dedupe_key":"pedido-1043"}'
```

## Erros

- `400`: Faltou um campo obrigatório ou ele veio errado. A mensagem diz qual.
- `401`: Sem token ou token inválido.
- `404`: Contato, fluxo ou automação não existe nesta conta.
- `409`: Não deu para fazer agora (ex.: fluxo não iniciado, automação desligada). A mensagem diz o motivo.
- `5xx`: Erro do nosso lado. Tente de novo em alguns segundos.

## Boas práticas

- Guarde o token numa variável de ambiente, nunca no front-end ou no repositório.
- Use POST /contacts para "criar ou atualizar" pelo telefone: não precisa buscar antes.
- Envio de mensagens tem ritmo e limite por contato para proteger o número. Para disparos em massa use Campanhas no CRM.
- Prefira webhooks de saída a ficar consultando a API em intervalos curtos.

## Links

- Documentação: https://crm.lymos.com.br/docs
- OpenAPI 3.1: https://crm.lymos.com.br/docs/openapi.json
- LYMOS CRM: https://lymos.com.br/crm
- Teste grátis de 7 dias: https://crm.lymos.com.br/cadastro
- Suporte: contato@lymos.com.br
