API de pedidos (beta)

Beta. A API está em beta: o contrato pode mudar, e avisamos antes.

Se o seu e-commerce é de desenvolvimento próprio, não existe um conector que baixe os seus pedidos. Com esta API, você mesmo os envia a partir do seu sistema, e eles aparecem na Wivo junto com os dos seus marketplaces: em Vendas, em Rentabilidade e no Cadastro de produtos.

Você envia lotes de pedidos para POST /orders. Cada pedido vai completo, com todas as suas linhas, e a Wivo calcula o resto: o custo a partir do seu Cadastro, e o frete e a comissão do gateway de pagamento distribuídos entre as linhas.

Está incluída no plano Pro: não é um add-on. Por enquanto é apenas para contas do Chile, com valores em pesos chilenos (CLP).

Os nomes das telas e botões aparecem em espanhol, como na app da Wivo. As mensagens de erro da API também vêm em espanhol.

Para que serve?

  • Ver as vendas da sua loja própria nos mesmos painéis que as dos seus marketplaces
  • Calcular a rentabilidade com o custo do seu Cadastro, o custo de frete e a comissão do seu gateway de pagamento
  • Manter em dia cancelamentos e devoluções: você reenvia o pedido com o novo status e a Wivo o substitui

Requisitos

  • Conta Wivo com plano Pro, do Chile
  • Sua API Key, da tela Integración con API
  • O source_id da sua fonte Tienda propia (API) (loja própria via API)

Você não precisa do add-on da API de dados: este recurso está incluído no plano Pro.

Como obter sua API Key?

  1. Entre na Wivo com o seu usuário.
  2. Abra Integración con API no menu, ou acesse direto app.wivoanalytics.com/u/0/#/api.
  3. Copie sua API Key. Com o plano Pro você a obtém ali mesmo, sem o add-on da API de dados. É pessoal, secreta e está associada à sua conta.

É a mesma chave para todos os recursos da API da Wivo.

Como obter seu source_id?

O source_id identifica a sua fonte Tienda propia (API): é a “integração” que recebe os seus pedidos. Você mesmo a cria, sem credenciais:

  1. Abra Integraciones (Integrações) no menu, ou acesse app.wivoanalytics.com/u/0/#/marketplaces/accounts.
  2. Clique em Agregar (Adicionar) e, em Tiendas Ecommerce, escolha Tienda propia (API) · Beta. Não são pedidas credenciais: a fonte é criada ao escolhê-la.
  3. Copie o source_id que aparece na tela.

Depois você continua a vê-lo em Integraciones, junto à sua Tienda propia (API). Cada conta tem apenas uma: se você a escolher de novo, a Wivo mostra a que você já tem.

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.

POST /orders

Recebe um lote de até 100 pedidos, em JSON (Content-Type: application/json).

O que você precisa saber antes de integrar

  • A unidade é o pedido completo. Cada vez que você envia um pedido, ele traz todas as suas linhas, não apenas a que mudou. Reenviar o mesmo order_id substitui o pedido inteiro: uma linha que não vem, desaparece. Por isso reenviar nunca duplica.
  • purchase_date não muda. É a data da compra e se mantém igual em cada reenvio. Se você a mover mais de 5 dias, o pedido aparece duas vezes.
  • Tudo ou nada. Se um único pedido do lote tiver um erro, nenhum entra. A resposta 422 diz qual campo de qual pedido falhou, para que você corrija e reenvie o lote completo.
  • 202 quer dizer recebido, não inserido. Seus pedidos aparecem na app alguns minutos depois.
  • Valores em CLP, com IVA incluído, tal como o comprador os vê.
  • O custo do produto não vai no pedido. Ele é carregado no Cadastro, como em qualquer outro canal (veja a receita).

Corpo

CampoTipoObrigatórioDescrição
source_idUUIDSimO source_id da sua Tienda propia (API). Tem que ser da mesma conta que a API Key
ordersListaSimEntre 1 e 100 pedidos

Campos de cada pedido

