Carregando...
Documentação para desenvolvedores

Zapini Integrations API

Construa sua própria integração consumindo os recursos da Zapini — quadros Kanban, agendamentos, conversas do chat e tickets de suporte — por meio de uma API REST simples e previsível.

Crie e gerencie suas chaves de API no painel em Integrações → "Integrações Customizadas".

Abrir Integrações Customizadas
URL base https://zapini.app/api/v1

Autenticação

Toda requisição é autenticada com uma chave de integração. As chaves têm 51 caracteres, começam com o prefixo zpk_ e são geradas no painel em Integrações → "Integrações Customizadas".

Sua chave é exibida uma única vez, no momento da criação. A Zapini armazena apenas um hash SHA-256 dela, então não é possível recuperá-la depois — se você a perder, revogue a chave e crie uma nova.

Envie a chave em toda requisição como Bearer token no cabeçalho Authorization. Todas as requisições e respostas usam JSON: defina Content-Type: application/json ao enviar um corpo e Accept: application/json sempre.

Exemplo de requisição

curl https://zapini.app/api/v1/kanban/boards \
  -H "Authorization: Bearer zpk_your_51_char_key_here" \
  -H "Accept: application/json"

Escopos

Cada chave carrega uma lista explícita de escopos escolhida na criação. Um escopo dá acesso a um recurso, dividido em uma metade de leitura e uma de escrita.

Escopo O que concede
kanban.read Ler quadros, colunas, leads e atividades de leads do Kanban.
kanban.write Criar, atualizar, mover e excluir quadros, colunas e leads do Kanban.
calendar.read Ler agendamentos da agenda.
calendar.write Criar, atualizar, confirmar, concluir, cancelar e excluir agendamentos.
chat.read Ler conversas e histórico de mensagens.
chat.write Enviar mensagens e mídias, arquivar conversas, gerenciar etiquetas e automação.
tickets.read Ler tickets de suporte.
tickets.write Criar e atualizar tickets de suporte.
database.read Ler coleções e registros do banco interno (Base Inteligente).
database.write Criar, atualizar e excluir registros do banco interno.
tms.read Ler o módulo de transporte: frota, fretes, monitoramento, ocorrências, CAP/CAR e listas de valores.
tms.write Criar, alterar e remover registros do transporte.

Requisições GET e HEAD exigem o escopo .read do recurso; requisições POST, PUT e DELETE exigem o escopo .write correspondente.

Negação por padrão: qualquer endpoint fora desses quatro recursos é rejeitado com HTTP 403 e código de erro ENDPOINT_NOT_IN_SCOPE, independentemente dos escopos da chave.

Segurança e limites

As chaves de integração customizada foram projetadas para serem entregues a sistemas de terceiros com segurança. Os controles abaixo valem para todas as chaves:

Limite de requisições

Cada chave pode fazer até 300 requisições por minuto. Acima disso a API responde HTTP 429 com o campo retry_after (em segundos) — aguarde e tente novamente.

Lista de IPs permitidos (opcional)

Restrinja uma chave a uma lista de endereços IP exatos ou faixas CIDR IPv4. Requisições de qualquer outro endereço são rejeitadas com 403 IP_NOT_ALLOWED.

Vínculo com instância (opcional)

Uma chave pode ser vinculada a uma única instância de WhatsApp. Chaves vinculadas só enxergam os dados daquela instância e nunca precisam do parâmetro instance_uuid.

Revogar e trocar

As chaves podem ser revogadas ou trocadas a qualquer momento no painel. A revogação é imediata — requisições feitas com uma chave revogada recebem 401.

Somente HTTPS

A API é servida exclusivamente por HTTPS. Requisições em HTTP puro não são aceitas.

Erros

Os erros usam códigos de status HTTP convencionais mais um código de erro legível por máquina no corpo JSON.

