KIPI KIPI Portal de Integração — API do Parceiro Swagger (teste ao vivo) kipi.com.br

Integre o seu ERP à KIPI

Manual completo para o parceiro atacadista integrar o seu sistema de gestão: carregue seu catálogo de produtos, baixe automaticamente os pedidos dos clientes (com os dados cadastrais para o seu ERP) e aceite, recuse ou entregue pedidos — tudo por API, sem precisar acessar o app.

Visão geral

A API do Parceiro é uma API REST sobre HTTPS que devolve JSON. Tudo o que o app do parceiro faz, o seu ERP também pode fazer.

URL base (produção)https://pinn-b2b-atacadista.onrender.com
FormatoJSON (envie o header Content-Type: application/json)
AutenticaçãoJWT — header Authorization: Bearer <access_token>
Documentação interativa/docs (Swagger UI — permite testar cada rota no navegador)

O que você pode fazer:

Multi-tenant automático: o token identifica a sua empresa. Você só enxerga (e só altera) os seus próprios produtos e pedidos — nunca envie atacadista_id no corpo das requisições.

Autenticação

Use o mesmo e-mail e senha da sua conta de parceiro (a que você usa em parceiros.kipi.com.br).

POST/auth/login
curl -X POST https://pinn-b2b-atacadista.onrender.com/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email": "seu-email@empresa.com.br", "senha": "sua-senha"}'

Resposta:

{
  "access_token": "eyJhbGciOi...",
  "refresh_token": "eyJhbGciOi...",
  "token_type": "bearer",
  "expires_in": 86400
}

Envie o access_token em todas as chamadas:

Authorization: Bearer eyJhbGciOi...
Validade: o access_token vale 24 horas (expires_in = segundos) — uma carga noturna inteira roda com um único login. Se receber 401 ("Não foi possível validar as credenciais"), renove com POST /auth/refresh enviando {"refresh_token": "..."} — ou faça login novamente e repita a chamada que falhou.

Produtos — carga em massa (recomendado)

É a rota ideal para integração com ERP: envie a lista de produtos e a KIPI faz upsert pelo campo codigo — se o código já existe, o produto é atualizado; se não existe, é criado. Pode rodar quantas vezes quiser (idempotente).

POST/produtos/bulk
curl -X POST https://pinn-b2b-atacadista.onrender.com/produtos/bulk \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '[
    {
      "codigo": "7891234567890",
      "descricao": "ARROZ BRANCO TIPO 1 5KG",
      "estoque": 350,
      "qtd_minima": 1,
      "qtd_maxima": 200,
      "imagem_base64": "data:image/jpeg;base64,/9j/4AAQSkZJRg...",
      "precos": [
        {"unidade": "UN", "preco": 22.90, "quantidade_unidades": 1},
        {"unidade": "FD", "preco": 132.00, "quantidade_unidades": 6}
      ]
    },
    {
      "codigo": "7899876543210",
      "descricao": "OLEO DE SOJA 900ML",
      "imagem_base64": null,
      "estoque": 1200,
      "precos": [
        {"unidade": "CX", "preco": 118.80, "quantidade_unidades": 20}
      ]
    }
  ]'

Campos do produto

CampoTipoObrigatórioDescrição
codigostringsimCódigo do produto no seu ERP (chave do upsert). Use o mesmo sempre.
descricaostringsimDescrição de venda (exibida ao cliente em CAIXA ALTA).
precoslistasim (mín. 1)Um item por embalagem: unidade (texto livre: UN, CX, FD, PALLET...), preco (> 0, da embalagem inteira) e quantidade_unidades (quantas unidades a embalagem contém).
estoqueinteironão (padrão 0)Saldo disponível.
qtd_minima / qtd_maximainteironãoLimites de quantidade por pedido para este produto.
imagem_base64stringnãoImagem do produto em base64 (data:image/jpeg;base64,...) — é assim que os parceiros enviam hoje. A KIPI hospeda a imagem para você. Pode ser null. Se o upload da imagem falhar, o produto é gravado mesmo assim (sem imagem).
image_urlstringnãoAlternativa: URL pública da imagem, se você já tiver a foto hospedada.
Rotina sugerida: exporte o catálogo do ERP e envie ao /produtos/bulk 1x ao dia (ou sempre que preço/estoque mudar). Lotes de até ~200 produtos por chamada funcionam bem; para catálogos maiores, divida em várias chamadas.

