Documentação da API do Atlas
Referência completa da API REST do Atlas, o CRM da Skill-Hub.
Descreve exatamente o que a API faz hoje em produção.
URL base
https://atlas.skill-hub.app/api/v1
API REST do Atlas, o CRM da Skill-Hub.
Esta especificação descreve exatamente o que a API faz hoje em produção. Onde existe uma inconsistência entre recursos, ela está documentada em vez de escondida.
Autenticação
Gere um token em Configurações → Tokens de API dentro do
Atlas. O valor é exibido uma única vez, no momento da criação. São 40
caracteres.
curl 'https://atlas.skill-hub.app/api/v1/contacts' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
O cabeçalho Accept não é opcional
Sem Accept: application/json, um request sem token ou com
token inválido recebe um 302 para a tela de login em HTML, em
vez de um 401 em JSON. É a causa mais comum de integração que
parece "não autenticar".
O acesso também exige que a licença do ambiente tenha a API habilitada e que
o addon de acesso à API esteja ativo na conta. Sem isso, todo request responde
403.
Escopos do token
Cada token carrega um ou mais escopos, escolhidos na criação. Escopo
não se edita: para mudar, revogue o token e crie outro. Cada endpoint
abaixo mostra o escopo que exige.
| Escopo | Dá direito a |
| escopo read | Leitura. Todos os GET. |
| escopo write | Criar, alterar e apagar dados: contatos, conversas (status e atribuição), faturas, propostas, agendamentos, produtos e webhooks. |
| escopo send | Disparos que saem para o cliente ou para terceiros e consomem crédito: POST /messages/send, POST /conversations/{id}/messages, POST /wa-connector/send-template e POST /webhooks/{id}/test. |
Por que send é separado
Um token só de leitura e escrita nunca dispara mensagem por acidente.
write não implica send. Marque
send apenas em integrações que precisam enviar.
Tokens criados antes dos escopos têm acesso total e continuam valendo para
tudo. Sem o escopo exigido, a resposta é 403 com código de máquina:
{
"error": "Este token não tem o escopo 'send'. Crie um token com esse escopo em Configurações → Tokens de API.",
"code": "insufficient_scope",
"required_scope": "send"
}
Convenções
Escopo de dados
O tenant_id nunca é aceito no corpo de um request. Ele vem do
token. Um recurso que pertença a outra conta responde 404, e não
403, por decisão de segurança.
Limite de requisições
60 requisições por minuto, por token, em janela fixa de 60
segundos. Toda resposta traz X-RateLimit-Limit e
X-RateLimit-Remaining. Ao estourar, a resposta é 429
com Retry-After: 60.
Paginação
A maior parte das listagens aceita page e per_page
(padrão 50, teto 100) e devolve um envelope meta.
{
"data": [],
"meta": { "current_page": 1, "last_page": 10, "per_page": 50, "total": 500 }
}
Três exceções: /webhooks e /wa-connector/* não
paginam, e /conversations/{id}/messages usa cursor
(before_id, after_id, limit) com
has_more no lugar de meta.
Datas e valores
Datas em ISO 8601 com offset, por exemplo
2026-09-03T19:57:10-03:00. As exceções são
connected_at e last_synced_at do WhatsApp Connector,
que vêm em UTC com sufixo Z. Datas puras usam
YYYY-MM-DD. Valores monetários são devolvidos como número, não
como texto.
Erros
A API usa dois formatos de erro, por razões históricas. Ambos estão
documentados aqui porque ambos acontecem.
Formato geral
{ "error": "Contact not found." }
Validação, formato do framework
{
"message": "The name field is required.",
"errors": { "name": ["The name field is required."] }
}
Autenticação
{ "message": "Unauthenticated." }
| Código | Significado |
| 401 | Token ausente, inválido ou expirado. |
| 403 | Token sem o escopo exigido: corpo { "error": "…", "code": "insufficient_scope", "required_scope": "send" }. Ou conta sem vínculo, licença sem API habilitada, ou addon de acesso à API inativo. |
| 404 | Recurso inexistente ou de outra conta. |
| 422 | Falha de validação, ou regra de negócio que impede a operação. |
| 429 | Limite de requisições estourado. |
| 500 | Erro interno. |
Contatos
Pessoas e empresas, seus negócios e conversas.
GET/contactsescopo read
Listar contatos
Parâmetros
| Nome | Tipo | Observação |
|---|
pagequerypadrão 1 | integer | |
per_pagequerypadrão 50 | integer | |
typequery | lead | customer | prospect | supplier | Igualdade exata. |
person_typequery | individual | company | |
searchquery | string | Busca parcial, sem diferenciar maiúsculas, em nome, nome fantasia, e-mail, telefone, celular e documento. |
group_idquery | integer | |
assigned_toquery | integer | |
sourcequery | string | Igualdade exata e sensível a maiúsculas. A base contém grafias diferentes para a mesma origem, então prefira listar e filtrar do seu lado quando precisar de precisão. |
is_activequery | boolean | |
tagsquery | array<string> | Array ou lista separada por vírgula. As tags são combinadas com E, não com OU. |
sort_byquerypadrão created_at | name | email | type | created_at | updated_at | last_contact_at | |
sort_dirquerypadrão desc | asc | desc | Qualquer valor diferente de asc é tratado como desc. |
Respostas
| 200 | Lista paginada. |
| 401 | Token ausente, inválido ou expirado. |
| 403 | Quatro causas, distinguíveis pelo corpo:
- token sem o escopo exigido (code: insufficient_scope, com required_scope), ver a seção *Escopos do token*; - usuário sem conta vinculada; - licença sem API habilitada; - addon de acesso à API inativo. |
| 429 | Limite de 60 requisições por minuto estourado. |
Exemplo
curl -X GET 'https://atlas.skill-hub.app/api/v1/contacts' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
{
"data": [
{
"id": 1001,
"name": "Maria Exemplo",
"trading_name": null,
"display_name": "Maria Exemplo",
"person_type": "individual",
"type": "lead",
"email": "[email protected]",
"phone": null,
"mobile": "(11) 91234-5678",
"document": null,
"source": null,
"tags": [],
"is_active": true,
"group": null,
"assigned_to": null,
"deals_count": 0,
"contracts_count": 0,
"created_at": "2026-09-03T19:57:10-03:00",
"updated_at": "2026-09-03T19:57:10-03:00"
}
],
"meta": {
"current_page": 1,
"last_page": 12,
"per_page": 50,
"total": 580
}
}
POST/contactsescopo write
Criar contato
Aplica os padrões type = lead e person_type = individual quando os campos não são enviados, e grava o usuário do token em created_by.
Campos de rastreamento (utm_*, captured_at) não são aceitos.
Corpo
| Campo | Tipo | Observação |
|---|
nameobrigatóriomáx 255 | string | |
trading_namemáx 255 | string? | |
emailmáx 255 | string (email)? | |
phonemáx 50 | string? | |
mobilemáx 50 | string? | |
websitemáx 255 | string? | |
companymáx 255 | string? | |
positionmáx 255 | string? | |
documentmáx 50 | string? | |
state_registrationmáx 50 | string? | |
municipal_registrationmáx 50 | string? | |
person_typepadrão individual | individual | company | |
typepadrão lead | lead | customer | prospect | supplier | |
sourcemáx 100 | string? | |
contact_group_id | integer? | |
assigned_to | integer? | |
parent_id | integer? | |
addressmáx 255 | string? | |
address_numbermáx 20 | string? | |
address_complementmáx 100 | string? | |
neighborhoodmáx 100 | string? | |
citymáx 100 | string? | |
statemáx 50 | string? | |
zip_codemáx 20 | string? | |
countrymáx 100 | string? | |
birth_date | string (date)? | |
tags | array<string> | |
notesmáx 5000 | string? | |
custom_fields | object | {chave: valor} com as chaves do módulo de Campos Personalizados (GET /custom-fields). cf_chave também vale (dentro de custom_fields ou solto na raiz do corpo). Formato aceito por tipo: - text, textarea: texto (respeita tamanho mínimo e máximo do campo) - select, radio: o valor ou o rótulo de uma opção, sem diferenciar maiúsculas - multiselect: lista de valores ou rótulos das opções - checkbox: true/false ou lista de valores das opções - number, rating: número inteiro - decimal, currency: número (1234.56) ou texto "1.234,56" - date: AAAA-MM-DD - datetime: ISO 8601 (2026-09-30T14:00:00-03:00) - url: começando com http:// ou https:// - email, phone, color (#RRGGBB) - file, image: não gravados pela API (enviar pela tela)
Campos obrigatórios só são exigidos na criação (POST). No PATCH, só as chaves enviadas mudam e null apaga o valor do campo. Chave inexistente: 422 com unknown_keys (contas em modo compatível recebem warnings e a chave vai para legacy_custom_fields). |
notification_settings | object? | |
Respostas
| 201 | Criado. Devolve a representação detalhada. |
| 401 | Token ausente, inválido ou expirado. |
| 403 | Quatro causas, distinguíveis pelo corpo:
- token sem o escopo exigido (code: insufficient_scope, com required_scope), ver a seção *Escopos do token*; - usuário sem conta vinculada; - licença sem API habilitada; - addon de acesso à API inativo. |
| 422 | Validação, incluindo campos personalizados. Quando algum campo é inválido ou a chave não existe, nada do request é gravado. |
| 429 | Limite de 60 requisições por minuto estourado. |
Exemplo
curl -X POST 'https://atlas.skill-hub.app/api/v1/contacts' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"name": "Maria Exemplo", "email": "[email protected]", "mobile": "11912345678", "type": "lead", "person_type": "individual", "tags": ["campanha-setembro"]}'
GET/contacts/{contact}escopo read
Obter contato
Devolve a representação detalhada, incluindo employees quando o contato for uma empresa com pessoas vinculadas.
Parâmetros
| Nome | Tipo | Observação |
|---|
contactpathobrigatório | integer | |
Respostas
| 200 | OK |
| 401 | Token ausente, inválido ou expirado. |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
Exemplo
curl -X GET 'https://atlas.skill-hub.app/api/v1/contacts/123' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
PUT/contacts/{contact}escopo write
Atualizar contato
Grava o usuário do token em updated_by. Aceita dois campos que a criação não aceita, is_active e bot_protected. PATCH faz o mesmo. Campos personalizados são parciais: só as chaves enviadas mudam e null apaga o valor do campo.
Parâmetros
| Nome | Tipo | Observação |
|---|
contactpathobrigatório | integer | |
Corpo
| Campo | Tipo | Observação |
|---|
nameobrigatóriomáx 255 | string | |
trading_namemáx 255 | string? | |
emailmáx 255 | string (email)? | |
phonemáx 50 | string? | |
mobilemáx 50 | string? | |
websitemáx 255 | string? | |
companymáx 255 | string? | |
positionmáx 255 | string? | |
documentmáx 50 | string? | |
state_registrationmáx 50 | string? | |
municipal_registrationmáx 50 | string? | |
person_typepadrão individual | individual | company | |
typepadrão lead | lead | customer | prospect | supplier | |
sourcemáx 100 | string? | |
contact_group_id | integer? | |
assigned_to | integer? | |
parent_id | integer? | |
addressmáx 255 | string? | |
address_numbermáx 20 | string? | |
address_complementmáx 100 | string? | |
neighborhoodmáx 100 | string? | |
citymáx 100 | string? | |
statemáx 50 | string? | |
zip_codemáx 20 | string? | |
countrymáx 100 | string? | |
birth_date | string (date)? | |
tags | array<string> | |
notesmáx 5000 | string? | |
custom_fields | object | {chave: valor} com as chaves do módulo de Campos Personalizados (GET /custom-fields). cf_chave também vale (dentro de custom_fields ou solto na raiz do corpo). Formato aceito por tipo: - text, textarea: texto (respeita tamanho mínimo e máximo do campo) - select, radio: o valor ou o rótulo de uma opção, sem diferenciar maiúsculas - multiselect: lista de valores ou rótulos das opções - checkbox: true/false ou lista de valores das opções - number, rating: número inteiro - decimal, currency: número (1234.56) ou texto "1.234,56" - date: AAAA-MM-DD - datetime: ISO 8601 (2026-09-30T14:00:00-03:00) - url: começando com http:// ou https:// - email, phone, color (#RRGGBB) - file, image: não gravados pela API (enviar pela tela)
Campos obrigatórios só são exigidos na criação (POST). No PATCH, só as chaves enviadas mudam e null apaga o valor do campo. Chave inexistente: 422 com unknown_keys (contas em modo compatível recebem warnings e a chave vai para legacy_custom_fields). |
notification_settings | object? | |
is_active | boolean? | |
bot_protected | boolean? | |
Respostas
| 200 | Atualizado. |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
| 422 | Validação, incluindo campos personalizados. Quando algum campo é inválido ou a chave não existe, nada do request é gravado. |
Exemplo
curl -X PUT 'https://atlas.skill-hub.app/api/v1/contacts/123' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
PATCH/contacts/{contact}escopo write
Atualizar contato (parcial)
Igual ao PUT. Só os campos enviados mudam; em custom_fields, null apaga o valor do campo.
Parâmetros
| Nome | Tipo | Observação |
|---|
contactpathobrigatório | integer | |
Corpo
| Campo | Tipo | Observação |
|---|
nameobrigatóriomáx 255 | string | |
trading_namemáx 255 | string? | |
emailmáx 255 | string (email)? | |
phonemáx 50 | string? | |
mobilemáx 50 | string? | |
websitemáx 255 | string? | |
companymáx 255 | string? | |
positionmáx 255 | string? | |
documentmáx 50 | string? | |
state_registrationmáx 50 | string? | |
municipal_registrationmáx 50 | string? | |
person_typepadrão individual | individual | company | |
typepadrão lead | lead | customer | prospect | supplier | |
sourcemáx 100 | string? | |
contact_group_id | integer? | |
assigned_to | integer? | |
parent_id | integer? | |
addressmáx 255 | string? | |
address_numbermáx 20 | string? | |
address_complementmáx 100 | string? | |
neighborhoodmáx 100 | string? | |
citymáx 100 | string? | |
statemáx 50 | string? | |
zip_codemáx 20 | string? | |
countrymáx 100 | string? | |
birth_date | string (date)? | |
tags | array<string> | |
notesmáx 5000 | string? | |
custom_fields | object | {chave: valor} com as chaves do módulo de Campos Personalizados (GET /custom-fields). cf_chave também vale (dentro de custom_fields ou solto na raiz do corpo). Formato aceito por tipo: - text, textarea: texto (respeita tamanho mínimo e máximo do campo) - select, radio: o valor ou o rótulo de uma opção, sem diferenciar maiúsculas - multiselect: lista de valores ou rótulos das opções - checkbox: true/false ou lista de valores das opções - number, rating: número inteiro - decimal, currency: número (1234.56) ou texto "1.234,56" - date: AAAA-MM-DD - datetime: ISO 8601 (2026-09-30T14:00:00-03:00) - url: começando com http:// ou https:// - email, phone, color (#RRGGBB) - file, image: não gravados pela API (enviar pela tela)
Campos obrigatórios só são exigidos na criação (POST). No PATCH, só as chaves enviadas mudam e null apaga o valor do campo. Chave inexistente: 422 com unknown_keys (contas em modo compatível recebem warnings e a chave vai para legacy_custom_fields). |
notification_settings | object? | |
is_active | boolean? | |
bot_protected | boolean? | |
Respostas
| 200 | Atualizado. |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
| 422 | Validação, incluindo campos personalizados. Quando algum campo é inválido ou a chave não existe, nada do request é gravado. |
Exemplo
curl -X PATCH 'https://atlas.skill-hub.app/api/v1/contacts/123' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"custom_fields": {"segmento": "clinica"}}'
DELETE/contacts/{contact}escopo write
Remover contato
Exclusão lógica. O registro deixa de aparecer nas listagens mas não é apagado do banco.
Parâmetros
| Nome | Tipo | Observação |
|---|
contactpathobrigatório | integer | |
Respostas
| 200 | Removido. |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
Exemplo
curl -X DELETE 'https://atlas.skill-hub.app/api/v1/contacts/123' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
GET/contacts/{contact}/dealsescopo read
Negócios do contato
Ordenado por data de criação, do mais novo para o mais antigo. Sem filtros.
Parâmetros
| Nome | Tipo | Observação |
|---|
contactpathobrigatório | integer | |
pagequerypadrão 1 | integer | |
per_pagequerypadrão 25 | integer | |
Respostas
| 200 | Lista paginada. |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
Exemplo
curl -X GET 'https://atlas.skill-hub.app/api/v1/contacts/123/deals' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
GET/contacts/{contact}/conversationsescopo read
Conversas do contato
Ordenado pela última mensagem, da mais recente para a mais antiga. Sem filtros.
Parâmetros
| Nome | Tipo | Observação |
|---|
contactpathobrigatório | integer | |
pagequerypadrão 1 | integer | |
per_pagequerypadrão 25 | integer | |
Respostas
| 200 | Lista paginada. |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
Exemplo
curl -X GET 'https://atlas.skill-hub.app/api/v1/contacts/123/conversations' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
Funis e etapas
Funis de venda e suas etapas. É aqui que se descobre o id da etapa de destino.
GET/pipelinesescopo read
Listar funis
Funis ativos da conta, em ordem alfabética, cada um com suas etapas já ordenadas (inclusive as de ganho e de perda). Sem paginação.
Respostas
| 200 | OK |
| 401 | Token ausente, inválido ou expirado. |
| 403 | Quatro causas, distinguíveis pelo corpo:
- token sem o escopo exigido (code: insufficient_scope, com required_scope), ver a seção *Escopos do token*; - usuário sem conta vinculada; - licença sem API habilitada; - addon de acesso à API inativo. |
| 429 | Limite de 60 requisições por minuto estourado. |
Exemplo
curl -X GET 'https://atlas.skill-hub.app/api/v1/pipelines' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
GET/pipelines/{pipeline}/stagesescopo read
Listar etapas de um funil
Etapas do funil em sort_order. Por padrão exclui as etapas de ganho e de perda; passe include_won_lost=true para incluí-las. Funil de outra conta responde 404.
Parâmetros
| Nome | Tipo | Observação |
|---|
pipelinepathobrigatório | integer | |
include_won_lostquerypadrão False | boolean | |
Respostas
| 200 | OK |
| 401 | Token ausente, inválido ou expirado. |
| 403 | Quatro causas, distinguíveis pelo corpo:
- token sem o escopo exigido (code: insufficient_scope, com required_scope), ver a seção *Escopos do token*; - usuário sem conta vinculada; - licença sem API habilitada; - addon de acesso à API inativo. |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
| 429 | Limite de 60 requisições por minuto estourado. |
Exemplo
curl -X GET 'https://atlas.skill-hub.app/api/v1/pipelines/123/stages' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
Negócios
Negócios do Kanban. Mudança de etapa e fechamento só por /move, /win e /lose, com os dois interruptores.
GET/dealsescopo read
Listar negócios
Parâmetros
| Nome | Tipo | Observação |
|---|
pagequerypadrão 1 | integer | |
per_pagequerypadrão 50 | integer | |
pipeline_idquery | integer | |
stage_idquery | integer | |
assigned_toquery | integer | |
contact_idquery | integer | |
statusquery | open | won | lost | |
created_fromquery | string (date) | Criação, a partir de (data ou data-hora). |
created_toquery | string (date) | |
stage_changed_fromquery | string (date) | Entrada na etapa atual, a partir de. |
stage_changed_toquery | string (date) | |
value_minquery | number | |
value_maxquery | number | |
searchquery | string | Busca parcial no título do negócio e no nome do contato. |
sort_byquerypadrão created_at | created_at | updated_at | value | title | expected_close_date | stage_changed_at | |
sort_dirquerypadrão desc | asc | desc | Qualquer valor diferente de asc é tratado como desc. |
Respostas
| 200 | OK |
| 401 | Token ausente, inválido ou expirado. |
| 403 | Quatro causas, distinguíveis pelo corpo:
- token sem o escopo exigido (code: insufficient_scope, com required_scope), ver a seção *Escopos do token*; - usuário sem conta vinculada; - licença sem API habilitada; - addon de acesso à API inativo. |
| 429 | Limite de 60 requisições por minuto estourado. |
Exemplo
curl -X GET 'https://atlas.skill-hub.app/api/v1/deals' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
POST/dealsescopo write
Criar negócio
Cria o negócio na etapa informada, que precisa pertencer ao funil informado (GET /pipelines). Contato, responsável, origem e campanha são verificados contra a sua conta. Se conversation_id vier, é vinculado após verificação de posse; se não vier e o contato tiver exatamente uma conversa, ela é vinculada.
Na criação o único efeito colateral existente é a automação deal_created, controlada por trigger_automations (padrão false, exige send). fire_pixel_events é aceito por consistência e não tem efeito aqui.
Corpo
| Campo | Tipo | Observação |
|---|
titleobrigatóriomáx 255 | string | |
pipeline_idobrigatório | integer | |
stage_idobrigatório | integer | Etapa do funil informado. |
contact_id | integer? | |
assigned_to | integer? | |
valuepadrão 0 | number | |
currencypadrão BRLmáx 10 | string | |
expected_close_date | string (date)? | |
notesmáx 5000 | string? | |
custom_fields | object | {chave: valor} com as chaves do módulo de Campos Personalizados (GET /custom-fields). cf_chave também vale (dentro de custom_fields ou solto na raiz do corpo). Formato aceito por tipo: - text, textarea: texto (respeita tamanho mínimo e máximo do campo) - select, radio: o valor ou o rótulo de uma opção, sem diferenciar maiúsculas - multiselect: lista de valores ou rótulos das opções - checkbox: true/false ou lista de valores das opções - number, rating: número inteiro - decimal, currency: número (1234.56) ou texto "1.234,56" - date: AAAA-MM-DD - datetime: ISO 8601 (2026-09-30T14:00:00-03:00) - url: começando com http:// ou https:// - email, phone, color (#RRGGBB) - file, image: não gravados pela API (enviar pela tela)
Campos obrigatórios só são exigidos na criação (POST). No PATCH, só as chaves enviadas mudam e null apaga o valor do campo. Chave inexistente: 422 com unknown_keys (contas em modo compatível recebem warnings e a chave vai para legacy_custom_fields). |
source_id | integer? | |
campaign_id | integer? | |
conversation_id | integer? | |
trigger_automationspadrão False | boolean | |
fire_pixel_eventspadrão False | boolean | |
Respostas
| 201 | Criado |
| 401 | Token ausente, inválido ou expirado. |
| 403 | Quatro causas, distinguíveis pelo corpo:
- token sem o escopo exigido (code: insufficient_scope, com required_scope), ver a seção *Escopos do token*; - usuário sem conta vinculada; - licença sem API habilitada; - addon de acesso à API inativo. |
| 422 | Validação, incluindo campos personalizados. Quando algum campo é inválido ou a chave não existe, nada do request é gravado. |
| 429 | Limite de 60 requisições por minuto estourado. |
Exemplo
curl -X POST 'https://atlas.skill-hub.app/api/v1/deals' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
GET/deals/{deal}escopo read
Ler negócio
Parâmetros
| Nome | Tipo | Observação |
|---|
dealpathobrigatório | integer | |
Respostas
| 200 | OK |
| 401 | Token ausente, inválido ou expirado. |
| 403 | Quatro causas, distinguíveis pelo corpo:
- token sem o escopo exigido (code: insufficient_scope, com required_scope), ver a seção *Escopos do token*; - usuário sem conta vinculada; - licença sem API habilitada; - addon de acesso à API inativo. |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
| 429 | Limite de 60 requisições por minuto estourado. |
Exemplo
curl -X GET 'https://atlas.skill-hub.app/api/v1/deals/123' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
PATCH/deals/{deal}escopo write
Alterar dados do negócio
Altera título, valor, moeda, responsável, contato, data prevista, notas, campos personalizados, origem, campanha e conversa vinculada.
Campos personalizados no PATCH são parciais: só as chaves enviadas mudam; as que não vierem ficam como estão; null apaga o valor daquele campo. Se qualquer campo for inválido, a resposta é 422 e nada do request é gravado.
Não muda etapa nem status. stage_id, status, pipeline_id, probability, closed_at, lost_at, loss_reason_id, won e lost respondem 422 mandando usar /move, /win ou /lose.
Parâmetros
| Nome | Tipo | Observação |
|---|
dealpathobrigatório | integer | |
Corpo
| Campo | Tipo | Observação |
|---|
titlemáx 255 | string | |
contact_id | integer? | |
assigned_to | integer? | |
value | number | |
currencymáx 10 | string | |
expected_close_date | string (date)? | |
notesmáx 5000 | string? | |
custom_fields | object | {chave: valor} com as chaves do módulo de Campos Personalizados (GET /custom-fields). cf_chave também vale (dentro de custom_fields ou solto na raiz do corpo). Formato aceito por tipo: - text, textarea: texto (respeita tamanho mínimo e máximo do campo) - select, radio: o valor ou o rótulo de uma opção, sem diferenciar maiúsculas - multiselect: lista de valores ou rótulos das opções - checkbox: true/false ou lista de valores das opções - number, rating: número inteiro - decimal, currency: número (1234.56) ou texto "1.234,56" - date: AAAA-MM-DD - datetime: ISO 8601 (2026-09-30T14:00:00-03:00) - url: começando com http:// ou https:// - email, phone, color (#RRGGBB) - file, image: não gravados pela API (enviar pela tela)
Campos obrigatórios só são exigidos na criação (POST). No PATCH, só as chaves enviadas mudam e null apaga o valor do campo. Chave inexistente: 422 com unknown_keys (contas em modo compatível recebem warnings e a chave vai para legacy_custom_fields). |
source_id | integer? | |
campaign_id | integer? | |
conversation_id | integer? | |
Respostas
| 200 | OK |
| 401 | Token ausente, inválido ou expirado. |
| 403 | Quatro causas, distinguíveis pelo corpo:
- token sem o escopo exigido (code: insufficient_scope, com required_scope), ver a seção *Escopos do token*; - usuário sem conta vinculada; - licença sem API habilitada; - addon de acesso à API inativo. |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
| 422 | Validação, campo personalizado inválido (ver CustomFieldValidationError), ou tentativa de mudar etapa/status por PATCH: {"message":"…","errors":{"stage_id":["Este campo não pode ser alterado por PATCH. Use POST /deals/{id}/move…"]}}. |
| 429 | Limite de 60 requisições por minuto estourado. |
Exemplo
curl -X PATCH 'https://atlas.skill-hub.app/api/v1/deals/123' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"custom_fields": {"cargo_da_vaga": "SDR", "tipo_de_vaga": "SDR", "data_da_candidatura": "2026-09-30", "link_da_vaga": null}}'
GET/deals/{deal}/documentsescopo read
Listar documentos
Lista os arquivos da aba Documentos do negócio, do mais novo para o mais antigo. Cada item traz um link assinado novo em url, válido por 30 minutos (url_expires_at).
Parâmetros
| Nome | Tipo | Observação |
|---|
dealpathobrigatório | integer | |
Respostas
| 200 | Lista de documentos. |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
| 429 | Limite de 60 requisições por minuto estourado. |
Exemplo
curl -X GET 'https://atlas.skill-hub.app/api/v1/deals/123/documents' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
POST/deals/{deal}/documentsescopo write
Anexar documento
Anexa um arquivo na aba Documentos do negócio. multipart/form-data, campo file. Mesmos limites da tela: até 50 MB; arquivos executáveis ou que o navegador interpreta (php, html, svg, js, exe…) são recusados. Mesmo limite de requisições por minuto dos outros endpoints.
O arquivo fica em área privada. A resposta traz url, um link assinado e temporário para baixar o arquivo sem token, válido por 30 minutos (url_expires_at). Depois disso o link responde 403; para baixar de novo, chame GET /deals/{deal}/documents, que devolve links novos. Não guarde a URL como endereço permanente do arquivo.
Parâmetros
| Nome | Tipo | Observação |
|---|
dealpathobrigatório | integer | |
Respostas
| 201 | Anexado. |
| 401 | Token ausente, inválido ou expirado. |
| 403 | Quatro causas, distinguíveis pelo corpo:
- token sem o escopo exigido (code: insufficient_scope, com required_scope), ver a seção *Escopos do token*; - usuário sem conta vinculada; - licença sem API habilitada; - addon de acesso à API inativo. |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
| 422 | Falha de validação. Formato padrão do framework. |
| 429 | Limite de 60 requisições por minuto estourado. |
Exemplo
curl -X POST 'https://atlas.skill-hub.app/api/v1/deals/123/documents' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
POST/deals/{deal}/moveescopo write
Mover de etapa
Move o negócio para a etapa informada, que pode ser de outro funil da mesma conta. Etapa de ganho ou de perda responde 422: use /win ou /lose. Registra a atividade com o nome do token.
Sem os interruptores: só a etapa muda. Com trigger_automations=true as automações da etapa disparam e a métrica de conversão é gravada; com fire_pixel_events=true o evento mapeado da etapa vai para a Meta CAPI. Qualquer um ligado exige o escopo send.
Parâmetros
| Nome | Tipo | Observação |
|---|
dealpathobrigatório | integer | |
Corpo
| Campo | Tipo | Observação |
|---|
stage_idobrigatório | integer | |
trigger_automationspadrão False | boolean | |
fire_pixel_eventspadrão False | boolean | |
Respostas
| 200 | Movido |
| 401 | Token ausente, inválido ou expirado. |
| 403 | Quatro causas, distinguíveis pelo corpo:
- token sem o escopo exigido (code: insufficient_scope, com required_scope), ver a seção *Escopos do token*; - usuário sem conta vinculada; - licença sem API habilitada; - addon de acesso à API inativo. |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
| 422 | Falha de validação. Formato padrão do framework. |
| 429 | Limite de 60 requisições por minuto estourado. |
Exemplo
curl -X POST 'https://atlas.skill-hub.app/api/v1/deals/123/move' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
POST/deals/{deal}/winescopo write
Marcar como ganho
Status won, etapa de ganho do funil, closed_at hoje e o contato vira cliente. Negócio já ganho responde 422.
Sem os interruptores nada mais acontece. Com trigger_automations=true a automação deal_won dispara e a venda entra na métrica de conversão; com fire_pixel_events=true a Meta CAPI recebe Purchase (ou o evento mapeado). Purchase falso na conta de anúncios não se desfaz. Qualquer um ligado exige o escopo send.
Parâmetros
| Nome | Tipo | Observação |
|---|
dealpathobrigatório | integer | |
Corpo
| Campo | Tipo | Observação |
|---|
trigger_automationspadrão False | boolean | |
fire_pixel_eventspadrão False | boolean | |
Respostas
| 200 | Ganho |
| 401 | Token ausente, inválido ou expirado. |
| 403 | Quatro causas, distinguíveis pelo corpo:
- token sem o escopo exigido (code: insufficient_scope, com required_scope), ver a seção *Escopos do token*; - usuário sem conta vinculada; - licença sem API habilitada; - addon de acesso à API inativo. |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
| 422 | Negócio já ganho. |
| 429 | Limite de 60 requisições por minuto estourado. |
Exemplo
curl -X POST 'https://atlas.skill-hub.app/api/v1/deals/123/win' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
POST/deals/{deal}/loseescopo write
Marcar como perdido
Status lost, etapa de perda do funil, lost_at agora, motivo e notas de perda. O motivo precisa ser da sua conta. Negócio já perdido responde 422. Interruptores como em /win (deal_lost e evento mapeado).
Parâmetros
| Nome | Tipo | Observação |
|---|
dealpathobrigatório | integer | |
Corpo
| Campo | Tipo | Observação |
|---|
loss_reason_id | integer? | |
loss_notesmáx 1000 | string? | |
trigger_automationspadrão False | boolean | |
fire_pixel_eventspadrão False | boolean | |
Respostas
| 200 | Perdido |
| 401 | Token ausente, inválido ou expirado. |
| 403 | Quatro causas, distinguíveis pelo corpo:
- token sem o escopo exigido (code: insufficient_scope, com required_scope), ver a seção *Escopos do token*; - usuário sem conta vinculada; - licença sem API habilitada; - addon de acesso à API inativo. |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
| 422 | Falha de validação. Formato padrão do framework. |
| 429 | Limite de 60 requisições por minuto estourado. |
Exemplo
curl -X POST 'https://atlas.skill-hub.app/api/v1/deals/123/lose' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
GET/deals/{deal}/activitiesescopo read
Histórico do negócio
Atividades do mais recente para o mais antigo, com page e per_page (padrão 50, teto 100).
Parâmetros
| Nome | Tipo | Observação |
|---|
dealpathobrigatório | integer | |
pagequerypadrão 1 | integer | |
per_pagequerypadrão 50 | integer | |
Respostas
| 200 | OK |
| 401 | Token ausente, inválido ou expirado. |
| 403 | Quatro causas, distinguíveis pelo corpo:
- token sem o escopo exigido (code: insufficient_scope, com required_scope), ver a seção *Escopos do token*; - usuário sem conta vinculada; - licença sem API habilitada; - addon de acesso à API inativo. |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
| 429 | Limite de 60 requisições por minuto estourado. |
Exemplo
curl -X GET 'https://atlas.skill-hub.app/api/v1/deals/123/activities' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
Campos personalizados
Definições dos campos personalizados de negócios e contatos (as chaves que custom_fields aceita).
GET/custom-fieldsescopo read
Listar campos personalizados
Definições dos campos personalizados da sua conta: é daqui que saem as chaves que custom_fields aceita em negócios e contatos. Por padrão só os ativos.
Parâmetros
| Nome | Tipo | Observação |
|---|
entity_typequery | deal | contact | Sem ele, vêm os dois. |
include_inactivequerypadrão False | boolean | |
Respostas
| 200 | OK |
| 401 | Token ausente, inválido ou expirado. |
| 403 | Quatro causas, distinguíveis pelo corpo:
- token sem o escopo exigido (code: insufficient_scope, com required_scope), ver a seção *Escopos do token*; - usuário sem conta vinculada; - licença sem API habilitada; - addon de acesso à API inativo. |
| 422 | Falha de validação. Formato padrão do framework. |
| 429 | Limite de 60 requisições por minuto estourado. |
Exemplo
curl -X GET 'https://atlas.skill-hub.app/api/v1/custom-fields' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
Conversas
Conversas de WhatsApp e envio de mensagens.
GET/conversationsescopo read
Listar conversas
Parâmetros
| Nome | Tipo | Observação |
|---|
pagequerypadrão 1 | integer | |
per_pagequerypadrão 50 | integer | |
statusquery | open | pending | resolved | |
channel_idquery | integer | |
assigned_toquery | integer | |
contact_idquery | integer | |
searchquery | string | Busca parcial em nome exibido, identificador remoto e prévia da última mensagem. |
is_groupquery | boolean | |
sort_byquerypadrão last_message_at | last_message_at | created_at | unread_count | |
sort_dirquerypadrão desc | asc | desc | Qualquer valor diferente de asc é tratado como desc. |
Respostas
| 200 | Lista paginada. |
| 401 | Token ausente, inválido ou expirado. |
Exemplo
curl -X GET 'https://atlas.skill-hub.app/api/v1/conversations' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
GET/conversations/{conversation}escopo read
Obter conversa
Parâmetros
| Nome | Tipo | Observação |
|---|
conversationpathobrigatório | integer | |
Respostas
| 200 | OK |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
Exemplo
curl -X GET 'https://atlas.skill-hub.app/api/v1/conversations/123' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
PUT/conversations/{conversation}escopo write
Atualizar conversa
Enviar status: resolved executa a rotina de resolução da conversa, registrando quem resolveu.
Cuidado com dois comportamentos:
- assigned_user_id só atribui se o usuário pertencer à sua conta. Se não pertencer, o valor é ignorado em silêncio e a resposta é 200. - assigned_department_id é gravado sem essa verificação.
Envie null em assigned_user_id para desatribuir.
Parâmetros
| Nome | Tipo | Observação |
|---|
conversationpathobrigatório | integer | |
Corpo
| Campo | Tipo | Observação |
|---|
status | open | pending | resolved | |
assigned_user_id | integer? | |
assigned_department_id | integer? | |
Respostas
| 200 | Atualizada. |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
| 422 | Falha de validação. Formato padrão do framework. |
Exemplo
curl -X PUT 'https://atlas.skill-hub.app/api/v1/conversations/123' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
GET/conversations/{conversation}/messagesescopo read
Listar mensagens
Paginação por cursor, e não por página. A resposta traz has_more no lugar de meta. As mensagens vêm da mais antiga para a mais nova. Mensagens apagadas não são incluídas.
Parâmetros
| Nome | Tipo | Observação |
|---|
conversationpathobrigatório | integer | |
before_idquery | integer | Devolve mensagens anteriores a este id. Use para carregar histórico. |
after_idquery | integer | Devolve mensagens posteriores a este id. Use para buscar novidades. |
limitquerypadrão 50 | integer | |
Respostas
| 200 | OK |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
Exemplo
curl -X GET 'https://atlas.skill-hub.app/api/v1/conversations/123/messages' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
POST/conversations/{conversation}/messagesescopo send
Enviar mensagem em uma conversa
Envia para o canal já vinculado à conversa.
É obrigatório ao menos um entre content, media e media_url.
Efeitos colaterais, que acontecem sempre:
- A mensagem é marcada com
metadata.via = "api". - Se a conversa não tiver responsável, ela é atribuída ao usuário do token.
- O status da conversa passa para
open.
Áudio é enviado como mensagem de voz. Quando há mídia sem type, o padrão é document.
Parâmetros
| Nome | Tipo | Observação |
|---|
conversationpathobrigatório | integer | |
Corpo
| Campo | Tipo | Observação |
|---|
contentmáx 10000 | string? | |
type | text | image | document | video | audio | |
media_url | string (uri)? | |
filenamemáx 255 | string? | |
Aceita também multipart/form-data, com o arquivo no campo media.
Respostas
| 201 | Enviada. |
| 400 | O canal recusou o envio. Ocorre com canal desconectado (WhatsApp channel is disconnected.), com erro devolvido pelo provedor, ou com falha genérica de envio. |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
| 422 | Falha de validação, ou nenhum conteúdo enviado. |
Exemplo
curl -X POST 'https://atlas.skill-hub.app/api/v1/conversations/123/messages' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"content": "Olá! Seu atendimento foi retomado.", "type": "text"}'
POST/messages/sendescopo send
Enviar mensagem por telefone
Envia sem conhecer a conversa. Dois modos:
- Com conversation_id: usa a conversa existente e o canal dela. - Sem conversation_id: channel_id passa a ser obrigatório. O telefone é reduzido a dígitos e a conversa é criada se ainda não existir.
Embora phone seja declarado como opcional, ele é obrigatório na prática no segundo modo.
Corpo
| Campo | Tipo | Observação |
|---|
contentmáx 10000 | string? | |
type | text | image | document | video | audio | |
media_url | string (uri)? | |
filenamemáx 255 | string? | |
phonemáx 50 | string | Obrigatório quando não há conversation_id. |
conversation_id | integer? | |
channel_id | integer | Obrigatório quando não há conversation_id. |
Aceita também multipart/form-data, com o arquivo no campo media.
Respostas
| 201 | Enviada. |
| 400 | Canal desconectado ou erro do provedor. |
| 404 | Conversa ou canal não encontrado. As mensagens possíveis são Conversation not found., Channel not found for this conversation. e Channel not found. |
| 422 | Falha de validação. Formato padrão do framework. |
| 500 | Não foi possível criar a conversa. |
Exemplo
curl -X POST 'https://atlas.skill-hub.app/api/v1/messages/send' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"phone": "5511912345678", "channel_id": 12, "content": "Olá! Recebemos seu contato."}'
Faturas
Faturas, itens e pagamentos.
GET/invoicesescopo read
Listar faturas
Parâmetros
| Nome | Tipo | Observação |
|---|
pagequerypadrão 1 | integer | |
per_pagequerypadrão 50 | integer | |
statusquery | draft | pending | sent | paid | cancelled | |
contact_idquery | integer | |
searchquery | string | Busca parcial em número e título. |
due_fromquery | string (date) | |
due_toquery | string (date) | |
is_recurringquery | boolean | |
sort_byquerypadrão created_at | created_at | due_date | total | number | status | |
sort_dirquerypadrão desc | asc | desc | Qualquer valor diferente de asc é tratado como desc. |
Respostas
| 200 | Lista paginada. |
| 401 | Token ausente, inválido ou expirado. |
| 403 | Quatro causas, distinguíveis pelo corpo:
- token sem o escopo exigido (code: insufficient_scope, com required_scope), ver a seção *Escopos do token*; - usuário sem conta vinculada; - licença sem API habilitada; - addon de acesso à API inativo. |
| 429 | Limite de 60 requisições por minuto estourado. |
Exemplo
curl -X GET 'https://atlas.skill-hub.app/api/v1/invoices' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
POST/invoicesescopo write
Criar fatura
Os totais são calculados pelo servidor a partir dos itens. Não envie subtotal nem total.
Padrões aplicados: issue_date igual a hoje, currency igual a BRL, discount_type igual a fixed, status igual a draft, unit igual a un, e o gateway de pagamento padrão da conta.
Atenção: o contact_id enviado não é verificado contra a sua conta.
Corpo
| Campo | Tipo | Observação |
|---|
contact_idobrigatório | integer | |
titlemáx 255 | string? | |
descriptionmáx 5000 | string? | |
issue_date | string (date)? | |
due_dateobrigatório | string (date) | |
currencypadrão BRLmáx 10 | string? | |
discount_amount | number? | |
discount_typepadrão fixed | fixed | percent | |
notesmáx 5000 | string? | |
termsmáx 5000 | string? | |
itemsobrigatório | array<object> | |
Respostas
| 201 | Criada. |
| 422 | Falha de validação. Formato padrão do framework. |
Exemplo
curl -X POST 'https://atlas.skill-hub.app/api/v1/invoices' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"contact_id": 1001, "due_date": "2026-10-15", "title": "Mensalidade de outubro", "items": [{"name": "Plano Pro", "quantity": 1, "unit_price": 499.9, "unit": "un"}]}'
GET/invoices/{invoice}escopo read
Obter fatura
Parâmetros
| Nome | Tipo | Observação |
|---|
invoicepathobrigatório | integer | |
Respostas
| 200 | OK |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
Exemplo
curl -X GET 'https://atlas.skill-hub.app/api/v1/invoices/123' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
PUT/invoices/{invoice}escopo write
Atualizar fatura
Não aceita itens e não recalcula os totais. Para mudar os itens de uma fatura, crie uma nova.
Parâmetros
| Nome | Tipo | Observação |
|---|
invoicepathobrigatório | integer | |
Corpo
| Campo | Tipo | Observação |
|---|
contact_id | integer | |
titlemáx 255 | string? | |
descriptionmáx 5000 | string? | |
issue_date | string (date)? | |
due_date | string (date) | |
status | draft | pending | sent | paid | cancelled | |
currencymáx 10 | string? | |
discount_amount | number? | |
discount_type | fixed | percent | |
notesmáx 5000 | string? | |
termsmáx 5000 | string? | |
Respostas
| 200 | Atualizada. |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
| 422 | Falha de validação. Formato padrão do framework. |
Exemplo
curl -X PUT 'https://atlas.skill-hub.app/api/v1/invoices/123' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
DELETE/invoices/{invoice}escopo write
Remover fatura
Parâmetros
| Nome | Tipo | Observação |
|---|
invoicepathobrigatório | integer | |
Respostas
| 200 | Removido. |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
Exemplo
curl -X DELETE 'https://atlas.skill-hub.app/api/v1/invoices/123' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
GET/invoices/{invoice}/paymentsescopo read
Listar pagamentos da fatura
Parâmetros
| Nome | Tipo | Observação |
|---|
invoicepathobrigatório | integer | |
Respostas
| 200 | OK |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
Exemplo
curl -X GET 'https://atlas.skill-hub.app/api/v1/invoices/123/payments' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
POST/invoices/{invoice}/paymentsescopo write
Registrar pagamento
Registra um pagamento e atualiza o status da fatura. Uma fatura em status que não aceita pagamento responde 422 antes mesmo da validação dos campos.
Padrões: method igual a manual e paid_at igual a agora.
Parâmetros
| Nome | Tipo | Observação |
|---|
invoicepathobrigatório | integer | |
Corpo
| Campo | Tipo | Observação |
|---|
amountobrigatório | number | |
method | pix | boleto | credit_card | debit_card | transfer | manual | |
notesmáx 1000 | string? | |
paid_at | string (date-time)? | |
Respostas
| 201 | Registrado. |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
| 422 | Validação, ou a fatura não aceita pagamento no status atual. |
Exemplo
curl -X POST 'https://atlas.skill-hub.app/api/v1/invoices/123/payments' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"amount": 499.9, "method": "pix"}'
Propostas
Propostas comerciais e itens.
GET/proposalsescopo read
Listar propostas
Parâmetros
| Nome | Tipo | Observação |
|---|
pagequerypadrão 1 | integer | |
per_pagequerypadrão 50 | integer | |
statusquery | draft | sent | accepted | rejected | expired | |
contact_idquery | integer | |
deal_idquery | integer | |
searchquery | string | Busca parcial em número, título e assunto. |
sort_byquerypadrão created_at | created_at | proposal_date | valid_until | total | number | status | |
sort_dirquerypadrão desc | asc | desc | Qualquer valor diferente de asc é tratado como desc. |
Respostas
| 200 | Lista paginada. |
| 401 | Token ausente, inválido ou expirado. |
| 403 | Quatro causas, distinguíveis pelo corpo:
- token sem o escopo exigido (code: insufficient_scope, com required_scope), ver a seção *Escopos do token*; - usuário sem conta vinculada; - licença sem API habilitada; - addon de acesso à API inativo. |
| 429 | Limite de 60 requisições por minuto estourado. |
Exemplo
curl -X GET 'https://atlas.skill-hub.app/api/v1/proposals' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
POST/proposalsescopo write
Criar proposta
Totais calculados pelo servidor.
Padrões: assigned_to igual ao usuário do token, proposal_date igual a hoje, valid_until igual a hoje mais 30 dias, currency igual a BRL e status igual a draft.
Atenção ao discount_type: aqui os valores são fixed e percentage, diferente das faturas, que usam percent.
Corpo
| Campo | Tipo | Observação |
|---|
contact_idobrigatório | integer | |
deal_id | integer? | |
assigned_to | integer? | |
titlemáx 255 | string? | |
subjectmáx 255 | string? | |
proposal_date | string (date)? | |
valid_until | string (date)? | |
currencypadrão BRLmáx 10 | string? | |
discount_amount | number? | |
discount_type | fixed | percentage | |
content | string? | |
notesmáx 5000 | string? | |
termsmáx 5000 | string? | |
itemsobrigatório | array<object> | |
Respostas
| 201 | Criada. |
| 422 | Falha de validação. Formato padrão do framework. |
Exemplo
curl -X POST 'https://atlas.skill-hub.app/api/v1/proposals' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"contact_id": 1001, "title": "Proposta comercial", "items": [{"name": "Implantação", "quantity": 1, "unit_price": 3500}]}'
GET/proposals/{proposal}escopo read
Obter proposta
Parâmetros
| Nome | Tipo | Observação |
|---|
proposalpathobrigatório | integer | |
Respostas
| 200 | OK |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
Exemplo
curl -X GET 'https://atlas.skill-hub.app/api/v1/proposals/123' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
PUT/proposals/{proposal}escopo write
Atualizar proposta
Parâmetros
| Nome | Tipo | Observação |
|---|
proposalpathobrigatório | integer | |
Corpo
| Campo | Tipo | Observação |
|---|
contact_id | integer | |
deal_id | integer? | |
assigned_to | integer? | |
titlemáx 255 | string? | |
subjectmáx 255 | string? | |
proposal_date | string (date)? | |
valid_until | string (date)? | |
status | draft | sent | accepted | rejected | expired | |
currencymáx 10 | string? | |
discount_amount | number? | |
discount_type | fixed | percentage | |
content | string? | |
notesmáx 5000 | string? | |
termsmáx 5000 | string? | |
Respostas
| 200 | Atualizada. |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
| 422 | Falha de validação. Formato padrão do framework. |
Exemplo
curl -X PUT 'https://atlas.skill-hub.app/api/v1/proposals/123' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
DELETE/proposals/{proposal}escopo write
Remover proposta
Parâmetros
| Nome | Tipo | Observação |
|---|
proposalpathobrigatório | integer | |
Respostas
| 200 | Removido. |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
Exemplo
curl -X DELETE 'https://atlas.skill-hub.app/api/v1/proposals/123' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
Agendamentos
Compromissos da agenda.
GET/appointmentsescopo read
Listar agendamentos
A ordenação padrão aqui é crescente, diferente dos outros recursos.
Parâmetros
| Nome | Tipo | Observação |
|---|
pagequerypadrão 1 | integer | |
per_pagequerypadrão 50 | integer | |
statusquery | scheduled | confirmed | cancelled | completed | |
typequery | meeting | call | task | event | other | |
user_idquery | integer | |
contact_idquery | integer | |
deal_idquery | integer | |
start_fromquery | string (date-time) | |
start_toquery | string (date-time) | |
searchquery | string | Busca parcial em título, descrição e local. |
sort_byquerypadrão start_at | start_at | end_at | created_at | title | status | |
sort_dirquerypadrão asc | asc | desc | Qualquer valor diferente de desc é tratado como asc. |
Respostas
| 200 | Lista paginada. |
| 401 | Token ausente, inválido ou expirado. |
| 403 | Quatro causas, distinguíveis pelo corpo:
- token sem o escopo exigido (code: insufficient_scope, com required_scope), ver a seção *Escopos do token*; - usuário sem conta vinculada; - licença sem API habilitada; - addon de acesso à API inativo. |
| 429 | Limite de 60 requisições por minuto estourado. |
Exemplo
curl -X GET 'https://atlas.skill-hub.app/api/v1/appointments' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
POST/appointmentsescopo write
Criar agendamento
Padrões: user_id igual ao usuário do token, type igual a meeting, status igual a scheduled e end_at igual a start_at mais uma hora.
Corpo
| Campo | Tipo | Observação |
|---|
titleobrigatóriomáx 255 | string | |
descriptionmáx 5000 | string? | |
start_atobrigatório | string (date-time) | |
end_at | string (date-time)? | Precisa ser igual ou posterior a start_at. |
all_day | boolean? | |
locationmáx 255 | string? | |
typepadrão meeting | meeting | call | task | event | other | |
meeting_type | in_person | online | |
statuspadrão scheduled | scheduled | confirmed | cancelled | completed | |
colormáx 20 | string? | |
user_id | integer? | |
contact_id | integer? | |
deal_id | integer? | |
notesmáx 5000 | string? | |
Respostas
| 201 | Criado. |
| 422 | Falha de validação. Formato padrão do framework. |
Exemplo
curl -X POST 'https://atlas.skill-hub.app/api/v1/appointments' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"title": "Reunião de apresentação", "start_at": "2026-09-20T14:00:00-03:00", "end_at": "2026-09-20T15:00:00-03:00", "contact_id": 1001, "meeting_type": "online"}'
GET/appointments/{appointment}escopo read
Obter agendamento
Parâmetros
| Nome | Tipo | Observação |
|---|
appointmentpathobrigatório | integer | |
Respostas
| 200 | OK |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
Exemplo
curl -X GET 'https://atlas.skill-hub.app/api/v1/appointments/123' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
PUT/appointments/{appointment}escopo write
Atualizar agendamento
A validação de que end_at vem depois de start_at existe na criação, mas não na atualização. Garanta a coerência do seu lado.
Parâmetros
| Nome | Tipo | Observação |
|---|
appointmentpathobrigatório | integer | |
Corpo
| Campo | Tipo | Observação |
|---|
titleobrigatóriomáx 255 | string | |
descriptionmáx 5000 | string? | |
start_atobrigatório | string (date-time) | |
end_at | string (date-time)? | Precisa ser igual ou posterior a start_at. |
all_day | boolean? | |
locationmáx 255 | string? | |
typepadrão meeting | meeting | call | task | event | other | |
meeting_type | in_person | online | |
statuspadrão scheduled | scheduled | confirmed | cancelled | completed | |
colormáx 20 | string? | |
user_id | integer? | |
contact_id | integer? | |
deal_id | integer? | |
notesmáx 5000 | string? | |
Respostas
| 200 | Atualizado. |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
| 422 | Falha de validação. Formato padrão do framework. |
Exemplo
curl -X PUT 'https://atlas.skill-hub.app/api/v1/appointments/123' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
DELETE/appointments/{appointment}escopo write
Remover agendamento
Parâmetros
| Nome | Tipo | Observação |
|---|
appointmentpathobrigatório | integer | |
Respostas
| 200 | Removido. |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
Exemplo
curl -X DELETE 'https://atlas.skill-hub.app/api/v1/appointments/123' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
Produtos
Produtos e serviços do catálogo.
GET/productsescopo read
Listar produtos
A ordenação padrão aqui é crescente por nome.
Parâmetros
| Nome | Tipo | Observação |
|---|
pagequerypadrão 1 | integer | |
per_pagequerypadrão 50 | integer | |
typequery | product | service | |
category_idquery | integer | |
is_activequery | boolean | |
has_variationsquery | boolean | |
searchquery | string | Busca parcial em nome, SKU e descrição. |
sort_byquerypadrão name | name | price | sku | created_at | stock_quantity | sort_order | |
sort_dirquerypadrão asc | asc | desc | Qualquer valor diferente de desc é tratado como asc. |
Respostas
| 200 | Lista paginada. |
| 401 | Token ausente, inválido ou expirado. |
| 403 | Quatro causas, distinguíveis pelo corpo:
- token sem o escopo exigido (code: insufficient_scope, com required_scope), ver a seção *Escopos do token*; - usuário sem conta vinculada; - licença sem API habilitada; - addon de acesso à API inativo. |
| 429 | Limite de 60 requisições por minuto estourado. |
Exemplo
curl -X GET 'https://atlas.skill-hub.app/api/v1/products' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
POST/productsescopo write
Criar produto
Padrões: type igual a product e is_active igual a verdadeiro.
Não existe endpoint para criar ou editar variações. Elas são apenas listadas na leitura de um produto.
Corpo
| Campo | Tipo | Observação |
|---|
nameobrigatóriomáx 255 | string | |
skumáx 100 | string? | |
descriptionmáx 5000 | string? | |
short_descriptionmáx 500 | string? | |
typepadrão product | product | service | |
categorymáx 255 | string? | |
category_id | integer? | |
priceobrigatório | number | |
cost | number? | |
currencymáx 10 | string? | |
unitmáx 50 | string? | |
tax_rate | number? | |
track_stock | boolean? | |
stock_quantity | number? | |
min_stock | number? | |
is_activepadrão True | boolean? | |
custom_fields | object? | |
Respostas
| 201 | Criado. |
| 422 | Falha de validação. Formato padrão do framework. |
Exemplo
curl -X POST 'https://atlas.skill-hub.app/api/v1/products' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"name": "Plano Pro", "type": "service", "price": 499.9, "unit": "mês"}'
GET/products/{product}escopo read
Obter produto
Parâmetros
| Nome | Tipo | Observação |
|---|
productpathobrigatório | integer | |
Respostas
| 200 | OK |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
Exemplo
curl -X GET 'https://atlas.skill-hub.app/api/v1/products/123' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
PUT/products/{product}escopo write
Atualizar produto
Parâmetros
| Nome | Tipo | Observação |
|---|
productpathobrigatório | integer | |
Corpo
| Campo | Tipo | Observação |
|---|
nameobrigatóriomáx 255 | string | |
skumáx 100 | string? | |
descriptionmáx 5000 | string? | |
short_descriptionmáx 500 | string? | |
typepadrão product | product | service | |
categorymáx 255 | string? | |
category_id | integer? | |
priceobrigatório | number | |
cost | number? | |
currencymáx 10 | string? | |
unitmáx 50 | string? | |
tax_rate | number? | |
track_stock | boolean? | |
stock_quantity | number? | |
min_stock | number? | |
is_activepadrão True | boolean? | |
custom_fields | object? | |
Respostas
| 200 | Atualizado. |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
| 422 | Falha de validação. Formato padrão do framework. |
Exemplo
curl -X PUT 'https://atlas.skill-hub.app/api/v1/products/123' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
DELETE/products/{product}escopo write
Remover produto
Parâmetros
| Nome | Tipo | Observação |
|---|
productpathobrigatório | integer | |
Respostas
| 200 | Removido. |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
Exemplo
curl -X DELETE 'https://atlas.skill-hub.app/api/v1/products/123' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
WhatsApp Connector
Canais oficiais e envio por template aprovado na Meta.
GET/wa-connector/channelsescopo read
Listar canais oficiais
Devolve apenas canais da API Oficial da Meta que estejam ativos. Sem paginação, com envelope próprio { data, total }.
Respostas
| 200 | OK |
| 401 | Token ausente, inválido ou expirado. |
| 403 | Quatro causas, distinguíveis pelo corpo:
- token sem o escopo exigido (code: insufficient_scope, com required_scope), ver a seção *Escopos do token*; - usuário sem conta vinculada; - licença sem API habilitada; - addon de acesso à API inativo. |
| 429 | Limite de 60 requisições por minuto estourado. |
Exemplo
curl -X GET 'https://atlas.skill-hub.app/api/v1/wa-connector/channels' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
GET/wa-connector/templatesescopo read
Listar templates aprovados
Somente templates aprovados pela Meta, ordenados por nome. Sem paginação, com envelope próprio { data, total }.
Parâmetros
| Nome | Tipo | Observação |
|---|
categoryquery | UTILITY | MARKETING | AUTHENTICATION | Convertido para maiúsculas automaticamente. |
languagequery | string | |
channel_idquery | integer | Filtra pelos templates da conta de WhatsApp Business daquele canal. |
Respostas
| 200 | OK |
| 401 | Token ausente, inválido ou expirado. |
| 403 | Quatro causas, distinguíveis pelo corpo:
- token sem o escopo exigido (code: insufficient_scope, com required_scope), ver a seção *Escopos do token*; - usuário sem conta vinculada; - licença sem API habilitada; - addon de acesso à API inativo. |
| 429 | Limite de 60 requisições por minuto estourado. |
Exemplo
curl -X GET 'https://atlas.skill-hub.app/api/v1/wa-connector/templates' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
POST/wa-connector/send-templateescopo send
Enviar template
Envia um template aprovado pela API Oficial. É o caminho para iniciar conversa fora da janela de 24 horas.
O telefone é reduzido a dígitos. O idioma padrão é pt_BR.
components segue o formato da Cloud API da Meta.
Registro no Atlas. Depois que a Meta aceita o envio, o Atlas registra a mensagem como um envio feito pela tela:
- Contato: procurado pelo telefone na conta (com e sem 55, com e sem o 9º dígito). Se não existir, é criado como lead, com o nome de contact_name (ou o próprio número). Contato existente sem nome (ou com o número no lugar do nome) recebe o contact_name; nome de verdade não é trocado. - Conversa: a deste número no mesmo canal é reaproveitada, pela mesma regra que a entrada da Meta usa. Por isso, quando o lead responde, a resposta cai nessa conversa. Se não existir, é criada; se estiver resolvida, é reaberta. Ela termina com status open. - Mensagem: gravada como mensagem de saída, com o texto do template já com as variáveis (ou [Template: nome] e as variáveis, quando o template não está sincronizado no Atlas), o message_id da Meta (os status entregue/lido atualizam por ele) e metadata.via = "api". A conversa aparece na hora no inbox. A IA não é acionada por essa mensagem.
Se a Meta recusar, nada é criado no Atlas e a resposta é 400, como antes.
Atenção: o serviço não verifica se o template existe na conta antes de enviar. Um nome errado só falha na resposta da Meta.
Corpo
| Campo | Tipo | Observação |
|---|
channel_idobrigatório | integer | |
toobrigatóriomáx 30 | string | |
template_nameobrigatóriomáx 255 | string | |
languagepadrão pt_BRmáx 10 | string | |
components | array<object> | Formato da Cloud API da Meta. |
contact_namemáx 255 | string | Opcional. Nome do contato ao criar, ou para completar um contato existente sem nome. |
Respostas
| 200 | Enviado. |
| 400 | A Meta recusou o envio. A mensagem devolvida é a da própria Meta. Nada é criado no Atlas. |
| 404 | Canal não encontrado ou inativo para esta conta. |
| 422 | Validação, canal desconectado, ou canal sem token de acesso e identificador de telefone configurados. |
Exemplo
curl -X POST 'https://atlas.skill-hub.app/api/v1/wa-connector/send-template' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"channel_id": 12, "to": "5511912345678", "template_name": "appointment_reminder", "contact_name": "Maria Souza", "language": "pt_BR", "components": [{"type": "body", "parameters": [{"type": "text", "text": "Maria"}, {"type": "text", "text": "Consulta"}, {"type": "text", "text": "20/09 às 14h"}, {"type": "text", "text": "Dra. Ana"}]}]}'
E-mail
Envio de e-mail pelas caixas do Atlas (pessoal, do time ou Geral).
GET/email-accountsescopo read
Listar caixas de e-mail
Caixas que o dono do token pode usar para enviar: a caixa pessoal dele, as caixas do time em que ele participa e a caixa Geral (E-mail SMTP das configurações) quando ele tem a permissão de configurações de e-mail. São as mesmas caixas da tela E-mail.
O campo account é a chave usada em POST /emails/send: o id numérico da caixa ou general. Sem paginação, com envelope { data }.
Respostas
| 200 | OK |
| 401 | Token ausente, inválido ou expirado. |
| 403 | Quatro causas, distinguíveis pelo corpo:
- token sem o escopo exigido (code: insufficient_scope, com required_scope), ver a seção *Escopos do token*; - usuário sem conta vinculada; - licença sem API habilitada; - addon de acesso à API inativo. |
| 429 | Limite de 60 requisições por minuto estourado. |
Exemplo
curl -X GET 'https://atlas.skill-hub.app/api/v1/email-accounts' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
{
"data": [
{
"account": "3",
"name": "Comercial",
"from_email": "[email protected]",
"from_name": "Comercial",
"provider": "imap_smtp",
"is_general": false,
"is_personal": true,
"is_active": true
},
{
"account": "general",
"name": "Geral",
"from_email": "[email protected]",
"from_name": "Sua Empresa",
"provider": "smtp",
"is_general": true,
"is_personal": false,
"is_active": false
}
]
}
POST/emails/sendescopo send
Enviar e-mail por uma caixa
Envia um e-mail por uma caixa do Atlas, do mesmo jeito que a tela Novo e-mail. Funciona com caixas IMAP/SMTP e Microsoft. A mensagem fica na pasta Enviados da caixa, com o usuário do token como remetente interno, e o resultado aparece em Configurações, Logs de Integração.
account é a chave devolvida por GET /email-accounts. Sem ela, usa a caixa pessoal do dono do token; se ele não tiver, a primeira acessível. Caixa inativa (teste de SMTP falhou ou desligada) responde 422.
Destinatários (to, cc, bcc) aceitam três formas: uma string com um e-mail, uma lista de strings, ou uma lista de objetos { email, name }. Endereço inválido é descartado; sem nenhum destinatário válido em to, 422.
Corpo: body_html (apelido body) ou body_text. Mandando só um, o outro é derivado. Anexos vão em base64, até 10 arquivos e 10 MB somados.
O envio é síncrono: a resposta só volta depois que o servidor da caixa aceitou a mensagem. Com anexo grande ou servidor lento isso pode levar alguns segundos.
Corpo
| Campo | Tipo | Observação |
|---|
accountmáx 20 | string | Id numérico da caixa ou general. Padrão: caixa pessoal do dono do token. |
toobrigatório | object | String, lista de strings ou lista de { email, name }. |
cc | object | Mesmo formato de to. |
bcc | object | Mesmo formato de to. Cópia oculta. |
subjectobrigatóriomáx 255 | string | |
body_htmlmáx 500000 | string | Corpo em HTML. Apelido: body. |
body_textmáx 200000 | string | Corpo em texto puro. Obrigatório quando não há body_html. |
reply_to | string (email) | Endereço de resposta (Reply-To). |
in_reply_to_id | integer | Id de um e-mail recebido no Atlas, para responder na mesma conversa. |
attachments | array<object> | Até 10 arquivos e 10 MB somados. |
Respostas
| 201 | Enviado. |
| 403 | Token sem o escopo send, ou caixa que o dono do token não pode usar (a caixa de outra pessoa responde 403 mesmo existindo). |
| 422 | Validação (sem destinatário válido, sem corpo, anexo inválido ou acima de 10 MB), caixa inativa ou nenhuma caixa disponível para o usuário. |
| 502 | O servidor da caixa (SMTP ou Microsoft) recusou ou não respondeu. A mensagem fica em Enviados com status failed e o detalhe em Logs de Integração. |
Exemplo
curl -X POST 'https://atlas.skill-hub.app/api/v1/emails/send' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"account": "3", "to": [{"email": "[email protected]", "name": "Cliente"}], "cc": "[email protected]", "subject": "Proposta comercial", "body_html": "<p>Olá! Segue a proposta em anexo.</p>", "attachments": [{"filename": "proposta.pdf", "content_base64": "JVBERi0xLjQK...", "mime": "application/pdf"}]}'
GET/emails/{id}escopo read
Consultar e-mail enviado
Status e destinatários de um e-mail enviado pela API ou pela tela (só mensagens de saída da conta).
Parâmetros
| Nome | Tipo | Observação |
|---|
idpathobrigatório | integer | |
Respostas
| 200 | OK |
| 404 | E-mail inexistente, de entrada, ou de outra conta. |
Exemplo
curl -X GET 'https://atlas.skill-hub.app/api/v1/emails/123' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
Webhooks
Notificações de saída para o seu sistema.
GET/webhooksescopo read
Listar webhooks
Sem paginação e sem filtros. O segredo não é exibido na listagem.
Respostas
| 200 | OK |
| 401 | Token ausente, inválido ou expirado. |
| 403 | Quatro causas, distinguíveis pelo corpo:
- token sem o escopo exigido (code: insufficient_scope, com required_scope), ver a seção *Escopos do token*; - usuário sem conta vinculada; - licença sem API habilitada; - addon de acesso à API inativo. |
| 429 | Limite de 60 requisições por minuto estourado. |
Exemplo
curl -X GET 'https://atlas.skill-hub.app/api/v1/webhooks' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
POST/webhooksescopo write
Criar webhook
O segredo é gerado pelo servidor e devolvido apenas nesta resposta e nas leituras individuais. Use * em events para receber todos.
Corpo
| Campo | Tipo | Observação |
|---|
urlobrigatóriomáx 500 | string (uri) | |
eventsobrigatório | array<*|contact.created|contact.updated|contact.deleted|conversation.created|conversation.updated|message.received|message.sent|invoice.created|invoice.updated|invoice.paid|invoice.overdue|invoice.cancelled|product.created|product.updated|product.deleted> | |
is_activepadrão True | boolean? | |
Respostas
| 201 | Criado. Guarde o secret. |
| 422 | Falha de validação. Formato padrão do framework. |
Exemplo
curl -X POST 'https://atlas.skill-hub.app/api/v1/webhooks' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{"url": "https://seusistema.com/hooks/atlas", "events": ["contact.created", "message.received"]}'
GET/webhooks/{webhook}escopo read
Obter webhook
Parâmetros
| Nome | Tipo | Observação |
|---|
webhookpathobrigatório | integer | |
Respostas
| 200 | OK. Inclui o segredo. |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
Exemplo
curl -X GET 'https://atlas.skill-hub.app/api/v1/webhooks/123' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
PUT/webhooks/{webhook}escopo write
Atualizar webhook
Parâmetros
| Nome | Tipo | Observação |
|---|
webhookpathobrigatório | integer | |
Corpo
| Campo | Tipo | Observação |
|---|
urlmáx 500 | string (uri) | |
events | array<*|contact.created|contact.updated|contact.deleted|conversation.created|conversation.updated|message.received|message.sent|invoice.created|invoice.updated|invoice.paid|invoice.overdue|invoice.cancelled|product.created|product.updated|product.deleted> | |
is_active | boolean? | |
Respostas
| 200 | Atualizado. |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
| 422 | Falha de validação. Formato padrão do framework. |
Exemplo
curl -X PUT 'https://atlas.skill-hub.app/api/v1/webhooks/123' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
DELETE/webhooks/{webhook}escopo write
Remover webhook
Parâmetros
| Nome | Tipo | Observação |
|---|
webhookpathobrigatório | integer | |
Respostas
| 200 | Removido. |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
Exemplo
curl -X DELETE 'https://atlas.skill-hub.app/api/v1/webhooks/123' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
POST/webhooks/{webhook}/testescopo send
Disparar teste
Envia o evento webhook.test para a URL cadastrada, com o corpo {"message":"This is a test webhook event.","timestamp":"..."}.
Parâmetros
| Nome | Tipo | Observação |
|---|
webhookpathobrigatório | integer | |
Respostas
| 200 | Teste despachado. |
| 404 | Recurso inexistente ou pertencente a outra conta. As duas situações respondem igual, por decisão de segurança. |
Exemplo
curl -X POST 'https://atlas.skill-hub.app/api/v1/webhooks/123/test' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Accept: application/json'
Eventos de webhook
Cada entrega é um POST na URL cadastrada, com o corpo
{"event":"...","timestamp":"...","data":{...}}.
Cabeçalhos enviados
Content-Type: application/json
User-Agent: Atlas/1.0
X-Webhook-Event: contact.created
X-Webhook-Id: 1
X-Webhook-Signature: <HMAC-SHA256 hex do corpo cru, com o seu secret>
Verifique a assinatura
Calcule o HMAC-SHA256 do corpo cru da requisição usando o
secret do webhook e compare com
X-Webhook-Signature. Use comparação em tempo constante.
Reentrega
Timeout de 15 segundos. Até 3 tentativas, com espera de 10, 30 e 60
segundos, apenas para erro 5xx ou falha de rede.
Um 4xx conta como falha e não é repetido. Após 50 falhas
consecutivas o webhook é desativado automaticamente.
Eventos disponíveis
| Evento |
Quando dispara | Campos em data |
contact.created | Qualquer criação de contato, pela API ou pela interface. | id, name, email, phone, mobile, type, person_type, document, source, tags[] |
contact.updated | Qualquer atualização de contato, sem filtro de campo. | igual ao anterior |
contact.deleted | Exclusão lógica de contato. | id, name |
conversation.created | Nova conversa. | id, remote_jid, display_name, status, contact_id, channel_id, assigned_user_id |
conversation.updated | Somente quando status, responsável, departamento ou contato mudam. | igual ao anterior |
message.received | Mensagem recebida. Exclui mensagens de sistema e ocultas. | id, conversation_id, contact_id, direction, type, content, media_url, status, remote_message_id, created_at |
message.sent | Mensagem enviada, inclusive por bot, campanha ou automação. | igual ao anterior |
Oito eventos nunca disparam hoje
invoice.created, invoice.updated,
invoice.paid, invoice.overdue,
invoice.cancelled, product.created,
product.updated e product.deleted são aceitos no
cadastro de um webhook, mas nenhum código os emite. Não construa integração
que dependa deles.
Objetos de resposta
Os campos que cada recurso devolve.
CustomFieldErrorBody
| Campo | Tipo | Observação |
|---|
message | string | |
errors | object | |
custom_field_errors | array<object> | |
unknown_keys | array<string> | |
CustomFieldDefinition
| Campo | Tipo | Observação |
|---|
entity_type | deal | contact | |
key | string | Fixa depois de criada; renomear o rótulo não muda a chave. |
label | string | |
field_type | text | textarea | number | decimal | date | datetime | select | multiselect | checkbox | radio | email | phone | url | file | image | color | rating | currency | |
options | array<object> | |
is_required | boolean | |
is_active | boolean | |
order | integer | |
DealDocument
| Campo | Tipo | Observação |
|---|
id | integer | |
name | string | |
size | integer | Bytes. |
mime_type | string? | |
url | string (uri) | Link assinado e temporário para baixar o arquivo, sem token. Vale 30 minutos; vencido ou alterado, responde 403. |
url_expires_at | string (date-time) | Quando o link de url deixa de valer. |
created_at | string (date-time) | |
ErrorScope
| Campo | Tipo | Observação |
|---|
errorobrigatório | string | Mensagem legível. |
codeobrigatório | insufficient_scope | |
required_scopeobrigatório | read | write | send | |
Pipeline
| Campo | Tipo | Observação |
|---|
id | integer | |
name | string | |
description | string? | |
is_default | boolean | |
is_active | boolean | |
sort_order | integer | |
stages | array<object> | Etapas do funil em ordem, inclusive as de ganho e de perda. |
PipelineStage
| Campo | Tipo | Observação |
|---|
id | integer | |
pipeline_id | integer | |
name | string | |
color | string? | |
probability | integer | Probabilidade de fechamento atribuída à etapa, de 0 a 100. |
rotting_days | integer? | Dias parado na etapa a partir dos quais o negócio é sinalizado como esfriando. |
is_won | boolean | Etapa de ganho. |
is_lost | boolean | Etapa de perda. |
sort_order | integer | |
DealRef
| Campo | Tipo | Observação |
|---|
id | integer | |
name | string | |
Deal
| Campo | Tipo | Observação |
|---|
id | integer | |
title | string | |
value | number (float) | |
currency | string | |
status | open | won | lost | |
probability | integer | Herdada da etapa, 0 a 100. |
pipeline | object | |
stage | object? | |
contact | object | |
assigned_to | object | |
conversation_id | integer? | Conversa vinculada ao negócio, quando houver. |
expected_close_date | string (date)? | |
stage_changed_at | string (date-time)? | Última entrada na etapa atual. |
closed_at | string (date)? | |
created_at | string (date-time) | |
updated_at | string (date-time) | |
custom_fields | object | Valores do módulo de Campos Personalizados, os mesmos da tela, com as chaves do módulo. Só campos ativos e preenchidos. Tipos como em CustomFieldsInput (data em AAAA-MM-DD, data e hora em ISO 8601, número como número, múltipla seleção como lista). |
DealDetailed
| Campo | Tipo | Observação |
|---|
id | integer | |
title | string | |
value | number (float) | |
currency | string | |
status | open | won | lost | |
probability | integer | Herdada da etapa, 0 a 100. |
pipeline | object | |
stage | object? | |
contact | object | |
assigned_to | object | |
conversation_id | integer? | Conversa vinculada ao negócio, quando houver. |
expected_close_date | string (date)? | |
stage_changed_at | string (date-time)? | Última entrada na etapa atual. |
closed_at | string (date)? | |
created_at | string (date-time) | |
updated_at | string (date-time) | |
custom_fields | object | Valores do módulo de Campos Personalizados, os mesmos da tela, com as chaves do módulo. Só campos ativos e preenchidos. Tipos como em CustomFieldsInput (data em AAAA-MM-DD, data e hora em ISO 8601, número como número, múltipla seleção como lista). |
notes | string? | |
legacy_custom_fields | object | Somente leitura. Chaves antigas que não existem no módulo (contas em modo compatível e dados de importação). Não aparecem na tela nem para a IA. |
source_id | integer? | |
campaign_id | integer? | |
loss_reason | object | |
loss_notes | string? | |
lost_at | string (date-time)? | |
DealEffects
| Campo | Tipo | Observação |
|---|
trigger_automations | boolean | |
fire_pixel_events | boolean | |
DealActivity
| Campo | Tipo | Observação |
|---|
id | integer | |
type | string | created, stage_change, status_change, note, call, email, whatsapp, meeting… |
title | string? | |
description | string? | |
user | object | |
metadata | object? | Em movimentações: old_stage_id, new_stage_id, actor_label, via, trigger_automations, fire_pixel_events. |
activity_at | string (date-time)? | |
created_at | string (date-time) | |
EmailAccount
| Campo | Tipo | Observação |
|---|
account | string | Chave para POST /emails/send: id numérico da caixa ou general. |
name | string | |
from_email | string? | |
from_name | string? | |
provider | imap_smtp | microsoft | smtp | smtp é a caixa Geral das configurações.
|
is_general | boolean | |
is_personal | boolean | Caixa pessoal do dono do token. |
is_active | boolean | Só caixa ativa envia. |
EmailRecipient
| Campo | Tipo | Observação |
|---|
emailobrigatório | string (email) | |
name | string? | |
EmailAttachment
| Campo | Tipo | Observação |
|---|
filenameobrigatóriomáx 255 | string | |
content_base64obrigatório | string | Conteúdo do arquivo em base64. |
mimepadrão application/octet-streammáx 100 | string | |
EmailSent
| Campo | Tipo | Observação |
|---|
id | integer | |
account | string | |
message_id | string | Message-ID do cabeçalho. |
status | sent | failed | draft | |
from_email | string? | |
from_name | string? | |
to | array<object> | |
cc | array<object> | |
bcc | array<object> | |
subject | string | |
in_reply_to | string? | Message-ID do e-mail respondido. |
sent_at | string (date-time)? | |
sent_by_user_id | integer? | Usuário do token que enviou. |
Contact
| Campo | Tipo | Observação |
|---|
id | integer | |
name | string | |
trading_name | string? | |
display_name | string | Calculado a partir do nome e do nome fantasia. |
person_type | individual | company | |
type | lead | customer | prospect | supplier | |
email | string? | |
phone | string? | |
mobile | string? | |
document | string? | |
source | string? | Texto livre. É um rótulo de origem, não um canal detectado automaticamente. |
tags | array<string> | |
is_active | boolean | |
group | object? | |
assigned_to | object? | |
deals_count | integer | Preenchido na listagem. Na leitura individual vem zero. |
contracts_count | integer | Preenchido na listagem. Na leitura individual vem zero. |
created_at | string (date-time) | |
updated_at | string (date-time) | |
custom_fields | object | Valores do módulo de Campos Personalizados, os mesmos da tela, com as chaves do módulo. Só campos ativos e preenchidos. Tipos como em CustomFieldsInput (data em AAAA-MM-DD, data e hora em ISO 8601, número como número, múltipla seleção como lista). |
ContactDetailed
| Campo | Tipo | Observação |
|---|
id | integer | |
name | string | |
trading_name | string? | |
display_name | string | Calculado a partir do nome e do nome fantasia. |
person_type | individual | company | |
type | lead | customer | prospect | supplier | |
email | string? | |
phone | string? | |
mobile | string? | |
document | string? | |
source | string? | Texto livre. É um rótulo de origem, não um canal detectado automaticamente. |
tags | array<string> | |
is_active | boolean | |
group | object? | |
assigned_to | object? | |
deals_count | integer | Preenchido na listagem. Na leitura individual vem zero. |
contracts_count | integer | Preenchido na listagem. Na leitura individual vem zero. |
created_at | string (date-time) | |
updated_at | string (date-time) | |
custom_fields | object | Valores do módulo de Campos Personalizados, os mesmos da tela, com as chaves do módulo. Só campos ativos e preenchidos. Tipos como em CustomFieldsInput (data em AAAA-MM-DD, data e hora em ISO 8601, número como número, múltipla seleção como lista). |
website | string? | |
company | string? | |
position | string? | |
state_registration | string? | |
municipal_registration | string? | |
address | string? | |
address_number | string? | |
address_complement | string? | |
neighborhood | string? | |
city | string? | |
state | string? | |
zip_code | string? | |
country | string? | |
birth_date | string (date)? | |
notes | string? | |
legacy_custom_fields | object | Somente leitura. Chaves antigas que não existem no módulo (contas em modo compatível e dados de importação). Não aparecem na tela nem para a IA. |
notification_settings | object | |
parent_id | integer? | |
bot_protected | boolean | |
last_contact_at | string (date-time)? | |
employees | array<object> | Pessoas vinculadas a este contato. Só é carregado na leitura individual. |
DealSummary
| Campo | Tipo | Observação |
|---|
id | integer | |
title | string | |
value | number | |
currency | string | |
status | string | |
stage | object? | |
assigned_to | object? | |
expected_close_date | string (date)? | |
won_at | string (date-time)? | |
lost_at | string (date-time)? | |
created_at | string (date-time) | |
Conversation
| Campo | Tipo | Observação |
|---|
id | integer | |
remote_jid | string | Identificador no WhatsApp, no formato [email protected]. |
display_name | string? | |
avatar_url | string? | |
status | open | pending | resolved | |
is_group | boolean | |
unread_count | integer | |
last_message_preview | string? | |
last_message_at | string (date-time)? | |
channel | object? | |
contact | object? | |
assigned_to | object? | |
assigned_department | object? | |
created_at | string (date-time) | |
updated_at | string (date-time) | |
Message
| Campo | Tipo | Observação |
|---|
id | integer | |
conversation_id | integer | |
direction | incoming | outgoing | |
type | text | image | document | video | audio | |
content | string? | |
media_url | string? | |
media_mimetype | string? | |
filename | string? | Sempre responde null. O campo é montado a partir de um atributo que não existe na tabela. Use media_url para identificar o arquivo. |
status | string | |
remote_message_id | string? | |
sender_user | object? | |
metadata | object | Mensagens enviadas por esta API trazem via = "api". |
created_at | string (date-time) | |
MessageSend
| Campo | Tipo | Observação |
|---|
contentmáx 10000 | string? | |
type | text | image | document | video | audio | |
media_url | string (uri)? | |
filenamemáx 255 | string? | |
MessageSendByPhone
| Campo | Tipo | Observação |
|---|
contentmáx 10000 | string? | |
type | text | image | document | video | audio | |
media_url | string (uri)? | |
filenamemáx 255 | string? | |
phonemáx 50 | string | Obrigatório quando não há conversation_id. |
conversation_id | integer? | |
channel_id | integer | Obrigatório quando não há conversation_id. |
Invoice
| Campo | Tipo | Observação |
|---|
id | integer | |
number | string | |
title | string? | |
status | draft | pending | sent | paid | cancelled | |
issue_date | string (date) | |
due_date | string (date) | |
subtotal | number | |
discount_amount | number | |
discount_type | fixed | percent | |
tax_total | number | |
total | number | |
amount_paid | number | |
amount_due | number | |
currency | string | |
is_recurring | boolean | |
contact | object? | |
created_by | object? | |
created_at | string (date-time) | |
updated_at | string (date-time) | |
InvoiceDetailed
| Campo | Tipo | Observação |
|---|
id | integer | |
number | string | |
title | string? | |
status | draft | pending | sent | paid | cancelled | |
issue_date | string (date) | |
due_date | string (date) | |
subtotal | number | |
discount_amount | number | |
discount_type | fixed | percent | |
tax_total | number | |
total | number | |
amount_paid | number | |
amount_due | number | |
currency | string | |
is_recurring | boolean | |
contact | object? | |
created_by | object? | |
created_at | string (date-time) | |
updated_at | string (date-time) | |
description | string? | |
notes | string? | |
terms | string? | |
public_url | string | Link público da fatura, para envio ao cliente. |
sent_at | string (date-time)? | |
paid_at | string (date-time)? | |
viewed_at | string (date-time)? | |
items | array<object> | |
payments | array<object> | Preenchido na leitura individual. Na criação e na atualização vem vazio. |
InvoiceItem
| Campo | Tipo | Observação |
|---|
id | integer | |
name | string | |
description | string? | |
quantity | number | |
unit | string? | |
unit_price | number | |
discount_amount | number | |
discount_type | fixed | percent | |
tax_rate | number | |
tax_amount | number | |
total | number | |
product_id | integer? | |
PaymentSummary
| Campo | Tipo | Observação |
|---|
id | integer | |
amount | number | |
method | string | |
status | string | |
paid_at | string (date-time)? | |
Payment
| Campo | Tipo | Observação |
|---|
id | integer | |
amount | number | |
method | string | |
status | string | |
paid_at | string (date-time)? | |
fee | number | |
net_amount | number | |
gateway | string? | |
transaction_id | string? | |
notes | string? | |
created_at | string (date-time) | |
Proposal
| Campo | Tipo | Observação |
|---|
id | integer | |
number | string | |
title | string? | |
subject | string? | |
status | draft | sent | accepted | rejected | expired | |
proposal_date | string (date) | |
valid_until | string (date)? | |
subtotal | number | |
discount_amount | number | |
discount_type | fixed | percentage | |
tax_amount | number | |
total | number | |
currency | string | |
contact | object? | |
assigned_to | object? | |
created_by | object? | |
created_at | string (date-time) | |
updated_at | string (date-time) | |
ProposalDetailed
| Campo | Tipo | Observação |
|---|
id | integer | |
number | string | |
title | string? | |
subject | string? | |
status | draft | sent | accepted | rejected | expired | |
proposal_date | string (date) | |
valid_until | string (date)? | |
subtotal | number | |
discount_amount | number | |
discount_type | fixed | percentage | |
tax_amount | number | |
total | number | |
currency | string | |
contact | object? | |
assigned_to | object? | |
created_by | object? | |
created_at | string (date-time) | |
updated_at | string (date-time) | |
deal | object? | |
content | string? | |
notes | string? | |
terms | string? | |
public_url | string | Link público da proposta, para envio e assinatura. |
sent_at | string (date-time)? | |
viewed_at | string (date-time)? | |
accepted_at | string (date-time)? | |
rejected_at | string (date-time)? | |
signed_at | string (date-time)? | |
signer_name | string? | |
items | array<object> | |
ProposalItem
| Campo | Tipo | Observação |
|---|
id | integer | |
name | string | |
description | string? | |
quantity | number | |
unit | string? | |
unit_price | number | |
discount_amount | number | |
discount_type | fixed | percentage | |
tax_rate | number | |
tax_amount | number | |
total | number | |
is_optional | boolean | |
product_id | integer? | |
Appointment
| Campo | Tipo | Observação |
|---|
id | integer | |
title | string | |
type | meeting | call | task | event | other | |
status | scheduled | confirmed | cancelled | completed | |
start_at | string (date-time) | |
end_at | string (date-time)? | |
all_day | boolean | |
location | string? | |
meeting_type | in_person | online | |
color | string? | |
user | object? | |
contact | object? | |
deal | object? | |
created_at | string (date-time) | |
updated_at | string (date-time) | |
AppointmentDetailed
| Campo | Tipo | Observação |
|---|
id | integer | |
title | string | |
type | meeting | call | task | event | other | |
status | scheduled | confirmed | cancelled | completed | |
start_at | string (date-time) | |
end_at | string (date-time)? | |
all_day | boolean | |
location | string? | |
meeting_type | in_person | online | |
color | string? | |
user | object? | |
contact | object? | |
deal | object? | |
created_at | string (date-time) | |
updated_at | string (date-time) | |
description | string? | |
notes | string? | |
google_meet_link | string? | |
google_event_id | string? | |
Product
| Campo | Tipo | Observação |
|---|
id | integer | |
name | string | |
sku | string? | |
type | product | service | |
price | number | |
cost | number | |
tax_rate | number | |
stock_quantity | number | |
currency | string | |
unit | string? | |
is_active | boolean | |
track_stock | boolean | |
has_variations | boolean | |
category | object? | |
image | string? | Caminho relativo do arquivo, não uma URL completa. |
created_at | string (date-time) | |
updated_at | string (date-time) | |
ProductDetailed
| Campo | Tipo | Observação |
|---|
id | integer | |
name | string | |
sku | string? | |
type | product | service | |
price | number | |
cost | number | |
tax_rate | number | |
stock_quantity | number | |
currency | string | |
unit | string? | |
is_active | boolean | |
track_stock | boolean | |
has_variations | boolean | |
category | object? | |
image | string? | Caminho relativo do arquivo, não uma URL completa. |
created_at | string (date-time) | |
updated_at | string (date-time) | |
description | string? | |
short_description | string? | |
min_stock | number | |
custom_fields | object | |
margin | number | Margem calculada a partir de preço e custo. |
variations | array<object> | Somente na leitura individual. Não há endpoint para criar ou editar variações. |
WaChannel
| Campo | Tipo | Observação |
|---|
id | integer | |
name | string | |
phone_number | string | |
profile_name | string? | |
profile_picture | string? | |
status | string | |
is_connected | boolean | |
is_primary | boolean | |
is_default | boolean | |
waba_id | string? | Identificador da conta de WhatsApp Business na Meta. |
connected_at | string (date-time)? | Em UTC, com sufixo Z. |
WaTemplate
| Campo | Tipo | Observação |
|---|
id | integer | |
name | string | |
language | string | |
category | UTILITY | MARKETING | AUTHENTICATION | |
category_label | string | |
status | string | |
header_type | string | |
body_text | string | Corpo do template, com as variáveis no formato {{1}}, {{2}} e assim por diante. |
footer_text | string? | |
buttons | array<object> | |
dynamic_url_buttons | array<object> | |
has_dynamic_url_buttons | boolean | |
variables | array<string> | Nomes das variáveis, por exemplo ["1","2"]. |
variables_count | integer | |
waba_id | string? | |
last_synced_at | string (date-time)? | Em UTC, com sufixo Z. |
Webhook
| Campo | Tipo | Observação |
|---|
id | integer | |
url | string (uri) | |
events | array<*|contact.created|contact.updated|contact.deleted|conversation.created|conversation.updated|message.received|message.sent|invoice.created|invoice.updated|invoice.paid|invoice.overdue|invoice.cancelled|product.created|product.updated|product.deleted> | |
is_active | boolean | |
failure_count | integer | Falhas consecutivas. Em 50, o webhook é desativado automaticamente. |
last_triggered_at | string (date-time)? | |
created_at | string (date-time) | |
WebhookWithSecret
| Campo | Tipo | Observação |
|---|
id | integer | |
url | string (uri) | |
events | array<*|contact.created|contact.updated|contact.deleted|conversation.created|conversation.updated|message.received|message.sent|invoice.created|invoice.updated|invoice.paid|invoice.overdue|invoice.cancelled|product.created|product.updated|product.deleted> | |
is_active | boolean | |
failure_count | integer | Falhas consecutivas. Em 50, o webhook é desativado automaticamente. |
last_triggered_at | string (date-time)? | |
created_at | string (date-time) | |
secret | string | 64 caracteres. Usado para calcular a assinatura HMAC-SHA256 de cada entrega. Não aparece na listagem. |
Armadilhas conhecidas
Comportamentos que existem hoje e surpreendem quem integra.
Estão aqui porque são reais, não porque sejam desejáveis.
Accept: application/json é obrigatório
Sem ele, um erro de autenticação responde 302 em HTML em vez de 401 em JSON. É a causa mais comum de integração que "não autentica".
Recurso de outra conta responde 404
Nunca 403. Um 404 não significa que o registro não existe, significa que ele não é seu.
discount_type muda de nome entre recursos
Faturas usam percent. Propostas usam percentage.
A ordenação padrão não é a mesma em todo lugar
desc em contatos, conversas, faturas e propostas. asc em agendamentos e produtos.
filename de mensagem sempre responde null
Use media_url para identificar o arquivo.
deals_count e contracts_count só vêm na listagem
Na leitura individual de um contato eles respondem zero.
O filtro source é sensível a maiúsculas
E a base contém grafias diferentes para a mesma origem. Para precisão, liste e filtre do seu lado.
Atualizar fatura ou proposta não mexe nos itens
PUT ignora itens, e no caso da fatura também não recalcula os totais.
Atualizar agendamento não valida a ordem das datas
A verificação de que end_at vem depois de start_at só existe na criação.
Atribuir usuário de outra conta a uma conversa falha em silêncio
O valor é ignorado e a resposta ainda é 200. Confira o retorno.
Referências no corpo não são verificadas contra a sua conta
contact_id, deal_id, product_id e category_id são aceitos sem essa checagem.
Enviar mensagem muda o estado da conversa
Ela é atribuída ao usuário do token, se não tiver responsável, e o status passa para open.
send-template não verifica o template antes de enviar
Um nome errado só falha na resposta da Meta.
Oito eventos de webhook nunca disparam
Os cinco de fatura e os três de produto são aceitos no cadastro mas não têm código que os emita. Não construa integração sobre eles.
Downloads
A especificação completa, para importar em ferramentas ou colar dentro de um
modelo de linguagem.