Status Código de erro Descrição
401 INVALID_INTEGRATION_KEY A chave está ausente, malformada, revogada ou é desconhecida.
403 INSUFFICIENT_SCOPE A chave não possui o escopo exigido por este endpoint. O payload inclui required_scope e granted_scopes para ajudar no diagnóstico.
403 ENDPOINT_NOT_IN_SCOPE O endpoint está fora dos recursos cobertos pela API de Integrações (negação por padrão).
403 IP_NOT_ALLOWED A requisição veio de um endereço IP fora da lista de permitidos da chave.
429 RATE_LIMITED Requisições demais. Aguarde retry_after segundos antes de tentar novamente.
422 — Falha de validação. Formato padrão do Laravel: uma mensagem mais um objeto errors indexado pelo nome do campo.
404 DATABASE_NOT_CONFIGURED O tenant não tem uma Base Inteligente configurada, ou a chave não está vinculada a uma.
404 COLLECTION_NOT_FOUND A coleção não existe ou está fora da lista liberada para esta chave.
404 RECORD_NOT_FOUND O registro não existe nessa coleção.
403 TMS_NOT_ENABLED O módulo TMS não está habilitado para este cliente (crm_layout não é "tms").
422 DIRECTION_REQUIRED Listar lançamentos exige direction=payable (CAP) ou direction=receivable (CAR).

Exemplo de resposta — 403 INSUFFICIENT_SCOPE

{
  "success": false,
  "error": "INSUFFICIENT_SCOPE",
  "required_scope": "kanban.write",
  "granted_scopes": ["kanban.read", "chat.read"]
}

Kanban

Escopos necessários: kanban.read kanban.write

Gerencie quadros de vendas, colunas e leads — tudo o que você vê no módulo Kanban do painel.

Os quadros são separados por instância de WhatsApp. Envie o parâmetro instance_uuid (query/body) nas chamadas de quadro — a menos que sua chave esteja vinculada a uma instância, caso em que ele é implícito.

O prefixo canônico é /crm. O antigo /kanban continua respondendo exatamente as mesmas rotas, com o mesmo formato — nenhuma integração publicada precisa mudar.

