Carga de custos de produtos pela API
A Wivo permite atualizar os custos dos seus produtos de forma programática por meio de um arquivo CSV enviado à API. Os custos são processados em segundo plano e você receberá uma notificação por e-mail quando o processo terminar.
Esta funcionalidade está disponível para contas com plano Pro.
Para que serve?
- Sincronizar custos automaticamente a partir do seu ERP, data warehouse ou sistema contábil
- Programar atualizações periódicas (diárias, semanais) sem intervenção manual
- Atualizar custos de milhares de produtos em uma única operação
Requisitos
- Conta Wivo com plano Pro
- API Key ativa (obtém-se a partir da seção Integrações na plataforma)
Base URL
https://api.wivoanalytics.com
Autenticação
Todas as solicitações devem incluir a API Key no seguinte header HTTP:
Ocp-Apim-Subscription-Key: SUA_API_KEY_AQUI
Solicitações sem API Key ou com chave inválida recebem 401 Unauthorized.
Importante: Sua API Key é um segredo. Não a compartilhe, não a inclua em código-fonte público nem a exponha em logs. Armazene-a em variáveis de ambiente ou em um gerenciador de segredos.
Como obter sua API Key?
- Entrar na Wivo — Acesse sua conta com seu usuário administrador.
- Ir para Integrações — No menu do canto superior direito, clique em “Integração com API”.
- Solicitar habilitação — Clique em “Solicitar habilitar API” e agende uma reunião com a equipe da Wivo para ativar seu acesso.
- Obter sua chave — Uma vez habilitada, sua API Key será exibida. É pessoal, secreta e está associada à sua conta.
Endpoints
| Método | Endpoint | Descrição |
|---|---|---|
POST | /costs/fill/csv | Carregar arquivo CSV com custos |
GET | /costs/fill-status | Consultar se há uma carga em curso |
GET | /costs/fill-history | Consultar histórico de cargas (últimos 7 dias) |
POST /costs/fill/csv
Content-Type: multipart/form-data
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
file | File | Sim | Arquivo CSV (máximo 10 MB) |
email | String | Sim | E-mail onde você receberá o resultado da carga |
username | String | Sim | Nome do usuário ou sistema que realiza a carga |
fromDate | String | Não | Data a partir da qual aplicar custos (YYYY-MM-DD). Se não for enviada, aplicam-se desde o primeiro dia do mês de 2 anos atrás |
Exemplos de código
cURL:
curl -X POST "https://api.wivoanalytics.com/costs/fill/csv" \
-H "Ocp-Apim-Subscription-Key: SUA_API_KEY_AQUI" \
-F "file=@costos.csv" \
-F "email=usuario@minhaempresa.com" \
-F "username=Pipeline de Custos" \
-F "fromDate=2024-01-01"
Python (requests):
import requests
url = "https://api.wivoanalytics.com/costs/fill/csv"
headers = {"Ocp-Apim-Subscription-Key": "SUA_API_KEY_AQUI"}
with open("costos.csv", "rb") as f:
files = {"file": ("costos.csv", f, "text/csv")}
data = {
"email": "usuario@minhaempresa.com",
"username": "Pipeline de Custos",
"fromDate": "2024-01-01",
}
response = requests.post(url, headers=headers, files=files, data=data)
print(response.status_code) # 202
print(response.json()) # {"processId": "a1b2c3d4-..."}
Node.js (axios):
const axios = require("axios");
const FormData = require("form-data");
const fs = require("fs");
const form = new FormData();
form.append("file", fs.createReadStream("costos.csv"));
form.append("email", "usuario@minhaempresa.com");
form.append("username", "Pipeline de Custos");
form.append("fromDate", "2024-01-01");
const response = await axios.post(
"https://api.wivoanalytics.com/costs/fill/csv",
form,
{ headers: { "Ocp-Apim-Subscription-Key": "SUA_API_KEY_AQUI", ...form.getHeaders() } }
);
console.log(response.data); // { processId: "a1b2c3d4-..." }
Resposta bem-sucedida — 202 Accepted
{ "processId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" }
O
processIdé um identificador de referência para sua carga. Você pode citá-lo ao contatar o suporte. Não é necessário para consultar o status — a API o resolve automaticamente a partir da sua API Key.
Respostas do servidor
| Código | Significado | Tentar novamente |
|---|---|---|
202 | Arquivo recebido, processamento iniciado | Não |
400 | Arquivo não é CSV ou dados inválidos | Não |
401 | API Key ausente ou inválida | Não |
403 | Plano Pro requerido para este recurso | Não |
409 | Já há uma carga em curso | Sim |
429 | Limite de solicitações excedido | Sim |
500 | Erro interno | Sim |
400 Bad Request:
{ "success": false, "error": "Este endpoint solo acepta archivos CSV" }
401 Unauthorized:
{ "success": false, "error": "Authentication required" }
409 Conflict:
{ "message": "En estos momentos estamos procesando tu planilla. Por favor, espere a que finalice antes de subir una nueva planilla." }
500 Internal Server Error:
{ "message": "Error al subir el archivo" }
GET /costs/fill-status
Consulta se sua conta tem uma carga de custos em curso. Só pode haver uma carga ativa por vez.
cURL:
curl "https://api.wivoanalytics.com/costs/fill-status" \
-H "Ocp-Apim-Subscription-Key: SUA_API_KEY_AQUI"
Com processo ativo:
{ "process": { "status": "in_progress" } }
Sem processo ativo (sua carga já terminou):
{ "process": null }
Se você receber
null, sua carga já terminou. Consulte o histórico para ver o resultado, ou verifique seu e-mail.
GET /costs/fill-history
Mostra suas cargas de custos dos últimos 7 dias com seu resultado.
cURL:
curl "https://api.wivoanalytics.com/costs/fill-history" \
-H "Ocp-Apim-Subscription-Key: SUA_API_KEY_AQUI"
Resposta:
{
"process": [
{
"processId": "a1b2c3d4-...",
"status": "success",
"title": "Planilla procesada correctamente",
"message": "La planilla de productos subida por Pipeline de Costos se ha cargado exitosamente.",
"relativeTime": "hace 2 horas"
}
]
}
Valores possíveis de status: success, failed, in_progress.
Especificação do arquivo CSV
| Propriedade | Valor |
|---|---|
| Codificação | UTF-8 (com ou sem BOM) |
| Separador | Vírgula (,) |
| Delimitador de texto | Aspas duplas (") |
| Fim de linha | CRLF ou LF |
| Primeira linha | Headers |
| Tamanho máximo | 10 MB |
Colunas obrigatórias
Se faltar alguma destas colunas, o arquivo inteiro será rejeitado:
| Coluna | Tipo | Descrição | Exemplo |
|---|---|---|---|
ID Cuenta | Texto | Identificador da conta no marketplace | 123456 |
ID Producto | Texto | Identificador do produto no marketplace | MLB001 |
Costo de producto (con IVA) | Numérico | Custo unitário com IVA | 1500.50 |
Os nomes das colunas são sensíveis a maiúsculas e acentos. A ordem não importa.
Colunas opcionais
Você pode incluir colunas adicionais para enriquecer a informação: Marketplace, Cuenta, SKU Producto, Nombre Producto, Producto Interno, SKU Producto Interno, Marca Interna e Categoría Interna. Se não forem incluídas, recebem valores padrão.
Nomes alternativos (legacy)
Para compatibilidade com planilhas antigas, aceitam-se:
ID Productequivale aID ProductoCostoequivale aCosto de producto (con IVA)
Formato do campo custo
| Você escreve | É interpretado como |
|---|---|
1500 | 1500.00 |
1500.50 | 1500.50 |
1500,50 | 1500.50 |
1.500,50 | 1500.50 |
Faixa válida: -99,999,999.99 a 99,999,999.99. Valores fora da faixa ou inválidos são armazenados como vazio.
Exemplos de arquivo CSV
Arquivo completo (todas as colunas):
Marketplace,Cuenta,ID Cuenta,SKU Producto,Nombre Producto,ID Producto,Costo de producto (con IVA),Producto Interno,SKU Producto Interno,Marca Interna,Categoría Interna
mercadolibre,Mi Tienda,123456,SKU-001,Camiseta Básica,MLB001,1500.50,Camiseta Genérica,INT-001,Nike,Ropa
mercadolibre,Mi Tienda,123456,SKU-002,"Pantalón Cargo, modelo 2024",MLB002,3200,Pantalón Genérico,INT-002,Adidas,Ropa
mercadolibre,Mi Tienda,123456,SKU-003,Zapatillas Running,MLB003,8500.00,Zapatillas Genéricas,INT-003,Puma,Calzado
Arquivo mínimo (apenas colunas obrigatórias):
ID Cuenta,ID Producto,Costo de producto (con IVA)
123456,MLB001,1500.50
123456,MLB002,3200
123456,MLB003,8500.00
Geração do CSV por código
Python (pandas):
import pandas as pd
df = pd.DataFrame({
"ID Cuenta": ["123456", "123456"],
"ID Producto": ["MLB001", "MLB002"],
"Costo de producto (con IVA)": [1500.50, 3200.00],
})
df.to_csv("costos.csv", index=False, encoding="utf-8")
Node.js:
const { stringify } = require("csv-stringify/sync");
const fs = require("fs");
const data = [
["ID Cuenta", "ID Producto", "Costo de producto (con IVA)"],
["123456", "MLB001", "1500.50"],
["123456", "MLB002", "3200.00"],
];
fs.writeFileSync("costos.csv", stringify(data), "utf-8");
Retentativas automáticas
Para os códigos 409, 429 e 500, use backoff exponencial:
| Parâmetro | Valor |
|---|---|
| Máximo de retentativas | 5 |
| Espera inicial | 30 segundos |
| Multiplicador | 2× |
| Espera máxima | 10 minutos |
| Tentativa | Espera |
|---|---|
| 1 | 30 segundos |
| 2 | 1 minuto |
| 3 | 2 minutos |
| 4 | 4 minutos |
| 5 | 8 minutos |
Para erros 409, consulte GET /costs/fill-status antes de tentar novamente para verificar se há um processo ativo.
Exemplo Python com retentativas:
import time, random, requests
API_KEY = "SUA_API_KEY_AQUI"
API_URL = "https://api.wivoanalytics.com/costs/fill/csv"
MAX_RETRIES = 5
def upload_costs(csv_path, form_data):
headers = {"Ocp-Apim-Subscription-Key": API_KEY}
for attempt in range(1, MAX_RETRIES + 1):
with open(csv_path, "rb") as f:
files = {"file": ("costos.csv", f, "text/csv")}
response = requests.post(API_URL, headers=headers, files=files, data=form_data)
if response.status_code == 202:
return response.json()
if response.status_code in (400, 401):
raise Exception(f"Error {response.status_code}: {response.json()}")
if response.status_code in (409, 429, 500):
delay = min(30 * (2 ** (attempt - 1)), 600)
time.sleep(delay + random.uniform(-5, 5))
raise Exception("Foi excedido o número máximo de retentativas")
Tempos de processamento
| Produtos | Tempo aproximado |
|---|---|
| ~500 | Segundos |
| ~2.000 | 1 a 2 minutos |
| ~10.000 | 5 a 10 minutos |
Regras de negócio
- Um processo por vez — Só pode haver uma carga ativa por conta. Se você enviar um arquivo enquanto outro está sendo processado, receberá um erro
409. - Linhas incompletas — As linhas sem
ID ProductoouID Cuentasão ignoradas; o restante é processado normalmente. - Custos inválidos — Valores vazios, inválidos ou fora da faixa são armazenados como vazio (não rejeitam o arquivo).
- Processamento em lotes — Os produtos são processados em grupos de 500.
- Identificação por nome — As colunas são identificadas por nome, não por posição.
Perguntas frequentes
Posso enviar apenas as 3 colunas obrigatórias? Sim. As colunas opcionais são preenchidas com valores padrão.
A ordem das colunas importa? Não.
O 202 garante que os custos foram atualizados?
Não, apenas confirma que o arquivo foi recebido e o processamento começou. Você receberá um e-mail quando o processo terminar. Também pode consultar o status com GET /costs/fill-status ou ver o histórico com GET /costs/fill-history.
O que faz o parâmetro fromDate?
Define a partir de que data se aplicam os custos. Se não for enviado, aplicam-se desde o primeiro dia do mês de 2 anos atrás.
É a mesma API Key que uso para a API de dados da Wivo? Sim.
Tem dúvidas? Escreva para contacto@wivoanalytics.com ou acesse a plataforma em app.wivoanalytics.com.
Ao contatar o suporte, inclua: processId (se tiver), código HTTP recebido, e data e hora do erro.