Produtos — listar e consultar

GET/produtos?page=1&page_size=100&search=arroz
ParâmetroDescrição
page / page_sizePaginação (page_size máx. 100). A resposta traz total e total_pages.
searchBusca por código ou descrição (contém, sem diferenciar maiúsculas).
GET/produtos/{produto_id}

Consulta um produto pelo ID interno da KIPI (campo id retornado nas listagens).

Produtos — criar, atualizar e excluir (unitário)

POST/produtos

Cria um produto (mesmo corpo de um item do bulk). Para integração, prefira o /produtos/bulk.

PUT/produtos/{produto_id}

Atualização parcial: envie só os campos que quer mudar (ex.: {"estoque": 40}).

DELETE/produtos/{produto_id}

Remove o produto do catálogo.

Pedidos — status possíveis

StatusSignificadoQuem coloca
pendentePedido novo, aguardando a sua decisão.Criado pela compra do cliente (ou do representante VendeMais).
aceitoVocê confirmou que vai atender.Você — POST /pedidos/{id}/aceitar
recusadoVocê recusou (ou cancelou) o pedido, com motivo.Você — POST /pedidos/{id}/recusar ou /cancelar
entregueMercadoria entregue ao cliente.Você — POST /pedidos/{id}/entregar
O cancelar existe para desfazer um pedido já aceito; no sistema ele fica com status recusado e guarda o motivo informado.

Pedidos — listar com filtros

GET/pedidos/?status=pendente&page=1&page_size=50
ParâmetroDescrição
statuspendente, aceito, recusado ou entregue. Sem o parâmetro, retorna todos.
data_inicio / data_fimIntervalo da data de criação, formato YYYY-MM-DD.
varejistaFiltra pelo nome (ou ID) do cliente — busca "contém".
produtoFiltra por descrição de produto contida nos itens.
page / page_sizePaginação (máx. 100 por página).

Cada item da lista traz: id, nome do cliente (varejista_nome_fantasia), valor_total, status, condicao_pagamento, data_criacao, nome do representante e a marcação venda_mais quando o pedido veio do programa VendeMais.

Pedidos — detalhe (com dados do cliente para o seu ERP)

GET/pedidos/{pedido_id}

Retorna o pedido completo. Os blocos importantes para o seu ERP:

{
  "id": "6a4d3821f6c928eea9ca02c0",
  "status": "pendente",
  "data_criacao": "2026-07-06T02:31:30",
  "condicao_pagamento": "21 DIAS",
  "valor_total": 246.20,

  "varejista_nome_fantasia": "MERCEARIA DA CLAU",     // dados do CLIENTE
  "varejista_razao_social": "CLAUDETE COMERCIO LTDA", // p/ cadastro no ERP
  "varejista_cnpj": "12.345.678/0001-90",
  "varejista_inscricao_estadual": "096/2782076",
  "varejista_endereco": "Av. Bento Goncalves, 4200 - Partenon - Porto Alegre/RS - CEP 90650-002",
  "varejista_email": "clau@mercearia.com.br",
  "varejista_telefone": "(51) 99999-8888",

  "endereco_entrega": {                                // onde ENTREGAR
    "logradouro": "Rua Joao Salomoni", "numero": "1365",
    "bairro": "Vila Nova", "cidade": "Porto Alegre",
    "uf": "RS", "cep": "91740-830", "complemento": null
  },

  "representante_nome": null,   // preenchido quando ha representante
  "venda_mais": false,          // true = vendido pelo representante (VendeMais)

  "itens": [
    {
      "produto_id": "665f0c...",
      "codigo": "7891234567890",         // SEU codigo de produto (do bulk)
      "descricao_produto": "ARROZ BRANCO TIPO 1 5KG",
      "unidade": "FD",                   // embalagem escolhida pelo cliente
      "quantidade": 10,
      "valor_unitario": 132.00,
      "valor_total": 1320.00
    }
  ]
}
O campo codigo de cada item é o mesmo código que você enviou na carga de produtos — use-o para casar o pedido com o item no seu ERP, sem precisar guardar os IDs internos da KIPI.

