> ## Documentation Index
> Fetch the complete documentation index at: https://docs.wegly.com.br/llms.txt
> Use this file to discover all available pages before exploring further.

# Leads e oportunidades

> Captação, pessoas, rastreio, atualizações e consultas pela API externa.

Leads usam `/integrations/external/leads`; oportunidades usam `/integrations/external/deals`. Todas as chamadas exigem `Authorization: Bearer SUA_CHAVE` e operam na empresa da chave. O usuário que criou a chave é o ator das operações e o responsável padrão quando `responsible_id` é omitido.

| Ação | Leads | Oportunidades |
| - | - | - |
| Listar e consultar | `crm/lead.read` | `crm/deal.read` |
| Criar | `crm/lead.create` | `crm/deal.create` |
| Atualizar e gerenciar seguidores | `crm/lead.update` | `crm/deal.update` |
| Incluir resumos de chats na leitura | `crm/chats.read` | `crm/chats.read` |

## Criar e evitar duplicidades

`title` é obrigatório e aceita até 150 caracteres. Se `stage_id` for omitido, a API utiliza a primeira etapa do funil principal correspondente. `visibility` assume `0`: leads aceitam `0` (privado) ou `1` (time); oportunidades também aceitam `2` (público).

`responsible_id` recebe o ID de um usuário da empresa. Se o usuário informado existir, mas estiver inativo ou arquivado, a criação não falha: o registro é atribuído ao usuário master da conta e recebe uma nota automática explicando a substituição. Um usuário inexistente ou de outra empresa retorna `400`. Essa substituição vale apenas para a criação; no `PUT`, um responsável inativo retorna `400`.

Contatos pertencem à pessoa. Para cadastrar e associar uma pessoa, envie `person.name` e `person.contacts`. Para vincular pessoas existentes, envie `persons_id` como uma lista de objetos com `person_id`. No lead, `phone` e `email` no primeiro nível são rejeitados com `400`.

```bash theme={null}
curl --request POST 'https://api.wegly.com.br/integrations/external/leads' \
  --header 'Authorization: Bearer SUA_CHAVE' \
  --header 'Content-Type: application/json' \
  --header 'x-idempotency-key: formulario-contato-2026-00042' \
  --data '{
    "title": "Interesse no plano Enterprise",
    "measurement_consent": "GRANTED",
    "person": {
      "name": "Marina Souza",
      "contacts": [
        { "type": 0, "value": "11999999999", "primary": true },
        { "type": 1, "value": "marina@example.com" }
      ],
      "avoid_duplicate": true,
      "duplicate_check_types": [0, 1]
    },
    "marketing": {
      "utm_source": "google",
      "utm_medium": "cpc",
      "utm_campaign": "enterprise-setembro",
      "url_conversion": "https://example.com/contato?utm_source=google&utm_medium=cpc"
    },
    "note": {
      "content": "Solicitou uma demonstração.",
      "is_pinned": true
    }
  }'
```

Resposta `201`:

```json theme={null}
{
  "id": "123e4567-e89b-42d3-a456-426614174000",
  "code": 1042,
  "title": "Interesse no plano Enterprise",
  "measurement_consent": "GRANTED"
}
```

O mesmo formato de resposta se aplica à criação de oportunidades. Para criar uma oportunidade, use `/deals` e, quando necessário, inclua `value`, `expected_close_date`, `temperature` (`1`, `2` ou `3`) e `primary_person_id`.

A deduplicação de pessoa e a idempotência resolvem situações diferentes:

* Na criação, `person.avoid_duplicate: true` com `duplicate_check_types` preenchido procura uma pessoa da empresa que corresponda a **qualquer** contato dos tipos indicados. Reutiliza a primeira correspondência e acrescenta contatos faltantes. O nome, documentos e outros dados enviados não substituem os da pessoa reutilizada. Telefones consideram variantes brasileiras com e sem DDI `55`.
* `x-idempotency-key` identifica a tentativa lógica de criar o lead ou a oportunidade. Também é possível enviar `idempotency_key` no body, com até 255 caracteres; o header preenchido tem prioridade. Repetições de uma tentativa já concluída retornam o mesmo registro. Uma tentativa ainda em processamento retorna `409`. Use a mesma chave para repetir uma chamada que ficou sem resposta e outra chave para uma nova criação. A chave vale por chave de integração e é compartilhada entre leads e oportunidades.

