Pipeline (CRM)

Gerencie pipelines de vendas completos com estagios customizaveis, cards (deals), automacoes de workflow e lead scoring integrado.

Base URL

Todos os endpoints usam o prefixo /api/v1/accounts/{account_id}

Isolamento multi-tenant e seguranca

Toda a API de Pipeline e escopada por conta. Voce nunca consegue ler, alterar ou apagar dados de outra conta — nem por engano, nem de proposito. Entenda como o isolamento funciona antes de automatizar operacoes destrutivas.

O account_id vem da URL, nunca do corpo da requisicao

O {account_id} faz parte do caminho da URL e e validado contra o seu token: a API confirma que o usuario autenticado e membro daquela conta antes de qualquer operacao (caso contrario, 401). Nenhum endpoint le account_id do corpo (body) da requisicao. Por isso nao existe o cenario de "esquecer de setar o account_id" e atingir outra conta — o escopo e sempre derivado da rota autenticada.

IDs no caminho sao resolvidos dentro da sua conta

Todos os identificadores em {id}, display_id e conversation_display_id sao buscados dentro do escopo da conta da URL(Current.account.pipeline_cards.find(...)). Um ID que pertence a outra conta retorna 404 Not Found — nunca o registro alheio.

Atencao: display_id e conversation_display_id sao sequencias por conta(a conta A e a conta B podem ambas ter o card #42), nao identificadores globais. Use sempre o ID retornado pelos endpoints da sua propria conta; nao tente adivinhar/iterar IDs.

Delete nao cascateia entre contas — e e soft por padrao

  • DELETE /pipeline_cards/{id} e um soft delete (marca discarded_at), reversivel. O hard delete exige um passo separado e explicito (permanently_delete, restrito a administradores e so para cards ja descartados).
  • DELETE /pipelines/{id} faz soft delete apenas dos cards daquela conta — nunca dispara uma cascata atingindo cards de outras contas.
  • Operacoes em lote (bulk) e reorder filtram os IDs recebidos pela sua conta antes de agir: qualquer ID de outra conta e silenciosamente ignorado (no-op), nunca apagado nem movido. O reorder ainda exige pipeline_id obrigatorio para reforcar o isolamento entre pipelines.

Pipelines

GET/api/v1/accounts/{account_id}/pipelines

Lista todos os pipelines da conta.

bash
curl -s "https://chat.seudominio.com/api/v1/accounts/1/pipelines" \
  -H "api_access_token: YOUR_TOKEN" | jq .
200Array de pipelines (sem envelope). stages e um objeto/hash com a chave do estagio como key.
json
[
  {
    "id": 1,
    "account_id": 1,
    "name": "Vendas B2B",
    "description": "Pipeline principal de vendas",
    "active": true,
    "stages": {
      "1_prospeccao": { "id": "1_prospeccao", "name": "Prospeccao", "color": "#3b82f6", "position": 0 },
      "1_proposta":   { "id": "1_proposta", "name": "Proposta", "color": "#f59e0b", "position": 1 },
      "1_ganho":      { "id": "1_ganho", "name": "Ganho", "color": "#10b981", "position": 2, "is_won_stage": true },
      "1_perdido":    { "id": "1_perdido", "name": "Perdido", "color": "#ef4444", "position": 3, "is_lost_stage": true }
    },
    "settings": { "require_won_value": false, "require_loss_reason": false },
    "inbox_id": null,
    "default_for_appointments": false,
    "created_at": "2025-06-01T00:00:00Z",
    "updated_at": "2025-06-01T00:00:00Z"
  }
]
POST/api/v1/accounts/{account_id}/pipelines

Cria um novo pipeline com estagios.

stages e obrigatorio

O campo stages e obrigatorio e deve ser um objeto (hash), nao um array. Envie pelo menos um estagio ou a API retorna 422. Use sempre Content-Type: application/json.

Body

NomeTipoObrigatorioDescricao
pipeline.namestringSimNome do pipeline
pipeline.descriptionstringNaoDescricao
pipeline.stagesobjectSimObjeto com estagios. Chaves sao IDs temporarios (string). Apos criacao os IDs sao normalizados para {pipeline_id}_{slug}
pipeline.stages.{key}.namestringSimNome do estagio
pipeline.stages.{key}.colorstringNaoCor em hex (ex: "#3B82F6")
pipeline.stages.{key}.positionintegerNaoOrdem de exibicao (1 = primeiro)
curl -X POST "https://chat.seudominio.com/api/v1/accounts/1/pipelines" \
  -H "api_access_token: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "pipeline": {
      "name": "Vendas B2B",
      "stages": {
        "stage_1": { "name": "Prospeccao", "color": "#6366f1", "position": 1 },
        "stage_2": { "name": "Qualificacao", "color": "#3B82F6", "position": 2 },
        "stage_3": { "name": "Proposta", "color": "#f59e0b", "position": 3 },
        "stage_4": { "name": "Fechamento", "color": "#10b981", "position": 4 }
      }
    }
  }'

IDs dos estagios apos criacao

Apos criar o pipeline, os IDs dos estagios sao normalizados pelo servidor para o formato {pipeline_id}_{slug_do_nome} (ex: 1_prospeccao). Use GET /pipelines/{id}/stages para obter os IDs reais antes de criar cards.

