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 |
|---|---|
| Formato | JSON (envie o header Content-Type: application/json) |
| Autenticação | JWT — header Authorization: Bearer <access_token> |
| Documentação interativa | /docs (Swagger UI — permite testar cada rota no navegador) |
O que você pode fazer:
- Produtos — carga completa ou incremental do catálogo (preços por embalagem, estoque, imagem, quantidade mínima/máxima).
- Pedidos — baixar os pedidos feitos pelos clientes com todos os dados do cliente (razão social, CNPJ, endereço de entrega) e agir sobre eles: aceitar, recusar, marcar como entregue ou cancelar.
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).
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...
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).
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
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
codigo | string | sim | Código do produto no seu ERP (chave do upsert). Use o mesmo sempre. |
descricao | string | sim | Descrição de venda (exibida ao cliente em CAIXA ALTA). |
precos | lista | sim (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). |
estoque | inteiro | não (padrão 0) | Saldo disponível. |
qtd_minima / qtd_maxima | inteiro | não | Limites de quantidade por pedido para este produto. |
imagem_base64 | string | não | Imagem 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_url | string | não | Alternativa: URL pública da imagem, se você já tiver a foto hospedada. |
/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
| Parâmetro | Descrição |
|---|---|
page / page_size | Paginação (page_size máx. 100). A resposta traz total e total_pages. |
search | Busca por código ou descrição (contém, sem diferenciar maiúsculas). |
Consulta um produto pelo ID interno da KIPI (campo id retornado nas listagens).
Produtos — criar, atualizar e excluir (unitário)
Cria um produto (mesmo corpo de um item do bulk). Para integração, prefira o /produtos/bulk.
Atualização parcial: envie só os campos que quer mudar (ex.: {"estoque": 40}).
Remove o produto do catálogo.
Pedidos — status possíveis
| Status | Significado | Quem coloca |
|---|---|---|
pendente | Pedido novo, aguardando a sua decisão. | Criado pela compra do cliente (ou do representante VendeMais). |
aceito | Você confirmou que vai atender. | Você — POST /pedidos/{id}/aceitar |
recusado | Você recusou (ou cancelou) o pedido, com motivo. | Você — POST /pedidos/{id}/recusar ou /cancelar |
entregue | Mercadoria entregue ao cliente. | Você — POST /pedidos/{id}/entregar |
recusado e guarda o motivo informado.Pedidos — listar com filtros
| Parâmetro | Descrição |
|---|---|
status | pendente, aceito, recusado ou entregue. Sem o parâmetro, retorna todos. |
data_inicio / data_fim | Intervalo da data de criação, formato YYYY-MM-DD. |
varejista | Filtra pelo nome (ou ID) do cliente — busca "contém". |
produto | Filtra por descrição de produto contida nos itens. |
page / page_size | Paginaçã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)
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
}
]
}
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)
Sem corpo. Marca o pedido como aceito.
{"motivo": "Estoque insuficiente para o item 7891234567890"}
Sem corpo. Marca como entregue (informe apenas após a entrega física — este evento também ativa clientes pré-cadastrados por representante).
{"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):
POST /auth/login e guarde o access_token.GET /pedidos/?status=pendente. Se a lista vier vazia, encerre a execução.GET /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.POST /pedidos/{id}/aceitar) ou recuse com motivo (POST /pedidos/{id}/recusar).POST /pedidos/{id}/entregar. O cliente vê o status atualizado no app na hora.POST /produtos/bulk.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ódigo | Significado | O que fazer |
|---|---|---|
401 | Token ausente, inválido ou expirado. | Faça login novamente (ou use /auth/refresh) e repita a chamada. |
403 | Conta inativa. | Fale com o administrador da KIPI. |
404 | Recurso não encontrado (ou não pertence à sua conta). | Confira o id utilizado. |
422 | Corpo/parâmetros inválidos. | A resposta detalha campo a campo o que está errado — ajuste e reenvie. |
400 | Regra de negócio (ex.: recusar sem motivo). | Veja a mensagem em detail. |
- Consulte por
status=pendenteem intervalos de 5 a 15 minutos — não é necessário consultar a cada segundo. - O
/produtos/bulké idempotente: reenviar o mesmo catálogo não duplica produtos. - Guarde o
refresh_tokenapenas se for manter processos longos; para rotinas curtas, faça login a cada execução. - Dúvidas ou credenciais: fale com a KIPI pelo WhatsApp (51) 9852-7906.