Método Endpoint Descrição
Quadros
GET /crm/boards Listar os quadros da instância.
POST /crm/boards Criar um quadro.
GET /crm/boards/{uuid} Obter um quadro com suas colunas.
PUT /crm/boards/{uuid} Atualizar um quadro (nome, cor...).
DELETE /crm/boards/{uuid} Excluir um quadro.
GET /crm/boards/{uuid}/stats Totais do quadro: abertos, ganhos, perdidos, valores e distribuição por coluna.
POST /crm/boards/{uuid}/duplicate Duplicar o quadro com suas colunas (sem os leads).
Colunas
GET /crm/boards/{uuid}/columns Listar as colunas do quadro.
POST /crm/boards/{uuid}/columns Adicionar uma coluna ao quadro.
POST /crm/boards/{uuid}/columns/reorder Reordenar as colunas do quadro.
PUT /crm/columns/{uuid} Atualizar uma coluna.
DELETE /crm/columns/{uuid} Excluir uma coluna.
POST /crm/columns/{uuid}/clear Excluir todos os leads da coluna.
Leads
GET /crm/leads Buscar leads em todo o CRM (por telefone, texto, etiqueta de status, responsável ou período). Sempre paginado.
GET /crm/boards/{uuid}/leads Listar os leads de um quadro.
POST /crm/leads Criar um lead em uma coluna.
GET /crm/leads/{uuid} Obter um lead.
PUT /crm/leads/{uuid} Atualizar um lead.
DELETE /crm/leads/{uuid} Excluir um lead.
POST /crm/leads/{uuid}/move Mover um lead para outra coluna/posição.
POST /crm/leads/{uuid}/won Marcar um lead como ganho.
POST /crm/leads/{uuid}/lost Marcar um lead como perdido.
POST /crm/leads/{uuid}/note Adicionar uma nota à linha do tempo do lead.
GET /crm/leads/{uuid}/activities Listar o histórico de atividades do lead.
POST /crm/leads/{uuid}/assign Definir os responsáveis do lead.
POST /crm/leads/{uuid}/ignore Descartar o lead e vetar o número na detecção automática.
POST /crm/leads/{uuid}/convert-to-ticket Abrir um ticket a partir do lead (idempotente).
POST /crm/boards/{uuid}/leads/import Importar até 500 leads numa chamada, com relatório por linha.
POST /crm/leads/from-conversation Criar um lead a partir de uma conversa do chat.
POST /crm/leads/from-messages Criar um lead a partir de mensagens específicas.
GET /crm/conversations/{uuid}/lead Obter o lead vinculado a uma conversa.
Anexos do lead
GET /crm/leads/{uuid}/attachments Listar os anexos do lead.
POST /crm/leads/{uuid}/attachments Enviar um anexo para o lead (até 25 MB, 10 por lead).
GET /crm/leads/{uuid}/attachments/{attachmentUuid} Baixar um anexo do lead.
DELETE /crm/leads/{uuid}/attachments/{attachmentUuid} Excluir um anexo do lead.
IA sobre o lead
POST /crm/leads/{uuid}/ai-qualify Pontuar o lead com IA e roteá-lo pela pontuação.
POST /crm/leads/{uuid}/ai-suggest Sugerir a próxima ação para o lead com IA.
Automações
GET /crm/boards/{uuid}/automations Listar as automações do quadro.
POST /crm/boards/{uuid}/automations Criar uma automação (gatilho + ação).
PUT /crm/automations/{uuid} Atualizar uma automação.
DELETE /crm/automations/{uuid} Excluir uma automação.
POST /crm/automations/{uuid}/test Executar a automação contra um lead real, para conferir a configuração.
Detecção automática
GET /crm/boards/{uuid}/auto-detection Ler as regras de detecção automática de leads do quadro.
PUT /crm/boards/{uuid}/auto-detection Salvar as regras de detecção automática do quadro.
POST /crm/boards/{uuid}/auto-detection/preview Prever o que seria importado, sem criar nada.
POST /crm/boards/{uuid}/auto-detection/sync Criar os leads dos itens escolhidos na prévia.
GET /crm/boards/{uuid}/ignored-contacts Listar os contatos ignorados pelo quadro.
POST /crm/boards/{uuid}/ignored-contacts Devolver um contato ignorado à detecção.
Campos customizados
GET /crm/field-definitions Esquema dos campos customizados para montar o formulário.
GET /crm/boards/{uuid}/fields Gerenciar campos: inclui campo desligado e quantos cadastros já têm valor em cada um.
POST /crm/boards/{uuid}/fields Criar um campo customizado no quadro.
POST /crm/boards/{uuid}/fields/reorder Reordenar os campos do quadro.
PUT /crm/fields/{id} Atualizar um campo customizado (o nome interno não muda).
DELETE /crm/fields/{id} Remover um campo do formulário (os valores já gravados são mantidos).
Configuração e apoio
GET /crm/config Configuração do CRM do tenant (layout standard, TMS ou VC).
GET /crm/users Usuários que podem ser responsáveis por um lead.
GET /crm/tags Etiquetas do tenant, usadas nos filtros de detecção.

Exemplo de requisição

curl -X POST https://zapini.app/api/v1/kanban/leads \
  -H "Authorization: Bearer zpk_your_51_char_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "instance_uuid": "550e8400-e29b-41d4-a716-446655440000",
    "column_uuid": "c2b7e9d4-1f3a-4a5b-9c8d-7e6f5a4b3c2d",
    "name": "Jane Doe",
    "phone": "+5511999999999",
    "value": 1500
  }'

Agenda

Escopos necessários: calendar.read calendar.write

Crie e gerencie os agendamentos exibidos na agenda do painel, incluindo transições de status.