CampoTipoObrigatórioDescrição
order_idTexto (id)SimID do pedido na sua loja. Único por fonte e dentro do lote. Reenviá-lo substitui o pedido completo
purchase_dateDataSimData da compra. Não muda entre envios
last_update_dateDataSimÚltima modificação do pedido. Não pode ser anterior a purchase_date
currencyTextoSimSempre "CLP"
payment_statusTextoSimpaid ou unpaid
shipment_statusTextoNãoStatus do envio (veja status). Padrão noinformation
shopperObjetoNãoO comprador: id (obrigatório dentro do objeto) e name
shipping_costValorNãoO que custa para você enviar o pedido, não o que o comprador paga
shipping_incomeValorNãoO que o comprador pagou pelo frete, com IVA. Se não vier, é 0
payment_feeValorNãoComissão do gateway de pagamento (Webpay, Mercado Pago etc.) do pedido
itemsListaSimTodas as linhas do pedido, entre 1 e 200

Campos de cada linha

CampoTipoObrigatórioDescrição
product_idTexto (id)SimID do produto na sua loja. É o ID Producto com que ele aparece no Cadastro
skuTexto (id)NãoSKU do produto
nameTextoSimNome do produto
variantObjetoNãoA variante: id (obrigatório dentro do objeto) e name
brandTextoNãoMarca
categoryTextoNãoCategoria
quantityInteiroSimUnidades, de 1 a 100.000
unit_priceValorSimPreço unitário de lista, com IVA, antes do desconto
discountValorNãoDesconto total da linha (não unitário), com IVA. Padrão 0. Não pode superar unit_price × quantity
statusTextoSimStatus da linha: paid, canceled, returned ou pending

Se você não enviar variant, brand, category ou shopper, a Wivo os mostra como “Sin información” (sem informação).

Status

Só são aceitos os status da Wivo. Se a sua loja usa outros nomes, converta-os antes de enviar: um status que não está na lista rejeita o lote.

items[].status, status da linha:

ValorSignificado
paidPaga
canceledCancelada
returnedDevolvida
pendingPagamento pendente. A Wivo a conta como não concretizada, igual a uma cancelada, até você reenviar o pedido com a linha em paid

payment_status, status de pagamento do pedido: paid (pago) ou unpaid (não pago).

shipment_status, status do envio do pedido:

ValorSignificado
noinformationSem informação (padrão)
inpreparationEm preparação
intransitEm trânsito
deliveredEntregue
returnedDevolvido
returninprocessDevolução em andamento
inmediationEm mediação
faileddeliveryEntrega malsucedida
notrequiredNão requer envio
canceledCancelado

Datas

As datas vão no formato RFC 3339 com offset explícito: 2026-09-24T15:30:00-03:00 ou 2026-09-24T18:30:00Z. Sem offset, são rejeitadas.

  • Separador T entre data e hora (não um espaço)
  • Segundos obrigatórios; fração de segundo opcional (15:30:00.123-03:00)
  • Offset Z ou ±HH:MM. Não são aceitos -03 nem -0300

Por que o offset? O Chile muda de horário duas vezes por ano, e uma hora local sem fuso é ambígua na mudança: pode mover um pedido de dia sem que ninguém perceba.

Além disso, purchase_date não pode estar mais de 24 horas no futuro nem ter mais de 2 anos.

Valores

Todos os valores vão em CLP, com IVA incluído, e não podem ser negativos.

  • O total pago de uma linha é unit_price × quantity − discount.
  • shipping_cost é o seu custo de frete; shipping_income, o que o comprador pagou pelo frete. O seu custo líquido de frete é a diferença. Não misture a receita em shipping_cost: isso inverteria o sentido do número na sua rentabilidade.
  • payment_fee é a comissão do gateway. Se você não a enviar, a comissão fica como desconhecida.
  • A Wivo distribui shipping_cost, shipping_income e payment_fee entre as linhas do pedido em proporção ao total de cada linha: a linha mais cara carrega mais.

Por exemplo, no pedido WEB-1001 do exemplo válido as linhas somam $23.980 e $8.990 (total $32.970). O frete de $3.990 fica em $2.902,04 para a primeira e $1.087,96 para a segunda.