Se a criação falhar depois de iniciada, a chave fica consumida e continua retornando `409`: corrija a requisição e envie uma nova chave. Isso acontece, por exemplo, quando a etapa, a tag, a pessoa, a organização ou a origem informada não existe, quando falta um campo personalizado obrigatório ou quando há erro ao gravar seguidores ou nota. Erros de validação do corpo, de consentimento e de responsável ocorrem antes disso e não consomem a chave.

Os tipos de contato são `0` WhatsApp, `1` e-mail, `2` celular, `3` telefone, `4` Instagram, `5` Facebook, `6` LinkedIn e `7` outros. Telefones (tipos `0`, `2` e `3`) devem ter 10 ou 11 dígitos, com DDD e sem o DDI `55`; os caracteres não numéricos são removidos antes da validação. O tipo `1` precisa ser um e-mail válido. A pessoa também aceita `documents`, `address` e `addresses`. Consulte os schemas das rotas para formatos, tipos de documento e campos de endereço.

## Origem, rastreio e consentimento

Para informar uma origem cadastrada manualmente, use `crm_lead_source_id`. O campo de entrada `lead_source` é rejeitado tanto em leads quanto em oportunidades.

Quando `crm_lead_source_id` é enviado, ele define a origem exibida no registro. Sem ele, vale a origem do tracker ativo indicado por `marketing.wegly_code` e, por último, a origem textual em `marketing.wegly_source` ou `marketing.utm_source`. Se o tracker e `crm_lead_source_id` forem enviados juntos, o tracker continua vinculado à aquisição, mas a origem retornada em `lead_source` ou `deal_source` e usada nos filtros é a de `crm_lead_source_id`.

A origem textual busca uma origem ativa pelo ID ou pelo nome e cria uma quando o nome ainda não existe; um texto em formato de UUID que não corresponda a uma origem ativa não cria origem. `wegly_source` tem prioridade sobre `utm_source`. `IG`, em qualquer combinação de maiúsculas e minúsculas, é tratado como a origem `Instagram` e não cria outra origem.

`marketing.url_conversion` preenche parâmetros de rastreio ausentes no objeto, incluindo parâmetros Wegly/UTM, `gclid`, `fbclid`, `oppref` e `obref`. Valores informados explicitamente têm prioridade. `utm_medium` é preservado. O contrato também aceita `fbc`, `fbp`, `client_ip_address`, `client_user_agent` e `ga_client_id`.

`measurement_consent` no primeiro nível é o campo canônico e aceita `GRANTED`, `DENIED` ou `UNSPECIFIED`. O valor deve representar a decisão efetiva do contato. Na criação, a omissão usa `GRANTED`; no PUT, a omissão preserva o valor existente.

O alias legado `marketing.measurement_consent` e o parâmetro `measurement_consent` em `marketing.url_conversion` continuam aceitos. Valores conflitantes retornam `400` antes de qualquer mutação. Um valor desconhecido na URL, parâmetros repetidos divergentes ou uma URL malformada que contenha a chave são tratados como `UNSPECIFIED`.

Sem consentimento efetivo `GRANTED`, a API remove `obref` e suas ocorrências na query da URL e descarta o fragmento da URL. A revogação também sanitiza o histórico. Alterar apenas o consentimento, enviar `marketing: {}` ou somente valores vazios não cria um novo registro de aquisição.

No `PUT`, `marketing` corrige a aquisição atual do registro em vez de criar outra: os campos enviados substituem os valores atuais, os omitidos são preservados e `null` limpa o campo. Uma aquisição nova só é criada quando o registro ainda não tem nenhuma. `crm_lead_source_id: null` remove a origem do registro e da aquisição atual.

Nas respostas, `measurement_consent` contém a decisão efetiva. O campo `marketing_lead_source` no detalhe representa o snapshot ativo de aquisição mais recente, que pode ser diferente do snapshot utilizado como compatibilidade para resolver o consentimento.

## Atualizar dados e associações

Use `PUT /leads/{id}` ou `PUT /deals/{id}` com o UUID do registro. **`title` continua obrigatório**, mesmo quando a intenção é alterar outro campo. Campos opcionais omitidos são preservados. A exceção é `custom_fields`: quando enviado com itens, substitui todas as respostas do registro, então reenvie o conjunto completo.

```json theme={null}
{
  "title": "Interesse no plano Enterprise — demonstração agendada",
  "measurement_consent": "DENIED",
  "persons_id": [
    {
      "person_id": "123e4567-e89b-42d3-a456-426614174001"
    },
    {
      "person_id": "123e4567-e89b-42d3-a456-426614174002",
      "delete": true
    }
  ],
  "organization_id": null
}
```