Pedidos — ações (sem acessar o app)

POST/pedidos/{pedido_id}/aceitar

Sem corpo. Marca o pedido como aceito.

POST/pedidos/{pedido_id}/recusar
{"motivo": "Estoque insuficiente para o item 7891234567890"}
POST/pedidos/{pedido_id}/entregar

Sem corpo. Marca como entregue (informe apenas após a entrega física — este evento também ativa clientes pré-cadastrados por representante).

POST/pedidos/{pedido_id}/cancelar
{"motivo": "Cliente solicitou cancelamento"}

Todas respondem com {"id": "...", "status": "...", "data_criacao": "..."}.

Fluxo de integração recomendado

Exemplo prático de rotina do ERP (pode rodar a cada 5–15 minutos):

LoginPOST /auth/login e guarde o access_token.
Consultar pedidos novosGET /pedidos/?status=pendente. Se a lista vier vazia, encerre a execução.
Baixar cada pedidoGET /pedidos/{id}. Cadastre o cliente no ERP (razão social, CNPJ, IE, endereço) se ainda não existir, e importe os itens usando o campo codigo.
Decidir no ERP — verifique estoque/crédito e então aceite (POST /pedidos/{id}/aceitar) ou recuse com motivo (POST /pedidos/{id}/recusar).
Após a entrega físicaPOST /pedidos/{id}/entregar. O cliente vê o status atualizado no app na hora.
Catálogo em dia — em rotina separada (ex.: diária), envie preços/estoque com POST /produtos/bulk.
Evite processar duas vezes: guarde no seu ERP o id dos pedidos já importados. Como você mesmo muda o status para aceito/recusado, a consulta por status=pendente naturalmente deixa de retorná-los.

Exemplo completo (Python)

import requests

BASE = "https://pinn-b2b-atacadista.onrender.com"
EMAIL, SENHA = "seu-email@empresa.com.br", "sua-senha"

# 1) login
r = requests.post(f"{BASE}/auth/login", json={"email": EMAIL, "senha": SENHA})
r.raise_for_status()
token = r.json()["access_token"]
H = {"Authorization": f"Bearer {token}"}

# 2) carga de produtos (upsert pelo codigo)
catalogo = [
    {"codigo": "7891234567890", "descricao": "ARROZ BRANCO TIPO 1 5KG",
     "imagem_base64": None,  # ou "data:image/jpeg;base64,..."
     "estoque": 350, "precos": [{"unidade": "UN", "preco": 22.90, "quantidade_unidades": 1}]},
]
requests.post(f"{BASE}/produtos/bulk", json=catalogo, headers=H).raise_for_status()

# 3) baixar pedidos pendentes
pedidos = requests.get(f"{BASE}/pedidos/", params={"status": "pendente", "page_size": 100},
                       headers=H).json()["items"]

for p in pedidos:
    det = requests.get(f"{BASE}/pedidos/{p['id']}", headers=H).json()
    print("Pedido", det["id"], "-", det["varejista_nome_fantasia"],
          "- CNPJ", det.get("varejista_cnpj"), "- R$", det["valor_total"])
    # ... cadastre o cliente e importe os itens no seu ERP ...

    tem_estoque = True  # sua regra de negocio aqui
    if tem_estoque:
        requests.post(f"{BASE}/pedidos/{p['id']}/aceitar", headers=H).raise_for_status()
    else:
        requests.post(f"{BASE}/pedidos/{p['id']}/recusar",
                      json={"motivo": "Estoque insuficiente"}, headers=H).raise_for_status()

Erros e boas práticas

CódigoSignificadoO que fazer
401Token ausente, inválido ou expirado.Faça login novamente (ou use /auth/refresh) e repita a chamada.
403Conta inativa.Fale com o administrador da KIPI.
404Recurso não encontrado (ou não pertence à sua conta).Confira o id utilizado.
422Corpo/parâmetros inválidos.A resposta detalha campo a campo o que está errado — ajuste e reenvie.
400Regra de negócio (ex.: recusar sem motivo).Veja a mensagem em detail.