PATCH/api/v1/accounts/{account_id}/pipelines/{id}

Atualiza nome, descricao, estagios ou settings de um pipeline.

ATENCAO: formato do campo stages

Sempre envie stages como objeto (hash) com IDs reais como chaves, nao como array. Array com cada item contendo id tambem e aceito (desde v4.13.0.34), mas array sem id em cada item e rejeitado com 422 e os cards nao sao alterados (defesa contra payloads mal-formatados que poderiam mover todos os cards para a primeira stage nao-terminal).

A rota PATCH /pipelines/{id}/stages/{stage_id} nao existe e retorna 404. Para editar uma stage individual (descricao, cor, nome, posicao), envie PATCH /pipelines/{id} com o hashstagescompleto — o backend faz diff inteligente.

Body

NomeTipoObrigatorioDescricao
pipeline.namestringNaoNome do pipeline
pipeline.descriptionstringNaoDescricao
pipeline.activebooleanNaoStatus de ativacao
pipeline.stagesobjectNaoHash com stages keyed por ID real (ex: "1_qualificado"). Array tambem aceito desde que cada item tenha campo id.
pipeline.settingsobjectNaoConfiguracoes do pipeline (JSONB). Chaves desconhecidas sao descartadas.
curl -X PATCH "https://chat.seudominio.com/api/v1/accounts/1/pipelines/36" \
  -H "api_access_token: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "pipeline": {
      "stages": {
        "36_qualificado": {
          "name": "Qualificado",
          "position": 1,
          "description": "Lead qualificado para proxima etapa",
          "color": "#10b981"
        },
        "36_entrada_de_lead": { "name": "Entrada de Lead", "position": 0 }
      }
    }
  }'

Comportamento ao remover stages

Quando uma stage existente e omitida do payload, ela e considerada removida e os cards que estavam nela sao automaticamente movidos para a primeira stage nao-terminal por ordem de position. Cada movimento e registrado em pipeline_stage_histories.

Limites: maximo de 50 stages por pipeline; settings JSON ate 64 KB.

DELETE/api/v1/accounts/{account_id}/pipelines/{id}

Remove um pipeline. Os cards associados sao soft-deleted (discard), nao apagados.

Escopo de conta e cascata

O id e resolvido dentro da conta autenticada(Current.account.pipelines.find) — nao e um ID global. Tentar deletar um pipeline de outra conta retorna 404.

Ao destruir o pipeline, os cards associados sao soft-deleted(discard!, marcando discarded_at) — nao sao hard-deleted — e pipeline_stage_histories, follow_up_rules e pipeline_webhooks sao removidos em cascata. O proprio registro do pipeline e removido permanentemente; planeje com cuidado antes de chamar.

Estagios do Pipeline

GET/api/v1/accounts/{account_id}/pipelines/{pipeline_id}/stages

Lista os estagios de um pipeline. O id de cada estagio e a string no formato {pipeline_id}_{slug} usada no campo pipeline_stage dos cards.

200Estagios ordenados por position
json
{
  "pipeline_id": 8143,
  "pipeline_name": "Clinica Medica - Jornada do Paciente",
  "stages": [
    {
      "id": "8143_entrada_de_lead",
      "name": "Entrada de Lead",
      "color": "#64748b",
      "icon": null,
      "position": 0,
      "description": "Entrada automatica de leads via inbox",
      "is_entry_stage": true,
      "is_won_stage": false,
      "is_lost_stage": false
    },
    {
      "id": "8143_ganho",
      "name": "Ganho",
      "color": "#10b981",
      "position": 6,
      "is_entry_stage": false,
      "is_won_stage": true,
      "is_lost_stage": false
    }
  ]
}

Renomear um estagio muda o id (pipeline_stage)

O id do estagio e derivado do nome ({pipeline_id}_{slug}). Ao renomear um estagio via PATCH /pipelines/{id}, o backend re-slugifica a chave e migra os cards daquele estagio na mesma transacao — ou seja, o valor de pipeline_stage muda. Integracoes que armazenam o id do estagio devem reconsultar GET /pipelines/{id}/stages apos mudancas de configuracao.

Cards (Deals)

Cards representam oportunidades de venda (deals) dentro de um pipeline. Cada card possui valor, contato associado, estagio atual e lead score.

GET/api/v1/accounts/{account_id}/pipeline_cards

Lista cards do kanban com filtros. Existem duas rotas: /pipeline_cards (legacy, paginacao limit/offset) e /pipeline/cards (canonica, paginacao page/per_page). Ambas aceitam o mesmo conjunto completo de filtros avancados (labels, priority, valor, agente, datas, SLA, stages) via o concern compartilhado PipelineCardFilterable.

Filtros avancados (ambas as rotas, via concern compartilhado)

A rota /api/v1/accounts/{id}/pipeline_cards (legacy, paginacao por limit/offset) aceita o conjunto completo de filtros: alem de pipeline_id, pipeline_stage, conversation_display_id e contact_id, ela tambem filtra por labels[], priority[], value_min/value_max, agent_id, date_start/date_end, status, sla_exceeded e stages[]. Os mesmos filtros sao aplicados pelo endpoint de exportacao (GET /pipeline/cards/export).