Identificadores e textos

  • Os ids (order_id, product_id, sku, variant.id, shopper.id) têm até 64 caracteres e não podem ter aspas simples (') nem caracteres de controle.
  • Os textos (name, brand, category, variant.name, shopper.name) têm até 255 caracteres e aceitam aspas simples: “María O’Higgins” é válido.
  • O source_id é um UUID de 36 caracteres, com hifens. Tanto faz se vier em maiúsculas ou minúsculas.
  • Um order_id não pode se repetir dentro do mesmo lote.

Exemplos

cURL

curl -X POST "https://api.wivoanalytics.com/orders" \
  -H "Ocp-Apim-Subscription-Key: SUA_API_KEY_AQUI" \
  -H "Content-Type: application/json" \
  -d '{
    "source_id": "SEU_SOURCE_ID_AQUI",
    "orders": [
      {
        "order_id": "WEB-1001",
        "purchase_date": "2026-09-20T15:30:00-03:00",
        "last_update_date": "2026-09-20T16:05:00-03:00",
        "currency": "CLP",
        "payment_status": "paid",
        "shipment_status": "delivered",
        "shipping_cost": 3990,
        "shipping_income": 2990,
        "payment_fee": 1250,
        "items": [
          {
            "product_id": "P-10",
            "sku": "POL-AZ-M",
            "name": "Polera azul",
            "quantity": 2,
            "unit_price": 12990,
            "discount": 2000,
            "status": "paid"
          }
        ]
      }
    ]
  }'

Se os seus dados tiverem aspas simples (por exemplo, um comprador “O’Higgins”), no terminal envie o corpo a partir de um arquivo, assim as aspas não cortam o comando:

curl -X POST "https://api.wivoanalytics.com/orders" \
  -H "Ocp-Apim-Subscription-Key: SUA_API_KEY_AQUI" \
  -H "Content-Type: application/json" \
  --data @pedidos.json

Python (requests)

import requests

lote = {
    "source_id": "SEU_SOURCE_ID_AQUI",
    "orders": [
        {
            "order_id": "WEB-1001",
            "purchase_date": "2026-09-20T15:30:00-03:00",
            "last_update_date": "2026-09-20T16:05:00-03:00",
            "currency": "CLP",
            "payment_status": "paid",
            "items": [
                {"product_id": "P-10", "name": "Polera azul", "quantity": 2,
                 "unit_price": 12990, "discount": 2000, "status": "paid"},
            ],
        }
    ],
}

response = requests.post(
    "https://api.wivoanalytics.com/orders",
    headers={"Ocp-Apim-Subscription-Key": "SUA_API_KEY_AQUI"},
    json=lote,
    timeout=30,
)
corpo = response.json()

if response.status_code == 202:
    print(f"{corpo['accepted']} pedidos recebidos")
elif response.status_code == 422:
    for erro in corpo["errors"]:
        print(f"Pedido {erro['order_id']} · {erro['field']}: {erro['error']}")
else:
    print(response.status_code, corpo)

Node.js (fetch)

const lote = {
  source_id: "SEU_SOURCE_ID_AQUI",
  orders: [
    {
      order_id: "WEB-1001",
      purchase_date: "2026-09-20T15:30:00-03:00",
      last_update_date: "2026-09-20T16:05:00-03:00",
      currency: "CLP",
      payment_status: "paid",
      items: [
        { product_id: "P-10", name: "Polera azul", quantity: 2,
          unit_price: 12990, discount: 2000, status: "paid" },
      ],
    },
  ],
};

const response = await fetch("https://api.wivoanalytics.com/orders", {
  method: "POST",
  headers: {
    "Ocp-Apim-Subscription-Key": "SUA_API_KEY_AQUI",
    "Content-Type": "application/json",
  },
  body: JSON.stringify(lote),
});
const corpo = await response.json();

if (response.status === 202) {
  console.log(`${corpo.accepted} pedidos recebidos`);
} else if (response.status === 422) {
  for (const e of corpo.errors) console.error(`Pedido ${e.order_id} · ${e.field}: ${e.error}`);
} else {
  console.error(response.status, corpo);
}