Método Endpoint Descrição
GET /calendar/appointments Listar agendamentos (filtro por período/status).
POST /calendar/appointments Criar um agendamento.
GET /calendar/appointments/{uuid} Obter um agendamento.
PUT /calendar/appointments/{uuid} Atualizar um agendamento.
DELETE /calendar/appointments/{uuid} Excluir um agendamento.
POST /calendar/appointments/{uuid}/confirm Marcar o agendamento como confirmado.
POST /calendar/appointments/{uuid}/complete Marcar o agendamento como concluído.
POST /calendar/appointments/{uuid}/cancel Cancelar o agendamento.
POST /calendar/appointments/{uuid}/to-kanban Criar um lead no Kanban a partir do agendamento.

Exemplo de requisição

curl -X POST https://zapini.app/api/v1/calendar/appointments \
  -H "Authorization: Bearer zpk_your_51_char_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Demo call",
    "start_at": "2026-07-10 14:00",
    "end_at": "2026-07-10 14:30",
    "contact_name": "Jane Doe",
    "contact_number": "+5511999999999"
  }'

Chat

Escopos necessários: chat.read chat.write

Leia conversas e mensagens e envie texto ou mídia pela sua instância de WhatsApp conectada.

Método Endpoint Descrição
GET /chat/conversations Listar as conversas do chat.
GET /chat/conversations/{id} Obter uma conversa.
GET /chat/conversations/{id}/messages Listar as mensagens de uma conversa.
POST /chat/send Enviar mensagem de texto (corpo: conversation ou recipient, mais message).
POST /chat/send-media Enviar mensagem de mídia (imagem, áudio, vídeo, documento).
POST /messages/send Enfileirar uma mensagem de saída (API de mensagens).
GET /messages Listar mensagens (com filtros).
GET /conversations Listar conversas (recurso conversations).
POST /conversations/{id}/archive Arquivar/desarquivar uma conversa.
POST /conversations/{id}/tags Gerenciar as etiquetas de uma conversa.
POST /conversations/{id}/automation/pause Pausar a automação de IA na conversa.
POST /conversations/{id}/automation/resume Retomar a automação de IA na conversa.

Exemplo de requisição

curl -X POST https://zapini.app/api/v1/chat/send \
  -H "Authorization: Bearer zpk_your_51_char_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "recipient": "+5511999999999",
    "message": "Hello from my integration!"
  }'

Tickets

Escopos necessários: tickets.read tickets.write

Abra e acompanhe tickets de suporte de forma programática.

Método Endpoint Descrição
GET /tickets Listar tickets. Filtros: status (open, in_progress, waiting, resolved, closed), priority (low, medium, high, urgent), category, search, per_page.
POST /tickets Criar um ticket. subject é obrigatório; opcionais: description, priority, category, contact_name, contact_number, tags[], due_at.
GET /tickets/{uuid} Obter um ticket pelo UUID.
PUT /tickets/{uuid} Atualizar campos e/ou transicionar o status.

Exemplo de requisição

curl -X POST https://zapini.app/api/v1/tickets \
  -H "Authorization: Bearer zpk_your_51_char_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "subject": "Customer cannot log in",
    "description": "Password reset e-mail never arrives.",
    "priority": "low",
    "contact_name": "Jane Doe",
    "contact_number": "+5511999999999",
    "tags": ["login", "email"]
  }'

Exemplo de resposta — 201

{
  "success": true,
  "data": {
    "uuid": "9d3f2c1a-7b6e-4d5c-8a9b-0c1d2e3f4a5b",
    "code": "TK-8F3K2M1Q",
    "subject": "Customer cannot log in",
    "status": "open",
    "priority": "low",
    "category": null,
    "contact_name": "Jane Doe",
    "contact_number": "+5511999999999",
    "tags": ["login", "email"],
    "due_at": null,
    "created_at": "2026-07-02T12:00:00Z"
  }
}