A rota /api/v1/accounts/{id}/pipeline/cards (canonica, paginacao por page/per_page) aceita os mesmos filtros avancados (mesmo concern), e adicionalmente owner_id e lead_score_category (hot/warm/cold).

Importante: o filtro contact_id foi implementado na v4.12.3.0. Antes dessa versao, ele era silenciosamente ignorado e retornava todos os cards da conta. Se voce tem automacoes que dependem desse filtro, confirme que esta rodando v4.12.3.0 ou superior.

Parametros (rota legacy /pipeline_cards — conjunto completo)

NomeTipoObrigatorioDescricao
pipeline_id(query)integerNaoFiltrar por pipeline (todos os cards desse funnel)
pipeline_stage(query)stringNaoFiltrar por um estagio especifico (ex: "1_lead")
conversation_display_id(query)integerNaoFiltrar por conversa associada (display_id, nao ID global)
contact_id(query)integerNaoFiltrar por contato (v4.12.3.0+)
labels[](query)string[]NaoTitulos de labels da conversa vinculada ao card. Match OR (qualquer um dos titulos).
priority[](query)string[]NaoPrioridade do card: none, low, medium, high, urgent. Match OR.
value_min(query)numberNaoValor minimo do card (>=). Valor do card = expected_revenue ou item_details.value. Cards sem valor algum sao EXCLUIDOS quando value_min/value_max esta presente.
value_max(query)numberNaoValor maximo do card (<=). Cards sem valor algum sao excluidos (filtrar por valor implica ter valor).
agent_id(query)integerNaoID do responsavel (owner) do card. Use -1 ou "unassigned" para cards sem responsavel.
date_start(query)stringNaoData inicial de criacao (created_at), formato YYYY-MM-DD, interpretada no fuso da conta.
date_end(query)stringNaoData final de criacao (created_at), formato YYYY-MM-DD, fuso da conta.
status(query)stringNaoEstado do deal: open, won, lost ou closed.
sla_exceeded(query)booleanNaotrue = apenas cards abertos com SLA vencido (sla_overdue).
stages[](query)string[]NaoLista de estagios (pipeline_stage). Match OR — cards em qualquer um dos estagios informados.
limit(query)integerNaoItens por pagina (default 50, max 500 — valores acima sao limitados a 500)
offset(query)integerNaoOffset para paginacao(default: 0)

Parametros extras da rota canonica /pipeline/cards (alem dos filtros avancados acima)

NomeTipoObrigatorioDescricao
pipeline_id(query)integerNaoFiltrar por pipeline
pipeline_stage(query)stringNaoFiltrar por estagio (ex: "69_lead")
owner_id(query)integerNaoFiltrar por responsavel (alem de agent_id da tabela acima)
contact_id(query)integerNaoFiltrar por contato (v4.12.3.0+)
lead_score_category(query)stringNaohot, warm, cold (exclusivo da canonica)
page(query)integerNaoPagina atual(default: 1)
per_page(query)integerNaoItens por pagina(default: 25)
bash
# Filtros avancados na rota legacy: prioridade alta, valor minimo, SLA vencido
curl -s "https://chat.seudominio.com/api/v1/accounts/1/pipeline_cards?pipeline_id=1&priority[]=high&priority[]=urgent&value_min=5000&sla_exceeded=true" \
  -H "api_access_token: YOUR_TOKEN" | jq .

# Filtrar por labels, agente e intervalo de datas
curl -s "https://chat.seudominio.com/api/v1/accounts/1/pipeline_cards?labels[]=vip&agent_id=5&date_start=2026-01-01&date_end=2026-06-30" \
  -H "api_access_token: YOUR_TOKEN" | jq .

# Cards sem responsavel
curl -s "https://chat.seudominio.com/api/v1/accounts/1/pipeline_cards?agent_id=unassigned&pipeline_id=1" \
  -H "api_access_token: YOUR_TOKEN" | jq .

# Canonica com status
curl -s "https://chat.seudominio.com/api/v1/accounts/1/pipeline/cards?status=open&pipeline_id=1" \
  -H "api_access_token: YOUR_TOKEN" | jq .
200Lista de cards (legacy /pipeline_cards)
json
{
  "data": [
    {
      "id": 1,
      "title": "Contrato Empresa XYZ",
      "pipeline_id": 1,
      "pipeline_stage": "1_qualificacao",
      "position": 1,
      "status": "open",
      "contact_id": 10,
      "owner_id": 5,
      "lead_score": 78,
      "conversation_display_id": 42,
      "item_details": { "value": 15000.00 },
      "active_sequence": { "id": 9, "name": "Onboarding", "status": "active", "current_step": 1, "total_steps": 3, "progress_percentage": 33 },
      "created_at": "2026-01-10T10:00:00Z"
    }
  ],
  "meta": {
    "limit": 50,
    "offset": 0,
    "has_more": false,
    "next_cursor": null,
    "stage_counts": { "1_lead": 12, "1_qualificacao": 18, "1_ganho": 12 }
  }
}

Importar Cards (CSV)

Importe cards (deals) em lote a partir de um arquivo CSV. O processamento e assincrono: a API valida e enfileira o import, e o job cria os cards em background. Ambos os endpoints exigem permissao de administrador.