Exemplo válido completo

Dois pedidos: um pago e entregue, com todos os campos opcionais, e um não pago com sua única linha cancelada, só com os obrigatórios.

{
  "source_id": "3f2b6c1e-8a4d-4c2e-9b7a-1d2e3f4a5b6c",
  "orders": [
    {
      "order_id": "WEB-1001",
      "purchase_date": "2026-09-20T15:30:00-03:00",
      "last_update_date": "2026-09-20T16:05:00-03:00",
      "currency": "CLP",
      "payment_status": "paid",
      "shipment_status": "delivered",
      "shopper": {"id": "C-77", "name": "María O'Higgins"},
      "shipping_cost": 3990,
      "payment_fee": 1250,
      "items": [
        {"product_id": "P-10", "sku": "POL-AZ-M", "name": "Polera azul", "variant": {"id": "P-10-M", "name": "M"}, "brand": "Marca Propia", "category": "Poleras", "quantity": 2, "unit_price": 12990, "discount": 2000, "status": "paid"},
        {"product_id": "P-22", "name": "Gorro de lana", "quantity": 1, "unit_price": 8990, "status": "paid"}
      ]
    },
    {
      "order_id": "WEB-1002",
      "purchase_date": "2026-09-21T10:00:00-03:00",
      "last_update_date": "2026-09-22T09:00:00-03:00",
      "currency": "CLP",
      "payment_status": "unpaid",
      "items": [
        {"product_id": "P-10", "name": "Polera azul", "quantity": 1, "unit_price": 12990, "status": "canceled"}
      ]
    }
  ]
}

Exemplo inválido

Cinco erros em um único pedido: data sem offset, um status de pagamento que não é da Wivo (pagado), quantidade 0, preço negativo e um campo que não existe no contrato (costo, que além disso é justamente o que não se envia).

{
  "source_id": "3f2b6c1e-8a4d-4c2e-9b7a-1d2e3f4a5b6c",
  "orders": [
    {
      "order_id": "WEB-2001",
      "purchase_date": "2026-09-20T15:30:00",
      "last_update_date": "2026-09-20T16:05:00-03:00",
      "currency": "CLP",
      "payment_status": "pagado",
      "items": [
        {"product_id": "P-10", "name": "Polera azul", "quantity": 0, "unit_price": -5, "status": "paid", "costo": 4000}
      ]
    }
  ]
}

A resposta é um 422 com um erro por problema, e nenhum pedido entra:

{
  "errors": [
    {"index": 0, "order_id": "WEB-2001", "field": "/orders/0/purchase_date", "error": "Debe ser una fecha RFC 3339 con offset explícito, p. ej. 2026-09-24T15:30:00-03:00."},
    {"index": 0, "order_id": "WEB-2001", "field": "/orders/0/payment_status", "error": "Debe ser uno de: paid, unpaid."},
    {"index": 0, "order_id": "WEB-2001", "field": "/orders/0/items/0/costo", "error": "El campo 'costo' no existe en el contrato v1."},
    {"index": 0, "order_id": "WEB-2001", "field": "/orders/0/items/0/quantity", "error": "Debe ser mayor o igual a 1."},
    {"index": 0, "order_id": "WEB-2001", "field": "/orders/0/items/0/unit_price", "error": "Debe ser mayor o igual a 0."}
  ],
  "correlation_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}

JSON Schema v1

É o schema com o qual a API valida cada lote (JSON Schema draft 2020-12). Você pode usá-lo para validar seus lotes antes de enviá-los. As descrições internas do schema estão em espanhol. As regras que o schema não consegue expressar estão mais abaixo.

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://api.wivoanalytics.com/schemas/orders-v1.schema.json",
  "title": "Wivo — lote de órdenes v1 (Tienda propia API)",
  "description": "Cuerpo de POST /orders (contrato v1).",
  "type": "object",
  "additionalProperties": false,
  "required": ["source_id", "orders"],
  "properties": {
    "source_id": {
      "description": "UUID (identifier) de la fuente 'Tienda propia (API)' del tenant. Se verifica contra el tenant de la API key.",
      "type": "string",
      "format": "uuid"
    },
    "orders": {
      "type": "array",
      "minItems": 1,
      "maxItems": 100,
      "items": { "$ref": "#/$defs/order" }
    }
  },
  "$defs": {
    "text": {
      "type": "string",
      "minLength": 1,
      "maxLength": 255,
      "pattern": "^[^\\u0000-\\u001f]*$"
    },
    "id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 64,
      "description": "Sin caracteres de control ni comilla simple.",
      "pattern": "^[^\\u0000-\\u001f']*$"
    },
    "amount": {
      "type": "number",
      "minimum": 0,
      "maximum": 100000000000
    },
    "datetime": {
      "description": "ISO 8601 / RFC 3339 CON offset explícito (p. ej. 2026-09-24T15:30:00-03:00). Sin offset se rechaza.",
      "type": "string",
      "format": "date-time"
    },
    "order": {
      "type": "object",
      "additionalProperties": false,
      "required": ["order_id", "purchase_date", "last_update_date", "currency", "payment_status", "items"],
      "properties": {
        "order_id": {
          "$ref": "#/$defs/id",
          "description": "ID de la orden en la tienda. Único por fuente. Reenviar el mismo order_id REEMPLAZA la orden completa."
        },
        "purchase_date": {
          "$ref": "#/$defs/datetime",
          "description": "Fecha de compra. INMUTABLE: si cambia más de 5 días respecto de lo ya enviado, la orden se duplica."
        },
        "last_update_date": { "$ref": "#/$defs/datetime" },
        "currency": { "const": "CLP" },
        "payment_status": { "enum": ["paid", "unpaid"] },
        "shipment_status": {
          "enum": ["noinformation", "inpreparation", "intransit", "delivered", "returned", "returninprocess", "inmediation", "faileddelivery", "notrequired", "canceled"],
          "default": "noinformation"
        },
        "shopper": {
          "type": "object",
          "additionalProperties": false,
          "required": ["id"],
          "properties": {
            "id": { "$ref": "#/$defs/id" },
            "name": { "$ref": "#/$defs/text" }
          }
        },
        "shipping_cost": {
          "$ref": "#/$defs/amount",
          "description": "Lo que le cuesta AL SELLER despachar la orden (no lo que paga el comprador). Wivo lo prorratea entre las líneas por su total."
        },
        "shipping_income": {
          "$ref": "#/$defs/amount",
          "description": "Lo que PAGÓ EL COMPRADOR por el despacho, IVA incluido. Va a shipping_import, prorrateado entre las líneas por su total. El costo neto de despacho del seller = shipping_cost − shipping_income."
        },
        "payment_fee": {
          "$ref": "#/$defs/amount",
          "description": "Comisión de la pasarela de pago de la orden (Webpay, Mercado Pago, etc.). Va a market_fee, prorrateada entre las líneas por su total."
        },
        "items": {
          "type": "array",
          "minItems": 1,
          "maxItems": 200,
          "description": "TODAS las líneas de la orden, siempre. Una actualización trae la orden completa.",
          "items": { "$ref": "#/$defs/item" }
        }
      }
    },
    "item": {
      "type": "object",
      "additionalProperties": false,
      "required": ["product_id", "name", "quantity", "unit_price", "status"],
      "properties": {
        "product_id": {
          "$ref": "#/$defs/id",
          "description": "ID del producto en la tienda. Es el 'ID Producto' con el que aparece en el Maestro de Wivo."
        },
        "sku": { "$ref": "#/$defs/id" },
        "name": { "$ref": "#/$defs/text" },
        "variant": {
          "type": "object",
          "additionalProperties": false,
          "required": ["id"],
          "properties": {
            "id": { "$ref": "#/$defs/id" },
            "name": { "$ref": "#/$defs/text" }
          }
        },
        "brand": { "$ref": "#/$defs/text" },
        "category": { "$ref": "#/$defs/text" },
        "quantity": { "type": "integer", "minimum": 1, "maximum": 100000 },
        "unit_price": {
          "$ref": "#/$defs/amount",
          "description": "Precio unitario de lista, IVA incluido, ANTES del descuento."
        },
        "discount": {
          "$ref": "#/$defs/amount",
          "default": 0,
          "description": "Descuento TOTAL de la línea (no unitario), IVA incluido. No puede superar unit_price × quantity."
        },
        "status": { "enum": ["paid", "canceled", "returned", "pending"] }
      }
    }
  }
}