Banco de Dados (Base Inteligente)

Escopos necessários: database.read database.write

A Base Inteligente é o banco de dados interno do tenant — imóveis, cardápio, produtos, serviços, profissionais, o que o segmento pedir. Esta API a transforma em um CMS headless: o seu site lê e grava exatamente os mesmos registros que o cliente administra no painel da Zapini ou no portal público. Nada é duplicado, não há sincronização para manter.

A chave é resolvida para UMA Base Inteligente do tenant e, opcionalmente, para uma lista de coleções liberadas. Uma coleção fora dessa lista responde 404 — igual a uma que não existe.

Método Endpoint Descrição
GET /database Informações do banco: segmento (categoria) e coleções que a chave enxerga.
GET /database/collections Somente a lista de coleções, com nome de exibição e total de registros.
GET /database/collections/{collection} Esquema de campos da coleção: tipo, obrigatoriedade, opções de enum e referências. Use para montar formulários dinâmicos.
GET /database/collections/{collection}/records Listar registros com busca, filtros, ordenação, projeção e paginação.
POST /database/collections/{collection}/records Criar um registro. O corpo é filtrado pelo esquema — campos desconhecidos são ignorados.
GET /database/collections/{collection}/records/{id} Obter um registro pelo id.
PUT /database/collections/{collection}/records/{id} Atualizar um registro (PUT ou PATCH). Envie apenas os campos que mudam.
DELETE /database/collections/{collection}/records/{id} Excluir um registro.
POST /database/uploads Enviar um arquivo (multipart, campo file) para a galeria do tenant e receber a URL pública para gravar em um campo do tipo image.

Consultando registros

A listagem aceita os parâmetros abaixo. Nomes de campo são validados contra o esquema da coleção e operadores vêm de uma lista fixa — a query string nunca chega crua ao banco.

Parâmetro Descrição
page Página da listagem (padrão 1).
per_page Registros por página (padrão 25, máximo 100).
search Busca textual nos campos de texto, e-mail, telefone, documento, URL e enum da coleção.
sort / order Campo de ordenação (do esquema, ou created_at / updated_at) e direção asc | desc. Padrão: mais recentes primeiro.
fields Lista separada por vírgula dos campos a retornar. O id sempre volta.
filter[campo] Igualdade: filter[ativo]=true, filter[cidade]=Niterói.
filter[campo][op] Com operador: filter[preco][gte]=500000, filter[tipo][in]=casa,apartamento.
Operadores aceitos: eq ne gt gte lt lte in nin like starts ends exists

Exemplo de requisição

# Imóveis ativos até R$ 800 mil, do mais barato ao mais caro
curl "https://zapini.app/api/v1/database/collections/imoveis/records?per_page=12&sort=preco&order=asc&filter[ativo]=true&filter[preco][lte]=800000" \
  -H "Authorization: Bearer zpk_your_51_char_key_here"

Exemplo de resposta — 200

{
  "success": true,
  "data": [
    {
      "id": "66b3f1c2a4d5e6f708192a3b",
      "titulo": "Apartamento 3 quartos — Icaraí",
      "preco": 780000,
      "quartos": 3,
      "foto_principal": "https://storage.zapini.app/gallery/8/image/....jpg",
      "ativo": true,
      "created_at": "2026-08-01 10:22:41"
    }
  ],
  "meta": { "current_page": 1, "per_page": 12, "total": 37, "last_page": 4 }
}

Criando um registro

curl -X POST https://zapini.app/api/v1/database/collections/imoveis/records \
  -H "Authorization: Bearer zpk_your_51_char_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "titulo": "Cobertura duplex — Santa Rosa",
    "preco": 1250000,
    "quartos": 4,
    "ativo": true
  }'

Dica: chame GET /database/collections/{collection} antes de gravar. O esquema devolve o nome exato de cada campo, o tipo e as opções válidas dos campos enum — é o que evita 422 na escrita.