GET/api/v1/accounts/{account_id}/pipeline/cards/template

Baixa um CSV modelo com os cabecalhos esperados e uma linha de exemplo.

Formato do CSV modelo

A resposta e um arquivo text/csv (download direto — Content-Disposition: attachment, filename pipeline_cards_import_template.csv). A primeira linha contem os cabecalhos e a segunda linha traz um exemplo preenchido.

Colunas (nessa ordem):

  • titleobrigatoria, titulo do card.
  • stage — estagio inicial do card. Aceita a chave completa (1_contato), o slug (contato) ou o nome legivel sem distincao de caixa/acento (Contato, Negociação). Nao reconhecido → primeira etapa do pipeline.
  • description — descricao livre.
  • expected_revenue — receita esperada (numerico).
  • contact_identifier — identificador externo do contato.
  • contact_email — email do contato.
  • contact_phone — telefone do contato.
bash
curl -s "https://chat.seudominio.com/api/v1/accounts/1/pipeline/cards/template" \
  -H "api_access_token: YOUR_TOKEN" \
  -o pipeline_cards_import_template.csv
POST/api/v1/accounts/{account_id}/pipeline/cards/import

Envia um CSV para importar cards em lote (multipart/form-data). Processamento assincrono.

multipart/form-data — campos obrigatorios

Envie como multipart/form-data. O arquivo CSV vai no campo import_file e o pipeline alvo no campo pipeline_id. O pipeline_id e resolvido dentro da conta autenticada — um pipeline de outra conta (ou ausente) retorna 422.

Validacao do arquivo (limites)

O upload e validado antes de enfileirar: tamanho maximo de 10MB; content-type aceito text/csv, text/plain, application/csv ou application/vnd.ms-excel; e a primeira linha precisa conter o cabecalho do template (coluna title). Arquivo fora dessas regras retorna 422.

Body (multipart/form-data)

NomeTipoObrigatorioDescricao
import_file(body)fileSimArquivo CSV no formato do template (cabecalhos na 1a linha). Maximo 10MB.
pipeline_id(body)integerSimID do pipeline alvo onde os cards serao criados (escopado a conta).
bash
curl -X POST "https://chat.seudominio.com/api/v1/accounts/1/pipeline/cards/import" \
  -H "api_access_token: YOUR_TOKEN" \
  -F "import_file=@pipeline_cards.csv" \
  -F "pipeline_id=1"
200Import enfileirado com sucesso. Os cards sao criados em background; use import_id para rastrear.
json
{
  "message": "Importacao iniciada. Os cards serao criados em segundo plano.",
  "import_id": 42
}
422Arquivo ausente/grande demais (>10MB)/tipo invalido, pipeline_id invalido/ausente, ou falha ao criar o import.
json
{ "error": "Pipeline obrigatorio para importar cards." }

Exportar Cards (CSV)

Exporta os cards da conta como um arquivo CSV, respeitando os mesmos filtros aceitos pela rota de listagem. O resultado e escopado a conta autenticada (a visibilidade por pipeline do usuario tambem se aplica).

GET/api/v1/accounts/{account_id}/pipeline/cards/export

Exporta os cards filtrados como CSV (download direto). Aceita os mesmos query params da listagem.

Filtros aceitos

Os mesmos filtros da rota legacy de listagem se aplicam (query params): pipeline_id, pipeline_stage, conversation_display_id, contact_id, labels[], priority[], value_min/value_max, agent_id, date_start/date_end, status, sla_exceeded e stages[]. Sem filtros, exporta todos os cards visiveis da conta.

A resposta e um arquivo text/csv (Content-Disposition: attachment, filename pipeline_cards_export_<timestamp>.csv, com o timestamp no fuso da conta).

Limite de linhas e protecao anti-formula

O export sincrono e limitado a 20.000 cards. Acima disso a API retorna 422 — aplique filtros para reduzir o resultado.

