API da integração com a Cayena
Esta API permite que a Cayena consulte produtos, cadastre clientes, envie pedidos e acompanhe status e notas fiscais no Demander. Antes de usá-la, preencha a configuração da integração da empresa.
Endereço
Seção intitulada “Endereço”https://sistema.demander.com.br/cayena/v1Use esse endereço como base para todas as rotas deste artigo. O corpo das chamadas POST deve ser enviado em JSON.
As respostas de erro seguem este formato:
{ "error": { "code": "INVALID_REQUEST", "message": "Texto do erro.", "details": {} }}details aparece somente quando a API precisa identificar, por exemplo, um produto, um pedido ou uma cidade relacionada ao erro.
| Limite | Onde |
|---|---|
| 60 chamadas por minuto | POST /auth, por empresa |
| 300 chamadas por minuto | Demais rotas, pelo token de acesso |
Quando o limite é excedido, a API responde com HTTP 429 e código RATE_LIMIT_EXCEEDED.
Autenticação
Seção intitulada “Autenticação”POST /auth
{ "clientId": "codigo-da-empresa", "clientSecret": "token-gerado-na-configuracao"}clientId é o código da empresa no Demander. clientSecret é o token gerado na tela Integração Cayena.
Resposta HTTP 200:
{ "accessToken": "token-de-acesso", "tokenType": "Bearer"}O token de acesso vale por 1 hora. Envie-o nas demais rotas:
Authorization: Bearer accessTokenSubstitua accessToken pelo valor devolvido na autenticação.
| HTTP | Código | Quando |
|---|---|---|
| 400 | INVALID_REQUEST |
clientId ou clientSecret ausente, ou clientId diferente de um código de empresa válido |
| 401 | INVALID_CREDENTIALS |
Token diferente ou integração inativa |
| 403 | COMPANY_INACTIVE |
Empresa inativa ou fora do período de testes |
| 401 | INVALID_TOKEN |
Nas outras rotas: Bearer ausente, expirado, adulterado ou de uma configuração que foi desativada ou teve o token trocado |
Catálogo de produtos
Seção intitulada “Catálogo de produtos”GET /products?page=1&limit=100
| Parâmetro | Padrão | Regra |
|---|---|---|
page |
1 | Inteiro a partir de 1 |
limit |
100 | Inteiro de 1 a 1000 |
A API devolve os produtos ativos com preço maior que zero na lista configurada. Preços específicos por cliente não entram no catálogo. Se houver mais de um preço para o mesmo produto nessa lista, será usado o registro de menor código.
{ "currentPage": 1, "totalPages": 3, "totalProducts": 250, "products": [ { "productId": "10", "description": "Nome do produto", "content": "1", "size": "0.5", "availableStock": 20, "price": 10.25, "boxWeight": 12, "ean": "7890000000000", "brand": "Marca", "units": [ { "unitCode": "UN", "unitDescription": "Unidade" } ] } ]}| Campo | Origem no Demander |
|---|---|
productId |
Código do produto |
description |
Descrição |
content |
Quantidade da embalagem na lista de preço |
size |
Peso líquido na lista de preço |
availableStock |
Saldo de estoque. Valores negativos são devolvidos como 0 |
price |
Preço na lista configurada |
boxWeight |
Primeiro múltiplo de embalagem, quando existir |
ean |
Código de barras, quando preenchido |
brand |
Marca, quando preenchida |
units |
Sigla da unidade e a descrição do de-para |
A unidade vem do registro de preço. Quando não estiver preenchida, a API usa a unidade de venda do produto.
| HTTP | Código | Quando |
|---|---|---|
| 400 | INVALID_REQUEST |
page ou limit inválido |
| 422 | MISSING_UNIT |
Produto da página sem unidade |
| 422 | UNIT_NOT_MAPPED |
Sigla sem descrição no de-para |
Esses erros 422 impedem o retorno de toda a página consultada. O objeto details informa o productId e, quando disponível, o unitCode.
Clientes
Seção intitulada “Clientes”Consultar
Seção intitulada “Consultar”GET /customers/{documentNumber}
Substitua documentNumber pelo CPF ou CNPJ do cliente. O documento pode ser enviado somente com dígitos ou com máscara.
POST /customers
{ "documentNumber": "11444777000161", "documentType": "CNPJ", "legalName": "Cliente Exemplo Ltda", "tradeName": "Cliente Exemplo", "email": "compras@exemplo.com", "phone": "11999998888", "stateRegistration": "123456789", "address": { "street": "Rua Exemplo", "number": "100", "complement": "Sala 2", "neighborhood": "Centro", "city": "São Paulo", "state": "SP", "zipCode": "01001000" }, "owner": { "name": "Maria Souza", "email": "maria@exemplo.com", "phone": "11988887777" }}| Campo | Regra |
|---|---|
documentNumber |
CPF ou CNPJ válido |
documentType |
CPF ou CNPJ, de acordo com o documento |
legalName, email, phone |
Obrigatórios. E-mail válido. Telefone com DDD, 10 ou 11 dígitos |
address |
Logradouro, número, bairro, cidade, UF e CEP. Número numérico. UF com 2 letras. CEP com 8 dígitos |
stateRegistration |
Opcional. Vira a inscrição estadual |
owner |
Opcional. Quando name é informado, grava um contato para o cliente |
tradeName |
Opcional. Quando vazio, usa a razão social |
Ao criar um cliente, a API responde com HTTP 201. Se já existir um cadastro com o mesmo documento, responde com HTTP 200 e devolve os dados existentes. Nesse caso, a chamada não atualiza nome, endereço ou contato.
A combinação de cidade e UF precisa existir no Demander. O nome da cidade pode ser enviado com ou sem acento.
Resposta:
{ "customerId": "12345", "documentNumber": "11444777000161", "documentType": "CNPJ", "legalName": "Cliente Exemplo Ltda", "tradeName": "Cliente Exemplo", "status": "ACTIVE", "approvalStatus": "APPROVED", "isExternalAsset": false, "externalAssetReason": null, "email": "compras@exemplo.com", "phone": "11999998888", "stateRegistration": "123456789", "address": { "street": "Rua Exemplo", "number": "100", "neighborhood": "Centro", "city": "São Paulo", "state": "SP", "zipCode": "01001000", "complement": "Sala 2" }}| Situação do cliente | status |
approvalStatus |
|---|---|---|
| Ativo e não bloqueado | ACTIVE |
APPROVED |
| Inativo | INACTIVE |
REJECTED |
| Bloqueado | BLOCKED |
REJECTED |
isExternalAsset é sempre devolvido como false.
| HTTP | Código | Quando |
|---|---|---|
| 400 | INVALID_DOCUMENT |
Documento que não tem 11 nem 14 dígitos |
| 422 | INVALID_DOCUMENT |
CPF ou CNPJ com dígitos verificadores inválidos |
| 422 | INVALID_DOCUMENT |
documentType não combina com o documento |
| 400 | INVALID_REQUEST |
Nome, e-mail, telefone ou endereço incompleto |
| 404 | CUSTOMER_NOT_FOUND |
Consulta sem cliente para o documento |
| 422 | CITY_NOT_FOUND |
Cidade e UF não encontradas. details traz city e state |
| 409 | CUSTOMER_PROCESSING |
Outra solicitação para gravar o mesmo documento ainda está em andamento |
O novo cliente é gravado como ativo, com o vendedor e com a lista de preço definidos na configuração.
Pedidos
Seção intitulada “Pedidos”POST /orders
{ "orderNumber": "20261007001", "customerId": "12345", "deliveryDate": "2026-10-08", "totalAmount": 20.5, "note": "Entregar pela manhã", "items": [ { "productId": "10", "quantity": 2, "unitPrice": 10.25 } ]}| Campo | Regra |
|---|---|
orderNumber |
Texto obrigatório, até 50 caracteres. É o número do pedido na Cayena |
customerId |
customerId devolvido na API de clientes |
deliveryDate |
Data AAAA-MM-DD. Não pode ser anterior a hoje |
totalAmount |
Maior que zero. Deve corresponder à soma de quantidade × preço de todos os itens |
note |
Opcional. Vai para a observação do pedido |
items |
Ao menos um item. productId, quantity e unitPrice são obrigatórios e maiores que zero. O mesmo produto não pode aparecer mais de uma vez |
Cada produto precisa estar ativo, ter preço na lista configurada e possuir estoque suficiente. Saldos negativos são considerados como zero.
Ao criar um pedido, a API responde com HTTP 201.
{ "orderId": "1500", "orderNumber": "20261007001", "status": "CONFIRMED", "description": "RECEBIDO"}orderId é o código do pedido no Demander. status é o orderStatus relacionado no de-para, e description é a descrição do status no Demander.
O pedido é gravado com a origem Cayena e com o vendedor, a lista de preço, a filial, o tipo de pedido, a condição de pagamento e o status inicial definidos na configuração.
Pedido repetido
Seção intitulada “Pedido repetido”orderNumber identifica o pedido na Cayena. Se a mesma empresa reenviar um número já recebido, o Demander não cria outro pedido: a API devolve o pedido existente com HTTP 200 e "duplicate": true.
Essa regra também vale quando o pedido existente já foi entregue ou cancelado.
Consultar
Seção intitulada “Consultar”GET /orders/{orderId}
Substitua orderId pelo código numérico do pedido no Demander. A resposta traz orderId, status, description e, quando disponível, orderNumber.
| HTTP | Código | Quando |
|---|---|---|
| 400 | INVALID_REQUEST |
Campo obrigatório ausente, data em formato errado ou item inválido |
| 422 | INVALID_DELIVERY_DATE |
Data de entrega anterior a hoje |
| 422 | INVALID_REQUEST |
Total ou quantidade/preço menor ou igual a zero |
| 422 | DUPLICATE_PRODUCT |
Produto repetido no mesmo pedido |
| 422 | ORDER_TOTAL_MISMATCH |
totalAmount diferente da soma dos itens |
| 404 | CUSTOMER_NOT_FOUND |
customerId inexistente nesta empresa |
| 403 | CUSTOMER_INACTIVE |
Cliente inativo ou bloqueado |
| 422 | PRODUCT_NOT_FOUND |
Produto inativo ou sem preço na lista |
| 422 | INSUFFICIENT_STOCK |
Quantidade maior que o saldo |
| 409 | ORDER_PROCESSING |
O mesmo número ainda está sendo gravado |
| 404 | ORDER_NOT_FOUND |
Pedido que não pertence à empresa ou que não foi criado pela integração com a Cayena |
| 422 | INVALID_ORDER_STATUS |
Status atual do pedido fora do de-para |
Status do pedido
Seção intitulada “Status do pedido”GET /orders/{orderId}/status
{ "orderId": "1500", "orderNumber": "20261007001", "orderStatus": "DELIVERED", "orderStatusDescription": "FATURADO", "updatedAt": "2026-10-08T14:30:00-03:00", "deliveredAt": "2026-10-08T14:30:00-03:00"}orderStatus vem do de-para do status atual. orderStatusDescription é a descrição cadastrada no Demander. updatedAt informa quando o pedido entrou nesse status. deliveredAt aparece somente quando o status está marcado com entregue: true no de-para.
As datas usam o fuso de São Paulo, no formato ISO com o deslocamento.
Pedido inexistente ou status sem de-para usam os mesmos códigos da consulta do pedido.
Esta API não altera o status do pedido. A mudança acontece no fluxo do Demander, geralmente pela integração com o ERP; a Cayena apenas consulta o resultado.
Nota fiscal
Seção intitulada “Nota fiscal”GET /orders/{orderId}/invoice
Os dados da nota são recebidos pela tabela 170 — Pedido Nota. A chave deve ser enviada em chaveNfe, com 44 dígitos e sem máscara; a série deve ser enviada em serieNfe.
Se o pedido tiver mais de uma nota com chave, a API devolverá a nota de emissão mais recente.
{ "orderId": "1500", "nfeKey": "35261000000000000000550010000000011000000010", "invoiceNumber": "1", "series": "1", "issuedDate": "2026-10-08T10:00:00-03:00", "totalAmount": 20.5}nfeKey sempre aparece quando a consulta é concluída. Número, série, data e valor são devolvidos somente quando estiverem preenchidos na nota.
| HTTP | Código | Quando |
|---|---|---|
| 404 | NFE_NOT_ISSUED |
Pedido ainda sem chave de NF-e |
| 422 | INVALID_NFE_KEY |
Chave que não tem 44 dígitos |
Erro inesperado
Seção intitulada “Erro inesperado”Uma falha não prevista responde com HTTP 500, código SYSTEM_ERROR e a mensagem Erro inesperado. O detalhe interno não é exposto na resposta, mas a chamada fica registrada no log da empresa.