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?

  1. Entrar na Wivo — Acesse sua conta com seu usuário administrador.
  2. Ir para Integrações — No menu do canto superior direito, clique em “Integração com API”.
  3. Solicitar habilitação — Clique em “Solicitar habilitar API” e agende uma reunião com a equipe da Wivo para ativar seu acesso.
  4. Obter sua chave — Uma vez habilitada, sua API Key será exibida. É pessoal, secreta e está associada à sua conta.

Endpoints

MétodoEndpointDescrição
POST/costs/fill/csvCarregar arquivo CSV com custos
GET/costs/fill-statusConsultar se há uma carga em curso
GET/costs/fill-historyConsultar histórico de cargas (últimos 7 dias)

POST /costs/fill/csv

Content-Type: multipart/form-data

CampoTipoObrigatórioDescrição
fileFileSimArquivo CSV (máximo 10 MB)
emailStringSimE-mail onde você receberá o resultado da carga
usernameStringSimNome do usuário ou sistema que realiza a carga
fromDateStringNãoData 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ódigoSignificadoTentar novamente
202Arquivo recebido, processamento iniciadoNão
400Arquivo não é CSV ou dados inválidosNão
401API Key ausente ou inválidaNão
403Plano Pro requerido para este recursoNão
409Já há uma carga em cursoSim
429Limite de solicitações excedidoSim
500Erro internoSim

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

PropriedadeValor
CodificaçãoUTF-8 (com ou sem BOM)
SeparadorVírgula (,)
Delimitador de textoAspas duplas (")
Fim de linhaCRLF ou LF
Primeira linhaHeaders
Tamanho máximo10 MB

Colunas obrigatórias

Se faltar alguma destas colunas, o arquivo inteiro será rejeitado:

ColunaTipoDescriçãoExemplo
ID CuentaTextoIdentificador da conta no marketplace123456
ID ProductoTextoIdentificador do produto no marketplaceMLB001
Costo de producto (con IVA)NuméricoCusto unitário com IVA1500.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 Product equivale a ID Producto
  • Costo equivale a Costo de producto (con IVA)

Formato do campo custo

Você escreveÉ interpretado como
15001500.00
1500.501500.50
1500,501500.50
1.500,501500.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âmetroValor
Máximo de retentativas5
Espera inicial30 segundos
Multiplicador
Espera máxima10 minutos
TentativaEspera
130 segundos
21 minuto
32 minutos
44 minutos
58 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

ProdutosTempo aproximado
~500Segundos
~2.0001 a 2 minutos
~10.0005 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 Producto ou ID Cuenta sã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.