Celulas de texto que comecam com =, @, + ou - (e nao sao numeros/telefones) sao prefixadas com apostrofo (') para neutralizar injecao de formula em planilhas (CSV injection).

Colunas do CSV exportado

id, title, pipeline_id, stage, status, priority, value, currency, owner_name, contact_name, contact_email, contact_phone, conversation_display_id, labels, lead_score, lead_score_category, created_at, won_at, lost_at, deadline. Datas em ISO 8601 no fuso da conta; labels sao separadas por |.

bash
# Exportar todos os cards de um pipeline com status aberto
curl -s "https://chat.seudominio.com/api/v1/accounts/1/pipeline/cards/export?pipeline_id=1&status=open" \
  -H "api_access_token: YOUR_TOKEN" \
  -o pipeline_cards_export.csv
POST/api/v1/accounts/{account_id}/pipeline_cards

Cria um novo card (deal) no pipeline.

Como obter o pipeline_stage

O campo pipeline_stage e uma string no formato {pipeline_id}_{slug} (ex: "1_prospeccao"). Use GET /pipelines/{id}/stages para listar os IDs reais dos estagios do seu pipeline antes de criar cards.

Body envolto em pipeline_card

Envie sempre os campos dentro do wrapper pipeline_card. A rota legacy /pipeline_cards tolera campos no nivel raiz (sao re-embrulhados automaticamente via wrap_parameters e o card e criado normalmente), mas a rota canonica POST /pipeline/cards e estrita: sem o wrapper ela retorna 422 (param is missing: pipeline_card). Use sempre o wrapper para um comportamento consistente entre as duas rotas.

Body (pipeline_card)

NomeTipoObrigatorioDescricao
titlestringNaoTitulo do deal no nivel raiz. Opcional — se omitido, o card usa item_details.title (ou fica null).
pipeline_idintegerSimID do pipeline
pipeline_stagestringSimID do estagio no formato "{pipeline_id}_{slug}" (ex: "1_prospeccao"). Obtenha via GET /pipelines/{id}/stages
contact_idintegerNaoID do contato associado (resolvido dentro da conta autenticada)
conversation_display_idintegerNaoDisplay ID da conversa associada (per-account, nao ID global)
owner_idintegerNaoID do responsavel
expected_revenuenumberNaoReceita esperada do deal
deadlinestringNaoData prevista de fechamento (ISO 8601)
item_detailsobjectNaoJSONB freeform. title, value e currency do card vivem aqui.
custom_attributesobjectNaoAtributos personalizados
# Primeiro obtenha os IDs dos estagios:
# curl -s ".../api/v1/accounts/1/pipelines/1/stages" -H "api_access_token: TOKEN"

curl -X POST "https://chat.seudominio.com/api/v1/accounts/1/pipeline_cards" \
  -H "api_access_token: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "pipeline_card": {
      "title": "Contrato Empresa XYZ",
      "pipeline_id": 1,
      "pipeline_stage": "1_prospeccao",
      "contact_id": 10,
      "owner_id": 5,
      "item_details": {
        "title": "Contrato Empresa XYZ",
        "value": 15000.00,
        "currency": "BRL"
      },
      "deadline": "2026-03-15T00:00:00Z"
    }
  }'
GET/api/v1/accounts/{account_id}/pipeline_cards/{id}

Retorna detalhes completos de um card incluindo timeline e score.

PATCH/api/v1/accounts/{account_id}/pipeline_cards/{id}

Atualiza dados de um card. Body envolto em pipeline_card.

Body (pipeline_card)

NomeTipoObrigatorioDescricao
titlestringNaoTitulo do card
pipeline_stagestringNaoEstagio (formato "{pipeline_id}_{slug}"). Para mover entre estagios prefira POST /move_to_stage.
owner_idintegerNaoID do responsavel
contact_idintegerNaoID do contato
expected_revenuenumberNaoReceita esperada (coluna do card)
deadlinestringNaoData prevista de fechamento (ISO 8601)
forecast_close_datestringNaoData de previsao de fechamento (ISO 8601)
item_detailsobjectNaoJSONB freeform. value, currency e deadline_at vivem aqui. Faz deep-merge com o valor atual — envie apenas as chaves a alterar.
custom_attributesobjectNaoAtributos personalizados (JSONB)

Campos de valor: expected_revenue vs item_details.value vs won_value

Existem tres representacoes de valor, independentes:

  • expected_revenuecoluna numerica canonica do card (receita esperada). Use este para o valor previsto do deal.
  • item_details.value — campo legado (string, JSONB), alimentado pelo formulario do frontend. A rota legacy aceita value e deadline_at no nivel raiz por compatibilidade e os roteia para item_details automaticamente (deadline_at tambem grava a coluna deadline). Nao confie nele como fonte canonica de valor.
  • won_value — preenchido apenas ao fechar o deal via POST .../deal_status/mark_won (valor fechado).
bash
curl -X PATCH "https://chat.seudominio.com/api/v1/accounts/1/pipeline_cards/5" \
  -H "api_access_token: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "pipeline_card": {
      "title": "Contrato Empresa XYZ - revisado",
      "owner_id": 5,
      "item_details": { "value": 18000 }
    }
  }'
DELETE/api/v1/accounts/{account_id}/pipeline_cards/{id}

Remove um card (soft delete).

Soft delete escopado a conta

O id e resolvido dentro da conta autenticada(Current.account.pipeline_cards.find). Nao e um ID global — tentar deletar um card de outra conta retorna 404. A operacao e um soft delete (discarded_at); o card pode ser visto em GET /pipeline/cards/discarded e restaurado via POST /pipeline/cards/{id}/restore. A remocao definitiva exige um passo separado e explicito (DELETE /pipeline/cards/{id}/permanently_delete, so para cards ja descartados).

Lixeira por pipeline: GET /pipeline/cards/discarded e admin-only e aceita o parametro opcional pipeline_id(filtra a lixeira daquele pipeline; pipeline_id invalido/de outra conta retorna 404). Sem pipeline_id, lista a lixeira da conta inteira. Cada card retorna discarded_at, discarded_by, discard_reason e days_until_permanent_deletion (contagem regressiva ate a exclusao definitiva, respeitando a retencao da conta — default 30 dias).

Mover Card entre Estagios

POST/api/v1/accounts/{account_id}/pipeline_cards/{id}/move_to_stage

Move um card para outro estagio do pipeline.

Body