TMS — Transporte

Escopos necessários: tms.read tms.write

O módulo de transporte inteiro por HTTP: cadastrar veículos e motoristas, programar fretes, acompanhar a entrega nota a nota, registrar ocorrências e manter contas a pagar e a receber em dia — os mesmos dados que o operador vê no painel.

Estes endpoints só respondem para clientes que usam o layout TMS. Qualquer outro recebe 403 TMS_NOT_ENABLED, por mais escopos que a chave tenha.

Frota — um registro por VEÍCULO, com a placa como chave e o motorista junto. O Grid (a lista de disponibilidade do dia) é uma marca nesse registro, não um cadastro à parte.

Programação — o PLANO: origem, destino, carga, veículo. O "code" (Nº Embarque) é sequencial por cliente e atribuído pelo servidor.

Monitoramento — a EXECUÇÃO: uma linha por nota fiscal. Um frete tem N linhas; mande "nr_embarque" e o servidor faz o vínculo.

CAP/CAR — o dinheiro, uma tabela separada por "direction". Contas a pagar e a receber nunca se misturam numa listagem.

Módulo e painéis

Método Endpoint Descrição
GET /tms Índice do módulo: cliente, contagem de registros e links dos recursos.
GET /tms/overview Indicadores do painel — status dos veículos, status das cargas, cargas por cliente, cargas em aberto por veículo.
GET /tms/grid Lista de disponibilidade da frota. Filtre com status[]=01..04; o padrão esconde "04 Com viagem".
GET /tms/municipios?uf=SP Municípios do IBGE de uma UF — alimenta o seletor de cidade.

Frota (veículos e motoristas)

Método Endpoint Descrição
GET /tms/fleet Lista os veículos. Filtros: search, placa, classificacao, cadastro_status, uf, cidade, source, vehicle_type_id, body_type_id, in_grid, tem_mopp, per_page, sort, order.
GET /tms/fleet/options IDs válidos dos selects do cadastro: tipos de veículo, carrocerias, tags de pedágio, rastreadoras, status, classificações.
GET /tms/fleet/by-plate?placa=ABC1D23 Acha o veículo pela placa. Hífen, espaço e caixa não atrapalham.
POST /tms/fleet Cadastra um veículo. placa e nome_motorista são obrigatórios; o resto (CNH, banco, carretas, dimensões) é opcional.
GET /tms/fleet/{uuid} Cadastro completo pela UUID, com o dossiê inteiro.
PUT /tms/fleet/{uuid} Alteração parcial — só as chaves enviadas são validadas e gravadas.
DELETE /tms/fleet/{uuid} Apaga o cadastro de vez. Para tirar o veículo só da lista do dia, use o endpoint do Grid.
POST /tms/fleet/{uuid}/grid Coloca o veículo no Grid (lista de disponibilidade). Idempotente.
DELETE /tms/fleet/{uuid}/grid Tira o veículo do Grid. O cadastro continua na Frota.
PUT /tms/fleet/{uuid}/grid-status Sobrescreve o status do Grid (01 Vazio, 02 Interessado, 05 Negociado, 04 Com viagem; 03 Homologar só vem pelo automático). 05 guarda a carga (freight_uuid) e a programa (06 - Programado, com a placa do veículo). null devolve para automático. A placa não fica 05 em duas cargas: com outra carga programada/em andamento com ela, volta 409 PLATE_ALREADY_NEGOTIATED.

Programação (fretes)