Regras que o schema não expressa

A API também rejeita com 422:

  1. Um order_id repetido dentro do mesmo lote.
  2. Um discount maior que unit_price × quantity.
  3. Uma purchase_date mais de 24 horas no futuro ou com mais de 2 anos.
  4. Uma last_update_date anterior a purchase_date.
  5. Datas e UUIDs fora do formato estrito: os format date-time e uuid são validados de verdade. Data com separador T (não espaço), segundos obrigatórios, fração opcional e offset Z ou ±HH:MM; o T e o Z também são aceitos em minúscula. UUID canônico de 36 caracteres, sem prefixo urn:uuid: nem chaves, em maiúsculas ou minúsculas.

Se você valida com uma biblioteca de JSON Schema, ative a validação de formatos (em Python, FormatChecker; em Node, ajv-formats): sem ela, uma data sem offset passaria na sua validação e a API a rejeitaria.

Respostas do servidor

Toda resposta da API traz um correlation_id. Guarde-o: é o que nos permite rastrear um envio se você nos escrever.

CódigoSignificadoTentar de novo
202Lote recebido. Os pedidos aparecem na app alguns minutos depoisNão
400O corpo está vazio ou não é um JSON válidoNão, corrija o corpo
401API Key ausente ou inválidaNão
403Conta sem plano Pro, assinatura revogada, ou um source_id que não é uma Tienda propia (API) ativa da sua conta. Também quando se esgota o limite diárioNão
413Mais de 100 pedidos ou mais de 1 MB no loteNão: divida o lote
422Lote inválido. Nenhum pedido entrouNão: corrija e reenvie o lote completo
429Você superou as 30 solicitações por minutoSim, depois do que indicar o header Retry-After
503Não conseguimos receber o lote neste momento (retryable: true)Sim, o mesmo lote

202 Accepted