NomeTipoObrigatorioDescricao
pipeline_stagestringSimIdentificador do estagio destino no formato "{pipeline_id}_{stage_slug}" (ex: "2_qualificao"). Use GET /pipelines/{id}/stages para obter os identificadores disponiveis.
bash
curl -X POST "https://chat.seudominio.com/api/v1/accounts/1/pipeline_cards/5/move_to_stage" \
  -H "api_access_token: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "pipeline_stage": "1_qualificacao" }'
POST/api/v1/accounts/{account_id}/pipeline_cards/reorder

Reordena cards dentro de um estagio.

pipeline_id e obrigatorio (isolamento)

O campo pipeline_id e obrigatorio — sem ele a API retorna 400. Ele garante que o reorder so afeta cards daquele pipeline especifico da sua conta; cards descartados e cards de outros pipelines sao ignorados. Cada entrada de positions tambem pode carregar pipeline_id proprio.

Body

NomeTipoObrigatorioDescricao
pipeline_idintegerSimID do pipeline cujos cards serao reordenados (escopo obrigatorio)
positionsarraySimArray de objetos { id, position }. Apenas cards do pipeline_id informado e da conta autenticada sao afetados.
bash
curl -X POST "https://chat.seudominio.com/api/v1/accounts/1/pipeline_cards/reorder" \
  -H "api_access_token: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "pipeline_id": 1,
    "positions": [
      { "id": 5, "position": 0 },
      { "id": 9, "position": 1 }
    ]
  }'

Status do Deal

POST/api/v1/accounts/{account_id}/pipeline/cards/{id}/deal_status/mark_won

Marca o deal como ganho. Requer que o pipeline tenha etapas Ganho/Perdido habilitadas.

Body (opcional)

NomeTipoObrigatorioDescricao
won_valuenumberNaoValor final fechado (numerico). Valor invalido retorna 422.
won_notestringNaoNota sobre o ganho
winning_offer_indexintegerNaoIndice da oferta vencedora (quando o card tem ofertas em item_details)
bash
curl -X POST "https://chat.seudominio.com/api/v1/accounts/1/pipeline/cards/5/deal_status/mark_won" \
  -H "api_access_token: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "won_value": 15000, "won_note": "Fechado no plano anual" }'

Resposta uniforme

mark_won, mark_lost e reopen retornam o mesmo shape: { id, status, pipeline_stage, won_at, won_value, won_note, lost_at, lost_reason, item_details }. Card ja ganho retorna 409.

POST/api/v1/accounts/{account_id}/pipeline/cards/{id}/deal_status/mark_lost

Marca o deal como perdido.

Body

NomeTipoObrigatorioDescricao
lost_reasonstringNaoMotivo da perda
POST/api/v1/accounts/{account_id}/pipeline/cards/{id}/deal_status/reopen

Reabre um deal marcado como ganho ou perdido.

Timeline do Card

GET/api/v1/accounts/{account_id}/pipeline/cards/{id}/timeline

Retorna a timeline de atividades do card.

200Eventos agrupados por data (chave raiz timeline)
json
{
  "timeline": [
    {
      "date": "2026-01-15",
      "activities": [
        {
          "id": 1780508401,
          "type": "history_event",
          "event_type": "stage_changed",
          "details": {
            "user": { "id": 5, "name": "Maria Santos", "avatar_url": "" },
            "old_stage": "1_prospeccao",
            "new_stage": "1_qualificacao"
          },
          "user": { "id": 5, "name": "Maria Santos", "avatar_url": "" },
          "created_at": "2026-01-15T14:30:00Z",
          "timestamp": "2026-01-15T14:30:00Z"
        }
      ]
    }
  ]
}

Anexos do Card

GET/api/v1/accounts/{account_id}/pipeline/cards/{card_id}/attachments

Lista anexos de um card.

POST/api/v1/accounts/{account_id}/pipeline/cards/{card_id}/attachments

Adiciona um anexo ao card.

bash
curl -X POST "https://chat.seudominio.com/api/v1/accounts/1/pipeline/cards/5/attachments" \
  -H "api_access_token: YOUR_TOKEN" \
  -F "file=@/path/to/proposta.pdf"
DELETE/api/v1/accounts/{account_id}/pipeline/cards/{card_id}/attachments/{id}

Remove um anexo.

Sequencias de Atividade no Card

Inscreve um card numa sequencia de atividades (cadencia automatizada de etapas, definida previamente em pipeline/activity_sequences). Sequencias estao incluidas em toda licenca NooviChat valida; o acesso depende das permissoes do usuario e da configuracao operacional da conta. Um card so pode ter uma sequencia ativa/pausada da mesma definicao por vez (422 em duplicidade).

GET/api/v1/accounts/{account_id}/pipeline/cards/{card_id}/sequences

Lista as sequencias inscritas no card.

200Sequencias do card (chave raiz data)
json
{
  "data": [
    {
      "id": 14,
      "status": "active",
      "current_step": 1,
      "total_steps": 4,
      "progress_percentage": 25,
      "definition": { "id": 3, "name": "Cadencia de prospeccao" },
      "next_step_at": "2026-06-15T12:00:00-03:00",
      "steps_log": [],
      "created_at": "2026-06-13T09:00:00-03:00",
      "updated_at": "2026-06-13T09:00:00-03:00"
    }
  ]
}
POST/api/v1/accounts/{account_id}/pipeline/cards/{card_id}/sequences