`persons_id` adiciona participantes, e `delete: true` remove participantes existentes. Remover uma pessoa que não participa do registro é ignorado; em leads, um `person_id` que não existe retorna `404`. `organization_id: null` remove a organização atual. Em leads ganhos ou perdidos, essas duas remoções retornam `404`, e as demais alterações do corpo já terão sido aplicadas. Para cadastrar uma organização, envie `organization.name` e os demais dados; para associar uma existente, envie seu `organization_id`. Não envie a criação de organização e um ID de organização juntos.

No `PUT`, `person` sempre cadastra uma nova pessoa e a torna a principal; em oportunidades, `primary_person_id` pode indicar outra pessoa como principal. A deduplicação só ocorre na criação. Para associar alguém já cadastrado, use `persons_id`.

O PUT retorna um resumo da alteração. Em leads, inclui `id`, `code`, `title`, `quality_rating`, `quality_reason`, `status`, `lost_reason_description`, `measurement_consent` e `value`. Em oportunidades, inclui os mesmos campos de identificação, qualificação, status e consentimento, além de `won_reason_description`, sem `value`. Consulte o GET de detalhe para ler as associações após a atualização.

No PUT de oportunidade, `expected_close_date: null` limpa a previsão de fechamento. `tags` e `primary_person_id` também podem ser enviados; as tags informadas são acrescentadas às existentes. `value` é ignorado quando a oportunidade negocia por produtos ou por proposta, porque o valor passa a ser calculado pelos itens. Para indicar ganho, use `status: 2`:

```json theme={null}
{
  "title": "Contrato Enterprise",
  "status": 2,
  "won_date": "2026-09-10T15:00:00.000Z",
  "proposal_deadline_starts_on": "2026-09-14"
}
```

`status` não preenche datas automaticamente: envie `won_date` ou `lost_date` quando quiser registrá-las. A mudança de status pelo `PUT` gera o webhook `deal.updated`, e não `deal.won` ou `deal.lost`; consulte os [eventos de webhook](/documentacao-da-api/eventos-de-webhooks/index).

`proposal_deadline_starts_on` confirma a data-base do cronograma da proposta principal. Aceita uma data civil entre `1980-01-01` e `2100-12-31` somente na requisição que muda o status para ganho; em uma oportunidade que já está ganha, retorna `400`. Quando omitida, um cronograma existente recebe a data civil do ganho no fuso do cronograma. Os detalhes e exemplos do cronograma estão nas rotas de propostas.

## Campos personalizados e seguidores

Para enviar `custom_fields`, use uma lista de objetos com `id` da definição do campo e `value`, `option_id` ou `option_ids`, conforme seu tipo. Consulte `/integrations/external/custom-fields` para descobrir os campos configurados. Na criação, todos os campos personalizados obrigatórios da entidade precisam ser enviados; a falta de um deles retorna `400`. Campos do tipo arquivo não podem ser preenchidos por estas rotas. Campos temporais usam formatos locais canônicos, sem `Z` nem offset:

| Tipo | Formato | Exemplo de `value` |
| - | - | - |
| Data | `YYYY-MM-DD` | `2026-09-14` |
| Hora | `HH:mm` | `14:30` |
| Data e hora | `YYYY-MM-DDTHH:mm` | `2026-09-14T14:30` |

Na criação, `followers` recebe uma lista com `user_id`, `role_id` e `notes` opcional de até 1.000 caracteres. `note` adiciona uma nota inicial com `content` obrigatório e `is_pinned` opcional; o conteúdo aceita texto simples ou HTML, que é higienizado. Seguidores e nota são processados antes da resposta de criação, mas depois que o registro já foi gravado: se um deles falhar, a API retorna erro e o lead ou a oportunidade permanece criado. Nesse caso, consulte o registro antes de tentar de novo. Webhooks e notificações podem ser entregues de forma assíncrona.

Depois da criação, gerencie seguidores pelas rotas específicas:

| Método | Rota | Retorno |
| - | - | - |
| `POST` | `/integrations/external/leads/{id}/followers` | `201`, objeto com `followers` atualizado |
| `DELETE` | `/integrations/external/leads/{id}/followers/{user_id}` | `200`, `{"status":"success"}` |
| `POST` | `/integrations/external/deals/{id}/followers` | `201`, objeto com `followers` atualizado |
| `DELETE` | `/integrations/external/deals/{id}/followers/{user_id}` | `200`, `{"status":"success"}` |