Método Endpoint Descrição
GET /tms/freights Lista os fretes. Filtros: status, operational_status, code, vehicle_plate, driver_phone, search, pickup_from, pickup_to, per_page, sort, order.
POST /tms/freights Cria um frete. origin e destination são obrigatórios; vehicle_plate que exista na Frota traz motorista e veículo junto.
GET /tms/freights/{uuid} Busca um frete pela UUID, com observações e o objeto meta.
PUT /tms/freights/{uuid} Alteração parcial. Mandar operational_status sincroniza também o status grosso. Opcional: `expected_operational_status` (código ou lista) — se o frete não estiver nele, nada muda e volta 409 FREIGHT_STATUS_CHANGED.
DELETE /tms/freights/{uuid} Remove o frete (soft delete).
PUT /tms/freights/{uuid}/status Move o status grosso: open, assigned, in_route, delivered, cancelled.
GET /tms/freights/{uuid}/compatible-drivers Motoristas compatíveis com a carga, em três camadas: frota própria, terceiros do mesmo revendedor e base de distribuição.

Monitoramento (por nota fiscal)

Método Endpoint Descrição
GET /tms/monitoring Lista as notas fiscais. Filtros: nr_embarque, freight_uuid, nf_entrega, placa, status_entrega_nf, status_embarque, cliente_operacao, uf, data_from, data_to, search.
POST /tms/monitoring Cria a linha de uma nota. Mandar nr_embarque vincula ao frete e copia placa, motorista e cliente quando vierem vazios.
GET /tms/monitoring/{uuid} Busca a linha de uma nota pela UUID.
PUT /tms/monitoring/{uuid} Alteração parcial — é aqui que o rastreador ou o WMS grava o status da entrega e o comprovante.
DELETE /tms/monitoring/{uuid} Remove a linha da nota (soft delete).

Ocorrências (incidentes)

Método Endpoint Descrição
GET /tms/occurrences Lista os incidentes. Filtros: status, type, severity, freight_uuid, pending, search, from, to.
POST /tms/occurrences Registra um incidente: type, severity e title são obrigatórios; freight_uuid é opcional (existe ocorrência avulsa).
GET /tms/occurrences/{uuid} Busca um incidente pela UUID, com descrição e resolução.
PUT /tms/occurrences/{uuid} Alteração parcial. Passar para resolved ou closed carimba quem fechou e quando.
DELETE /tms/occurrences/{uuid} Remove o incidente (soft delete).

Contas a pagar e a receber

Método Endpoint Descrição
GET /tms/cap Contas a pagar (CAP) — a mesma listagem com a direção já fixada.
GET /tms/car Contas a receber (CAR) — a mesma listagem com a direção já fixada.
GET /tms/finance Lista os lançamentos. direction é obrigatório. Filtros: status, category, freight_uuid, counterparty, due_from, due_to, pending, search.
POST /tms/finance Cria um lançamento. direction, category, description e amount_brl são obrigatórios.
GET /tms/finance/{uuid} Busca um lançamento pela UUID, com referência e observações.
PUT /tms/finance/{uuid} Alteração parcial. direction não muda — para corrigir, cancele e lance de novo.
DELETE /tms/finance/{uuid} Remove o lançamento (soft delete).
POST /tms/finance/{uuid}/pay Dá baixa no lançamento. Sem corpo é quitação total; amount_paid_brl menor deixa parcial.

Listas de valores (cadastros auxiliares)

Método Endpoint Descrição
GET /tms/option-lists Todas as listas de valores de uma vez. Recorte com ?lists=operational_statuses,finance_categories.
GET /tms/option-lists/{list} Uma lista com seus valores e quantos registros usam cada um.
POST /tms/option-lists/{list} Acrescenta um valor. stage vale em operational_statuses; directions vale em finance_categories.
PUT /tms/option-lists/{list}/{id} Renomeia, troca a cor, reordena ou desativa um valor.
DELETE /tms/option-lists/{list}/{id} Remove um valor. Valor em uso ou de sistema é recusado — nesse caso, desative.

Exemplo de requisição