Inicia uma sequencia no card.

Body

NomeTipoObrigatorioDescricao
definition_idintegerSimID de uma activity_sequence ATIVA da conta

Respostas

201 com a sequencia criada;404 se a definicao nao existir/estiver inativa; 422 se ja houver uma sequencia ativa/pausada da mesma definicao no card.

POST/api/v1/accounts/{account_id}/pipeline/cards/{card_id}/sequences/external_start

Ponto de entrada para integracoes externas (ex: n8n). Inicia uma sequencia e aceita um contexto livre.

Body

NomeTipoObrigatorioDescricao
definition_idintegerSimID de uma activity_sequence ativa
contextobjectNaoObjeto livre com dados da origem externa. DEVE ser um objeto — um valor nao-objeto retorna 400.
PATCH/api/v1/accounts/{account_id}/pipeline/cards/{card_id}/sequences/{id}/pause

Pausa a execucao ativa da sequencia. 422 se nao houver execucao ativa.

PATCH/api/v1/accounts/{account_id}/pipeline/cards/{card_id}/sequences/{id}/resume

Retoma uma sequencia pausada. 422 se nao houver execucao pausada.

PATCH/api/v1/accounts/{account_id}/pipeline/cards/{card_id}/sequences/{id}/complete_step

Avanca manualmente para a proxima etapa da sequencia. 422 se nao houver execucao ativa ou se nao restarem etapas.

DELETE/api/v1/accounts/{account_id}/pipeline/cards/{card_id}/sequences/{id}

Cancela a sequencia no card (marca como cancelled). Retorna 200.

Operacoes em Lote

Operacao em massa — escopo de conta

O bulk_assign opera apenas sobre cards da conta autenticada(Current.account.pipeline_cards.where(id: item_ids)). IDs de cards de outras contas sao silenciosamente ignorados — nao ha vazamento cross-tenant. O lote e limitado a 200 cards por requisicao; passar mais retorna 400. Esta operacao apenas reatribui responsavel — nao remove nem move cards.

POST/api/v1/accounts/{account_id}/pipeline/cards/bulk_assign

Atribui responsavel para varios cards de uma vez (max 200).

Body

NomeTipoObrigatorioDescricao
item_idsarraySimIDs dos cards (max 200, escopados a conta autenticada)
owner_idintegerNaoID do novo responsavel. Omita junto com distribution para usar round_robin/workload_balanced.
distributionstringNaoround_robin ou workload_balanced — distribui automaticamente entre agentes online. Se omitido, usa owner_id.
bash
curl -X POST "https://chat.seudominio.com/api/v1/accounts/1/pipeline/cards/bulk_assign" \
  -H "api_access_token: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "item_ids": [5, 9, 12], "owner_id": 3 }'
PATCH/api/v1/accounts/{account_id}/pipeline/cards/{id}/assign

Atribui um responsavel a um card especifico.

Body

NomeTipoObrigatorioDescricao
owner_idintegerNaoID do responsavel. Omita para desatribuir o card.
notifybooleanNaoEnviar notificacao ao novo responsavel

Automacoes do Pipeline

Crie workflows automatizados que executam acoes quando cards mudam de estagio, atingem determinado score ou atendem condicoes especificas.

GET/api/v1/accounts/{account_id}/pipeline/automations

Lista todas as automacoes do pipeline. Retorna um array de automacoes (cada uma com objeto stats agregado).

200Lista de automacoes
json
[
  {
    "id": 1,
    "name": "Notificar ao entrar em Negociacao",
    "description": "Avisa o responsavel quando um card chega na negociacao",
    "active": true,
    "trigger_type": "event",
    "pipeline_id": 1,
    "trigger": { "event": "stage_change", "to_stage": "1_negociacao" },
    "conditions": [],
    "actions": [{ "type": "send_notification", "to": "owner" }],
    "flow": { "nodes": [], "connections": [], "viewport": { "x": 0, "y": 0, "zoom": 1 } },
    "stats": {
      "total_executions": 23,
      "success_count": 22,
      "failure_count": 1,
      "success_rate": 96
    }
  }
]
POST/api/v1/accounts/{account_id}/pipeline/automations

Cria uma nova automacao. Body envolto em pipeline_automation.

Body envolto em pipeline_automation

Os campos devem estar dentro do wrapper pipeline_automation. trigger_type aceita: event, webhook, scheduled ou manual.

Body (pipeline_automation)

NomeTipoObrigatorioDescricao
namestringSimNome da automacao
descriptionstringNaoDescricao
activebooleanNaoSe a automacao esta ativa
trigger_typestringNaoevent | webhook | scheduled | manual
pipeline_idintegerNaoID do pipeline alvo
triggerobjectNaoConfiguracao do gatilho (ex: { event, to_stage })
conditionsarrayNaoArray de condicoes para acionar
actionsarrayNaoArray de acoes a executar
schedule_configobjectNaoConfiguracao de agendamento (quando trigger_type = scheduled)
flowobjectNaoEditor de fluxo visual: { nodes, connections, viewport }
bash
curl -X POST "https://chat.seudominio.com/api/v1/accounts/1/pipeline/automations" \
  -H "api_access_token: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "pipeline_automation": {
      "name": "Notificar em Negociacao",
      "active": true,
      "trigger_type": "event",
      "pipeline_id": 1,
      "trigger": { "event": "stage_change", "to_stage": "1_negociacao" },
      "conditions": [],
      "actions": [{ "type": "send_notification", "to": "owner" }],
      "flow": { "nodes": [], "connections": [], "viewport": { "x": 0, "y": 0, "zoom": 1 } }
    }
  }'