{
  "accepted": 1,
  "order_ids": ["WEB-1001"],
  "dag_run_id": "tpapi__3f2b6c1e-8a4d-4c2e-9b7a-1d2e3f4a5b6c__f5610004e788a9df4b644366ee7112b4ffd54eb640d2d2eed526b5e0fd874f31",
  "duplicate": false,
  "correlation_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
CampoDescrição
acceptedQuantidade de pedidos recebidos
order_idsOs order_id recebidos, na ordem do lote
dag_run_idIdentificador do processamento do lote. Cite-o se nos escrever sobre um envio
duplicatetrue se já tínhamos recebido exatamente este mesmo lote: ele não é processado duas vezes

202 quer dizer que recebemos o lote, não que os pedidos já estejam nos seus relatórios: eles aparecem na app alguns minutos depois.

422 Unprocessable Entity

Cada erro traz:

CampoDescrição
indexPosição do pedido em orders (a partir de 0). null se o erro é do lote, por exemplo em /source_id
order_idO order_id desse pedido, ou null se não veio ou não é válido
fieldJSON Pointer para o campo com erro, por exemplo /orders/0/items/1/unit_price. Um campo que sobra aponta para esse campo: /orders/0/items/0/costo
errorO que está errado (em espanhol)

A lista traz no máximo 100 erros. Se havia mais, a resposta acrescenta "truncated": true. O exemplo completo está em Exemplo inválido.

413 Payload Too Large

{
  "error": "El lote trae 101 órdenes y el máximo por request es 100. Divide el envío en lotes de hasta 100 órdenes.",
  "max_orders": 100,
  "correlation_id": "a1b2c3d4-..."
}

Se o lote pesar mais de 1 MB, a resposta traz "max_bytes": 1048576 em vez de max_orders. Nos dois casos, reenviar o mesmo lote não vai funcionar: divida-o.

403 Forbidden

{
  "error": "La fuente '3f2b6c1e-8a4d-4c2e-9b7a-1d2e3f4a5b6c' no es una fuente 'Tienda propia (API)' activa de tu cuenta.",
  "correlation_id": "a1b2c3d4-..."
}

503 Service Unavailable

{
  "error": "No pudimos recibir el lote en este momento. Reintenta el mismo lote: si el contenido es idéntico, Wivo reconoce el reintento y no lo procesa dos veces.",
  "retryable": true,
  "correlation_id": "a1b2c3d4-..."
}

Limites de uso

  • 100 pedidos por solicitação, e até 200 linhas por pedido
  • 1 MB por solicitação (1.048.576 bytes)
  • 30 solicitações por minuto por API Key
  • 5.000 solicitações por dia

Passar de 100 pedidos ou de 1 MB retorna 413; de 30 solicitações por minuto, 429; e esgotar as 5.000 do dia, 403 até a cota ser renovada.

Com lotes de 100 pedidos, 30 solicitações por minuto são 3.000 pedidos por minuto. Enviar um lote a cada 2 segundos mantém você abaixo do limite.

Novas tentativas e idempotência

Reenviar é seguro. Há duas garantias, e juntas cobrem qualquer nova tentativa:

  • O mesmo lote não é processado duas vezes. Se você reenviar exatamente o mesmo conteúdo (mesmo que mude a ordem das chaves ou os espaços), a API responde 202 com "duplicate": true e o mesmo dag_run_id.
  • Reenviar um pedido o substitui. Se o conteúdo mudou, é um lote novo, e cada order_id substitui a sua versão anterior. Nunca duplica.

O que fazer de acordo com a resposta:

RespostaO que fazer
503 com retryable: trueTente de novo o mesmo lote, com espera crescente (2, 4, 8… segundos)
429Espere os segundos do header Retry-After e tente de novo
Sem resposta (timeout, queda de rede)Tente de novo o mesmo lote: se ele já tinha chegado, responde duplicate: true
400, 401, 403, 413, 422Não tente de novo igual: corrija primeiro. Repetir o mesmo lote dá o mesmo erro

Receitas

Enviar muitos pedidos, com novas tentativas

Divida seus pedidos em lotes de 100, envie-os em um ritmo que respeite o limite por minuto e tente de novo apenas o que se resolve tentando de novo.

import time
import requests

URL = "https://api.wivoanalytics.com/orders"
HEADERS = {"Ocp-Apim-Subscription-Key": "SUA_API_KEY_AQUI"}
SOURCE_ID = "SEU_SOURCE_ID_AQUI"


def enviar_lote(pedidos, tentativas=5):
    lote = {"source_id": SOURCE_ID, "orders": pedidos}
    espera = 2
    for tentativa in range(tentativas):
        try:
            response = requests.post(URL, headers=HEADERS, json=lote, timeout=30)
        except requests.RequestException:
            response = None  # sem resposta: reenviar o mesmo lote é seguro

        if response is not None:
            if response.status_code == 202:
                return response.json()
            if response.status_code == 429:
                espera = int(response.headers.get("Retry-After", espera))
            elif response.status_code != 503:
                # 400, 401, 403, 413 e 422 não se resolvem tentando de novo
                raise RuntimeError(f"Lote rejeitado ({response.status_code}): {response.text}")

        time.sleep(espera)
        espera = min(espera * 2, 60)

    raise RuntimeError("Não foi possível enviar o lote: tente mais tarde com o mesmo conteúdo")


pedidos = [...]  # os pedidos da sua loja, cada um completo

for i in range(0, len(pedidos), 100):
    resultado = enviar_lote(pedidos[i:i + 100])
    print(resultado["accepted"], "pedidos recebidos", "(já estavam)" if resultado["duplicate"] else "")
    time.sleep(2)  # 30 solicitações por minuto

Se um lote de 100 pedidos com muitas linhas pesar mais de 1 MB, a API responde 413 com max_bytes: use lotes menores.

Atualizar um pedido: cancelamento ou devolução

Reenvie o pedido completo, com o mesmo order_id e a mesma purchase_date, as linhas no novo status e uma last_update_date nova. Por exemplo, se o comprador devolveu o gorro do pedido WEB-1001:

{
  "source_id": "SEU_SOURCE_ID_AQUI",
  "orders": [
    {
      "order_id": "WEB-1001",
      "purchase_date": "2026-09-20T15:30:00-03:00",
      "last_update_date": "2026-09-25T11:00:00-03:00",
      "currency": "CLP",
      "payment_status": "paid",
      "shipment_status": "delivered",
      "shipping_cost": 3990,
      "payment_fee": 1250,
      "items": [
        {"product_id": "P-10", "name": "Polera azul", "quantity": 2, "unit_price": 12990, "discount": 2000, "status": "paid"},
        {"product_id": "P-22", "name": "Gorro de lana", "quantity": 1, "unit_price": 8990, "status": "returned"}
      ]
    }
  ]
}

A camiseta (Polera azul) vai igual, mesmo sem ter mudado: se você a omitir, essa linha desaparece da Wivo.

Carregar o custo dos seus produtos

O custo não vai no pedido. Os produtos dos seus pedidos aparecem no Cadastro com Marketplace “Tienda propia”, e ali você carrega o custo como em qualquer outro canal: com a planilha do Cadastro na app, ou pela API.

Para fazer isso pela API, leia os produtos da sua loja que ainda não têm custo com o Cadastro de produtos pela API, filtrando pelo seu source_id (é o ID Cuenta dos seus produtos):

curl "https://api.wivoanalytics.com/master/products?source_id=SEU_SOURCE_ID_AQUI&withoutCost=true" \
  -H "Ocp-Apim-Subscription-Key: SUA_API_KEY_AQUI"

E devolva os custos com a carga de custos pela API. O product_id que você envia em cada linha é o ID Producto do Cadastro.

Perguntas frequentes

Quanto tempo meus pedidos demoram para aparecer na Wivo? Alguns minutos depois do 202. O 202 confirma que recebemos o lote; o processamento vem depois.

Como sei que meus pedidos estão chegando? Em Integraciones, a sua Tienda propia (API) mostra quando chegou o último pedido. Se ainda não chegou nenhum, ela indica isso.

O que acontece se recebi um 202 mas os pedidos não aparecem? Nesta versão não existe um endpoint para consultar o status de um lote. Se depois de um tempo você não os vir, escreva para nós pelo chat da app ou para soporte@wivoanalytics.com com o correlation_id e o dag_run_id da resposta, e verificamos.

O que acontece se eu enviar o mesmo lote duas vezes? Nada de ruim. A API responde 202 com "duplicate": true e o lote não é processado duas vezes.

Posso enviar só a linha que mudou? Não. Cada envio traz o pedido completo, porque reenviar um order_id substitui o pedido inteiro: uma linha que não vem, desaparece.

Posso corrigir a data de compra de um pedido? Evite: purchase_date tem que ser sempre a mesma. Se você a mover mais de 5 dias, o pedido aparece duas vezes.

Posso apagar um pedido? Não nesta versão. Reenviá-lo com as linhas em canceled muda o seu status, mas não o apaga.

Posso enviar o custo dos produtos no pedido? Não, e um campo costo rejeita o lote. O custo fica no Cadastro, como em todos os seus canais: assim há uma única fonte de verdade. Veja Carregar o custo dos seus produtos.

Por que o meu order_id com aspas simples dá erro? Os ids não aceitam aspas simples, para que o order_id fique na Wivo exatamente igual ao da sua loja e você possa cruzá-los. Os textos, como o nome do comprador, aceitam.

Posso enviar pedidos antigos? Sim, com purchase_date de até 2 anos atrás, em lotes de 100 e respeitando os limites de uso. Não há uma carga histórica em massa separada.

Posso enviar pedidos em outra moeda ou de outro país? Por enquanto não: durante a beta a API é apenas para contas do Chile e valores em CLP.

Este recurso consome minha cota da API de dados? Não. Está incluído no plano Pro, não precisa do add-on e tem o seu próprio limite de 30 solicitações por minuto.