API de la integración con Cayena
Cayena consume esta API en Demander Web. La configuración de la empresa está en Configuración de la integración.
Dirección
Sección titulada «Dirección»https://sistema.demander.com.br/cayena/v1El cuerpo de las llamadas POST es JSON. Las respuestas de error siguen este formato:
{ "error": { "code": "INVALID_REQUEST", "message": "Texto do erro.", "details": {} }}details solo viene cuando la API necesita señalar producto, pedido o ciudad.
| Límite | Dónde |
|---|---|
| 60 llamadas por minuto | POST /cayena/v1/auth, por código de la empresa |
| 300 llamadas por minuto | Las demás rutas, por el token de acceso |
Por encima del límite la respuesta es HTTP 429, código RATE_LIMIT_EXCEEDED.
Autenticación
Sección titulada «Autenticación»POST /cayena/v1/auth
{ "clientId": "codigo-da-empresa", "clientSecret": "token-gerado-na-configuracao"}clientId es el código de la empresa en Demander. clientSecret es el token de la pantalla Integração Cayena.
Respuesta HTTP 200:
{ "accessToken": "token-de-acesso", "tokenType": "Bearer"}El token de acceso vale 1 hora. En las otras rutas envíe:
Authorization: Bearer accessTokenaccessToken es el valor devuelto en la autenticación.
| HTTP | Código | Cuándo |
|---|---|---|
| 400 | INVALID_REQUEST |
clientId o clientSecret ausente, o clientId que no es el código de la empresa |
| 401 | INVALID_CREDENTIALS |
Token distinto o integración inactiva |
| 403 | COMPANY_INACTIVE |
Empresa inactiva o fuera del período de pruebas |
| 401 | INVALID_TOKEN |
En las otras rutas: Bearer ausente, expirado, alterado o de una configuración que se desactivó o tuvo el token cambiado |
Catálogo de productos
Sección titulada «Catálogo de productos»GET /cayena/v1/products?page=1&limit=100
| Parámetro | Predeterminado | Regla |
|---|---|---|
page |
1 | Entero a partir de 1 |
limit |
100 | Entero de 1 a 1000 |
Entran productos activos con precio mayor que cero en la lista de precios de la configuración. El precio exclusivo de un cliente no entra. Si el producto tiene más de un precio en esa lista, vale el 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 | Origen en Demander |
|---|---|
productId |
Código del producto |
description |
Descripción |
content |
Cantidad del embalaje en la lista de precios |
size |
Peso neto en la lista de precios |
availableStock |
Saldo de stock. Negativo vuelve como 0 |
price |
Precio en la lista configurada |
boxWeight |
Primer múltiplo de embalaje, cuando existe |
ean |
Código de barras, cuando está lleno |
brand |
Marca, cuando está llena |
units |
Sigla de la unidad y la descripción del de-para |
La unidad viene del precio. Si está vacía, usa la unidad de venta del producto.
| HTTP | Código | Cuándo |
|---|---|---|
| 400 | INVALID_REQUEST |
page o limit inválido |
| 422 | MISSING_UNIT |
Producto de la página sin unidad |
| 422 | UNIT_NOT_MAPPED |
Sigla sin descripción en el de-para |
Esos errores 422 interrumpen la página. details trae productId y, en el caso de la unidad, unitCode.
Clientes
Sección titulada «Clientes»Consultar
Sección titulada «Consultar»GET /cayena/v1/customers/documentNumber
Envíe CPF o CNPJ solo con dígitos. Demander también acepta el documento con máscara.
POST /cayena/v1/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 | Regla |
|---|---|
documentNumber |
CPF o CNPJ válido |
documentType |
CPF o CNPJ, de acuerdo con el documento |
legalName, email, phone |
Obligatorios. Correo válido. Teléfono con DDD, 10 u 11 dígitos |
address |
Calle, número, barrio, ciudad, UF y CEP. Número numérico. UF con 2 letras. CEP con 8 dígitos |
stateRegistration |
Opcional. Pasa a ser la inscripción estadual |
owner |
Opcional. Cuando tiene name, graba un contacto del cliente |
tradeName |
Opcional. Vacío: usa la razón social |
Cliente nuevo: HTTP 201. Cliente que ya existe por el mismo documento: HTTP 200 con el registro que ya está en Demander. El POST no actualiza nombre, dirección ni contacto.
La ciudad debe existir en Demander para la combinación ciudad y UF. El nombre puede venir con o sin acento.
Respuesta:
{ "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" }}| Situación del cliente | status |
approvalStatus |
|---|---|---|
| Activo y no bloqueado | ACTIVE |
APPROVED |
| Inactivo | INACTIVE |
REJECTED |
| Bloqueado | BLOCKED |
REJECTED |
isExternalAsset vuelve siempre false.
| HTTP | Código | Cuándo |
|---|---|---|
| 400 | INVALID_DOCUMENT |
Documento que no tiene 11 ni 14 dígitos |
| 422 | INVALID_DOCUMENT |
CPF o CNPJ con dígitos verificadores inválidos |
| 422 | INVALID_DOCUMENT |
documentType no combina con el documento |
| 400 | INVALID_REQUEST |
Nombre, correo, teléfono o dirección incompletos |
| 404 | CUSTOMER_NOT_FOUND |
Consulta sin cliente para el documento |
| 422 | CITY_NOT_FOUND |
Ciudad y UF no encontradas. details trae city y state |
| 409 | CUSTOMER_PROCESSING |
Otra grabación del mismo documento todavía está en curso |
El cliente nuevo queda activo, en el vendedor y en la lista de precios de la configuración.
Pedidos
Sección titulada «Pedidos»POST /cayena/v1/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 | Regla |
|---|---|
orderNumber |
Texto obligatorio, hasta 50 caracteres. Es el número del pedido en Cayena |
customerId |
customerId devuelto en la API de clientes |
deliveryDate |
Fecha AAAA-MM-DD. No puede ser anterior a hoy |
totalAmount |
Mayor que cero. Tiene que ser la suma de cantidad × precio de los ítems, en centavos |
note |
Opcional. Va a la observación del pedido |
items |
Al menos un ítem. productId, quantity y unitPrice obligatorios y mayores que cero. El mismo producto no puede repetirse |
El producto debe estar activo, con precio en la lista de la configuración y con stock suficiente. El stock negativo cuenta como cero.
Pedido nuevo: HTTP 201.
{ "orderId": "1500", "orderNumber": "20261007001", "status": "CONFIRMED", "description": "RECEBIDO"}orderId es el código del pedido en Demander. status es el orderStatus del de-para. description es la descripción del estado en Demander.
El pedido se graba con origen Cayena, en el vendedor, lista, sucursal, tipo, condición y estado inicial de la configuración.
Pedido repetido
Sección titulada «Pedido repetido»Enviar de nuevo el mismo orderNumber no crea otro pedido. La respuesta es HTTP 200, con los mismos campos y "duplicate": true.
Eso también vale cuando el pedido ya fue entregado o cancelado.
Consultar
Sección titulada «Consultar»GET /cayena/v1/orders/orderId
orderId es numérico. La respuesta trae orderId, status, description y, cuando hay, orderNumber.
| HTTP | Código | Cuándo |
|---|---|---|
| 400 | INVALID_REQUEST |
Campo obligatorio ausente, fecha en formato incorrecto o ítem inválido |
| 422 | INVALID_DELIVERY_DATE |
Fecha de entrega anterior a hoy |
| 422 | INVALID_REQUEST |
Total o cantidad/precio menor o igual a cero |
| 422 | DUPLICATE_PRODUCT |
Producto repetido en el mismo pedido |
| 422 | ORDER_TOTAL_MISMATCH |
totalAmount distinto de la suma de los ítems |
| 404 | CUSTOMER_NOT_FOUND |
customerId inexistente en esta empresa |
| 403 | CUSTOMER_INACTIVE |
Cliente inactivo o bloqueado |
| 422 | PRODUCT_NOT_FOUND |
Producto inactivo o sin precio en la lista |
| 422 | INSUFFICIENT_STOCK |
Cantidad mayor que el saldo |
| 409 | ORDER_PROCESSING |
El mismo número todavía se está grabando |
| 404 | ORDER_NOT_FOUND |
Consulta de un pedido que no es de esta empresa o no vino de Cayena |
| 422 | INVALID_ORDER_STATUS |
Estado actual del pedido fuera del de-para |
Estado del pedido
Sección titulada «Estado del pedido»GET /cayena/v1/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 viene del de-para del estado actual. orderStatusDescription es la descripción registrada en Demander. updatedAt es el momento en que el pedido entró en ese estado. deliveredAt solo aparece cuando el de-para de ese estado está con entregue true.
Las fechas usan el huso de São Paulo, en formato ISO con el desplazamiento.
Pedido inexistente o estado sin de-para usan los mismos códigos de la consulta del pedido.
Quien cambia el estado es Demander o el ERP, no esta API. Cayena solo lee.
Nota fiscal
Sección titulada «Nota fiscal»GET /cayena/v1/orders/orderId/invoice
La nota viene de la tabla 170 — Nota del pedido. La clave debe estar en chaveNfe, con 44 dígitos, sin máscara. La serie queda en serieNfe.
Si hay más de una nota con clave, vale la de fecha más reciente.
{ "orderId": "1500", "nfeKey": "35261000000000000000550010000000011000000010", "invoiceNumber": "1", "series": "1", "issuedDate": "2026-10-08T10:00:00-03:00", "totalAmount": 20.5}nfeKey es obligatorio en la respuesta. Número, serie, fecha y valor solo entran cuando la nota los tiene.
| HTTP | Código | Cuándo |
|---|---|---|
| 404 | NFE_NOT_ISSUED |
Pedido todavía sin clave de NF-e |
| 422 | INVALID_NFE_KEY |
Clave que no tiene 44 dígitos |
Error inesperado
Sección titulada «Error inesperado»Una falla no prevista responde HTTP 500, código SYSTEM_ERROR, mensaje Erro inesperado. El detalle interno no va en el cuerpo. La llamada queda en el log de la empresa.