PATCH/api/v1/accounts/{account_id}/pipeline/automations/{id}

Atualiza uma automacao.

DELETE/api/v1/accounts/{account_id}/pipeline/automations/{id}

Remove uma automacao.

POST/api/v1/accounts/{account_id}/pipeline/automations/{id}/duplicate

Clona uma automacao existente.

Executar e Testar

POST/api/v1/accounts/{account_id}/pipeline/automations/{id}/execute

Executa manualmente uma automacao.

POST/api/v1/accounts/{account_id}/pipeline/automations/{id}/dry_run

Executa simulacao sem efeito real (teste).

Dry Run

Permite testar a automacao sem executar as acoes reais. Retorna o resultado esperado.

POST/api/v1/accounts/{account_id}/pipeline/automations/{id}/validate

Valida a configuracao da automacao.

GET/api/v1/accounts/{account_id}/pipeline/automations/{id}/executions

Historico de execucoes da automacao.

Estatisticas de Automacao

GET/api/v1/accounts/{account_id}/pipeline/automations/{id}/stats

Metricas de uma automacao especifica.

GET/api/v1/accounts/{account_id}/pipeline/automations/dashboard

Dashboard de todas as automacoes.

GET/api/v1/accounts/{account_id}/pipeline/automations/{id}/audit_logs

Logs de auditoria da automacao.

Webhooks do Pipeline

Receba eventos do Pipeline em tempo real numa URL externa. Gerenciar webhooks requer permissao de administrador.

A URL precisa ser publica

A URL do webhook deve resolver para um IP publico. Enderecos privados/internos (127.0.0.0/8, 10/8, 172.16/12, 192.168/16, 169.254/16, IPv6 ULA/link-local) sao bloqueados por protecao anti-SSRF e a criacao retorna 422 — a verificacao tambem roda no momento do envio.

POST/api/v1/accounts/{account_id}/pipeline/webhooks

Cria um webhook. Body envolto em pipeline_webhook.

Body (pipeline_webhook)

NomeTipoObrigatorioDescricao
namestringSimNome do webhook
urlstringSimURL https publica que recebera os POSTs
eventsstring[]SimSubconjunto dos eventos disponiveis (ver abaixo). Evento invalido retorna 422.
bash
curl -X POST "https://chat.seudominio.com/api/v1/accounts/1/pipeline/webhooks" \
  -H "api_access_token: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "pipeline_webhook": {
      "name": "Integracao CRM",
      "url": "https://example.com/hooks/pipeline",
      "events": ["pipeline_card_won", "pipeline_card_lost"]
    }
  }'
201Webhook criado (o secret e retornado apenas para administradores)
json
{ "id": 71, "name": "Integracao CRM", "url": "https://example.com/hooks/pipeline", "events": ["pipeline_card_won", "pipeline_card_lost"], "active": true, "secret": "<64 hex>" }
GET/api/v1/accounts/{account_id}/pipeline/webhooks

Lista os webhooks (admin).

GET/api/v1/accounts/{account_id}/pipeline/webhooks/{id}

Detalhes de um webhook.

PATCH/api/v1/accounts/{account_id}/pipeline/webhooks/{id}

Atualiza name, url, events ou active.

DELETE/api/v1/accounts/{account_id}/pipeline/webhooks/{id}

Remove o webhook.

POST/api/v1/accounts/{account_id}/pipeline/webhooks/{id}/test

Dispara um POST de teste sincrono para a URL configurada.

PATCH/api/v1/accounts/{account_id}/pipeline/webhooks/{id}/regenerate_secret

Gera um novo secret HMAC (invalida o anterior).

Eventos disponiveis

Sete eventos:

  • pipeline_card_created — card criado
  • pipeline_card_updated — card atualizado
  • pipeline_card_deleted — card removido (soft delete)
  • pipeline_card_stage_changed — mudou de estagio (inclui from_stage/to_stage)
  • pipeline_card_won — marcado como ganho (inclui won_at, pre_won_stage)
  • pipeline_card_lost — marcado como perdido (inclui lost_reason, pre_lost_stage)
  • pipeline_card_owner_changed — responsavel alterado

Formato do payload

json
{
  "event": "pipeline_card_won",
  "timestamp": "2026-06-03T23:21:38Z",
  "data": {
    "card": { "id": 12473, "pipeline_id": 8143, "pipeline_stage": "8143_ganho", "won_at": "...", "contact_id": 21, "item_details": { ... } }
  }
}

Verificacao da assinatura (HMAC)

Cada POST inclui o header X-Pipeline-Webhook-Signature: sha256=<hex>, onde <hex> e o HMAC-SHA256 do corpo JSON cru usando o secret do webhook (64 hex). Recalcule e compare para garantir a autenticidade:

javascript
import crypto from "crypto";
const expected = "sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
const ok = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(req.headers["x-pipeline-webhook-signature"]));