O POST recebe `user_id`, `role_id` e `notes` opcional. O usuário e a função precisam estar ativos e pertencer à empresa. Adicionar um seguidor existente atualiza sua função e observações; adicionar um seguidor removido reativa o vínculo. Em leads, essas rotas só funcionam enquanto o lead está aberto: em um lead ganho ou perdido, retornam `404`.

## Listagem, filtros e retorno de detalhe

As listagens usam `skip` e `take`; envie `take` explicitamente para limitar a página. O retorno é `{ "total": ..., "records": [...] }` e `projection_context` nas consultas completas. `count_only=true` retorna somente `total` e `records: []`.

```bash theme={null}
curl --get 'https://api.wegly.com.br/integrations/external/deals' \
  --header 'Authorization: Bearer SUA_CHAVE' \
  --data-urlencode 'skip=0' \
  --data-urlencode 'take=20' \
  --data-urlencode 'all_statuses=true' \
  --data-urlencode 'created_from=2026-09-01T00:00:00.000Z' \
  --data-urlencode 'order_by=created_at' \
  --data-urlencode 'order_direction=desc'
```

Além dos filtros de etapa, funil, status, arquivamento, origem, tags e datas, as listagens aceitam participantes e organizações, `responsible_ids`, `created_by`, `excluded_ids`, `partner_ids`, `follower_ids`, `only_followed_by_me`, `icp_ids`, `without_icp`, pontuação e qualificação, `stagnation_status`, `abandoned` e filtros de resposta do cliente no WhatsApp. O valor `only_followed_by_me` usa o criador da chave como referência.

Filtros de listas aceitam valores separados por vírgula ou parâmetros repetidos. `custom_field_filters` recebe um array serializado em JSON e codificado na query, com objetos contendo `id` e `value`, `option_id` ou `option_ids`.

Oportunidades também aceitam `lead_created_from`, `lead_created_to`, `only_without_expected_close_date` e `crm_gain_reason_ids`. `order_by` difere entre os recursos: leads aceitam `name`, `created_at`, `last_activity_at`, `quality_rating` e `score`; oportunidades aceitam `title`, `created_at`, `last_activity_at`, `quality_rating`, `score`, `value`, `expected_close_date` e `temperature`.

Os filtros de marketing podem usar `attribution_mode`. Para selecionar o recorte correto, consulte a descrição dos parâmetros na referência da rota. A origem exibida em `lead_source` e `deal_source` é a origem efetiva: a da aquisição mais recente e, na falta dela, a gravada no registro. Os filtros `crm_lead_source_id` e `without_lead_source` usam essa mesma origem, assim como `lead_sources` quando `attribution_mode` não é enviado; `lead_sources` aceita IDs, nomes de origem e o valor `unknown`. O filtro `tags` aceita apenas IDs de tags. O histórico de aquisição fica separado no detalhe.

<Warning>
  As listagens externas rejeitam filtros de tarefas relacionadas: `pending_task_status`, `task_start_date_from`, `task_start_date_to`, `task_type_ids` e `related_task_completion_scope`. Quando informados, retornam `400`.
</Warning>

`GET /leads/{id}` e `GET /deals/{id}` aceitam UUID ou código sequencial. Cada consulta por ID registra uma visualização do criador da chave: `views_count` aumenta e o registro deixa de aparecer em `only_new=true`. O detalhe inclui participantes, organização, seguidores, campos personalizados, propostas, qualificação, ICPs, parceiros e os valores comerciais em `valuation`. `projection_context` informa o modo de exibição e o horizonte de recorrência usados nos valores projetados; `value` permanece o valor atual.

O detalhe de lead também retorna `deals`, com as oportunidades associadas e visíveis. O detalhe de oportunidade retorna `products` com os produtos diretamente associados à oportunidade; itens de propostas permanecem nas propostas. `proposals[].delivery_schedule` contém o cronograma calculado. Sem uma data-base confirmada, o cronograma utiliza a data atual como referência de leitura.

Os campos `has_channel_chat`, `channel_chats`, `has_whatsapp_chat` e `whatsapp_chats` dependem da permissão `crm/chats.read` da **própria chave**. Sem ela, as flags são `false` e as listas são vazias. Nas consultas externas, os campos com nome `whatsapp` são aliases de compatibilidade da projeção multicanal e podem incluir Instagram.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.