curl -X POST https://zapini.app/api/v1/tms/freights \
  -H "Authorization: Bearer zpk_your_51_char_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "origin": "Santos/SP",
    "destination": "Betim/MG",
    "cargo_description": "Bobinas de aco",
    "cargo_weight_kg": 24000,
    "freight_value_brl": 7400.00,
    "vehicle_plate": "ABC1D23",
    "pickup_at": "2026-09-22T08:00:00-03:00",
    "delivery_eta": "2026-09-23T18:00:00-03:00",
    "operational_status": "06",
    "meta": { "nr_carga": "99812", "km": 780, "pedagio": 310.50 }
  }'

Exemplo de resposta — 201

{
  "success": true,
  "data": {
    "uuid": "9d3f2c1a-7b6e-4d5c-8a9b-0c1d2e3f4a5b",
    "code": "1482",
    "status": "assigned",
    "operational_status": "06",
    "origin": "Santos/SP",
    "destination": "Betim/MG",
    "driver_name": "Joao da Silva",
    "driver_phone": "+5513999999999",
    "vehicle_plate": "ABC1D23",
    "meta": { "nr_carga": "99812", "km": 780 },
    "created_at": "2026-09-17T12:00:00-03:00"
  }
}

O Nº Embarque (code) é do servidor e não muda: o Monitoramento amarra as notas por ele, então renumerar um embarque orfanaria entregas já lançadas.

operational_status, status_entrega_nf, status_embarque e category só aceitam valores que existem nas listas do cliente. Leia /tms/option-lists uma vez para conhecê-los — ou crie os seus.

Toda listagem é paginada (per_page até 200; meta traz current_page, last_page, per_page e total) e aceita sort e order.

Webhooks (saída)

Uma integração customizada pode registrar uma URL de webhook para receber eventos em tempo real — por exemplo message.received e message.sent — entregues como requisições POST em JSON.

Chaves com database.read também recebem database.record.created, database.record.updated e database.record.deleted sempre que um registro da Base Inteligente muda — é o gancho para revalidar o cache do seu site. Esses eventos são do tenant e não carregam instance_uuid.

Chaves com kanban.read também recebem crm.lead.created, crm.lead.updated, crm.lead.moved, crm.lead.won, crm.lead.lost e crm.lead.deleted sempre que um lead muda — por qualquer caminho: painel, API, formulário de site, importação, detecção automática ou automação. São eventos do tenant e não carregam instance_uuid. Movimentação, ganho e perda têm evento próprio e não repetem em crm.lead.updated. Apagar um QUADRO remove os leads dele em cascata no banco, sem evento por lead: esse caso emite um crm.board.deleted único, com a contagem do que foi removido.

Cada entrega é assinada com HMAC-SHA256. O cabeçalho X-Zapini-Signature carrega sha256= seguido do HMAC do corpo bruto da requisição, calculado com o seu segredo de webhook.

O segredo do webhook começa com zws_ e, assim como a chave de API, é exibido apenas uma vez ao ser gerado.

Para verificar uma entrega, calcule o HMAC sobre o corpo bruto da requisição (antes de qualquer parse) e compare com o cabeçalho usando comparação em tempo constante.

Exemplo de entrega

POST https://your-app.example.com/webhooks/zapini
Content-Type: application/json
X-Zapini-Signature: sha256=5257a869e7ecebeda32affa27f4245b1...

{
  "event": "message.received",
  "timestamp": "2026-07-02T12:00:00Z",
  "data": {
    "conversation_uuid": "550e8400-e29b-41d4-a716-446655440000",
    "message": {
      "direction": "incoming",
      "sender_number": "+5511999999999",
      "content": "Hi! I would like a quote."
    }
  }
}

Verificando a assinatura (PHP)

$secret    = 'zws_your_webhook_secret';
$payload   = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_ZAPINI_SIGNATURE'] ?? '';

$expected = 'sha256=' . hash_hmac('sha256', $payload, $secret);

// Timing-safe comparison
if (! hash_equals($expected, $signature)) {
    http_response_code(401);
    exit;
}

Pronto para construir?

Crie sua primeira chave de integração e comece a chamar a API em minutos.

Criar uma chave de integração