API de Wivo Analytics

La API de Wivo te permite acceder programáticamente a datos de ventas, ítems de órdenes, costos asociados (comisiones, envíos, promociones, publicidad), márgenes y métricas de rentabilidad disponibles en los reportes de la plataforma.

¿Por dónde empezar? Si vas a integrar por primera vez, lee las secciones 1 a 6 en orden: te llevan desde habilitar la API hasta dejar tus datos sincronizados. Las secciones 7 a 11 son la referencia técnica que vas a consultar de a ratos (parámetros, campos, límites).

1. Casos de uso principales

  1. Integrar datos de Wivo en data warehouses, ERPs, sistemas contables o herramientas internas
  2. Automatizar reportes y dashboards personalizados sin exportaciones manuales de archivos

2. Datos disponibles

La API entrega información a nivel de ítem de orden, que incluye:

  • Detalle de la orden (ID, fecha de compra, SKUs, tipo de envío, estado de orden y pago)
  • Costos de la orden (comisiones, envío, logística)
  • Costos adicionales (almacenamiento fulfillment, publicidad)
  • Métricas derivadas (rentabilidad, porcentaje de rentabilidad)

3. Habilitar la API

  1. Accede a tu cuenta de Wivo con credenciales de administrador
  2. Ve a “Integración API” en el menú superior derecho
  3. Haz clic en “Solicitar habilitación de API”
  4. Agenda una reunión con un representante de Wivo para la activación
  5. Recibe tu API Key personal y confidencial

4. Autenticación

Incluye tu API Key en el header HTTP de cada petición:

Ocp-Apim-Subscription-Key: TU_API_KEY

Las claves inválidas o ausentes retornan HTTP 401 Unauthorized. Si tu cuenta no tiene habilitado el acceso a la API de datos, o la suscripción fue revocada, retorna HTTP 403 Forbidden.

5. Tu primera petición

Con tu API Key lista, haz esta petición para confirmar que todo funciona. Trae los ítems de órdenes de un rango de fechas:

curl "https://api.wivoanalytics.com/data?date=purchase_date&from=2025-01-01&to=2025-01-31&page=1" \
  -H "Ocp-Apim-Subscription-Key: TU_API_KEY_AQUI"

La respuesta es un JSON con dos partes:

  • data — el array de ítems de orden (cada uno con sus ventas, costos y rentabilidad). Ver el detalle de los campos en la sección 8.
  • meta — información de paginación. Fíjate en totalPages: te dice cuántas páginas hay que recorrer para traer todo el rango.

Con esto ya puedes explorar los datos. Para una integración de verdad, sigue con la sección 6 (cómo mantener tus datos sincronizados) y usa las secciones 7 a 11 como referencia del detalle de cada parámetro y campo.

6. Cómo sincronizar tus datos: flujo histórico vs. flujo regular

Para una integración real vas a tener dos flujos: una carga histórica (una sola vez, para traer todo el pasado) y un flujo regular (recurrente, para mantenerte sincronizado).

Modelo mental — por qué borrar e insertar (delete + insert): Una orden no es inmutable. Después de la compra puede cambiar de estado, ajustar costos, recibir reembolsos o cancelarse. Por eso, cada vez que una orden aparece en la respuesta, borra todos sus ítems en tu base y vuelve a insertarlos completos. Así tu copia siempre refleja el último estado de Wivo, sin duplicados ni datos viejos. El campo para agrupar los ítems de una misma orden es Orden.

6.1. Carga histórica (backfill inicial)

Objetivo: traer toda la historia que incluye tu plan, una sola vez.

Usa date=purchase_date y pagina hasta agotar el rango. El campo meta.totalPages de la respuesta (ver sección 8) te dice cuántas páginas hay.

El punto de partida es el inicio de la ventana que incluye tu plan (ver sección 7.2). Desde ahí, un solo rango paginado cubre toda tu historia: sin to, la ventana llega hasta hoy.

desde_cuando = inicio_de_la_ventana_de_tu_plan()   # ver sección 7.2

page = 1
total_pages = 1                      # se actualiza con la primera respuesta
while page <= total_pages:
    resp = GET("/data", params={
        "date": "purchase_date",
        "from": desde_cuando,
        "page": page,
        "limit": 1000,
    })
    guardar_con_delete_insert(resp["data"])   # borrar ítems de cada Orden y reinsertar
    total_pages = resp["meta"]["totalPages"]
    page += 1

# Guarda el mayor "Fecha de actualización" (updated_at) que hayas visto:
# es el punto de partida del flujo regular.

Pide páginas grandes y respeta el rate limit. Con limit=1000 traes 10 veces más filas por request que con el mínimo, y el techo son 5 req/min (ver sección 10): unas 5.000 filas por minuto. Agrega una pausa entre páginas y reintentos con backoff exponencial ante un HTTP 429.

6.2. Flujo regular (incremental, por hora o por día)

Objetivo: mantener tu copia sincronizada trayendo solo lo que cambió.

Usa date=updated_at desde la última fecha que procesaste. Esto trae órdenes nuevas y actualizaciones (cambios de estado, ajustes de costo, cancelaciones, reembolsos):

last_synced = "2025-01-15T09:55:00"   # ← último updated_at procesado, MENOS la ventana de seguridad

page = 1
total_pages = 1
while page <= total_pages:
    resp = GET("/data", params={
        "date": "updated_at",
        "from": last_synced,
        "page": page,
        "limit": 1000,
    })
    guardar_con_delete_insert(resp["data"])
    total_pages = resp["meta"]["totalPages"]
    page += 1

La ventana se aplica a la fecha de actualización: la respuesta trae las subórdenes actualizadas en el rango, aunque se hayan comprado antes. Una orden comprada hace tres meses que hoy cambia de estado aparece en la ventana de hoy.

El alcance cubre las compras de los últimos 120 días y viene declarado en cada respuesta (ver sección 11).

Ventana de seguridad (recomendado): resta 5–10 min a tu último updated_at antes de pedir de nuevo. Si lo último procesado fue 2025-01-15T10:00:00, pide desde 2025-01-15T09:55:00. Esto evita perder cambios por desfases de reloj o latencia. Como reinsertas por orden completa, volver a traer una orden no genera duplicados.

Elige ventanas cortas. Una ventana de varios días puede devolver varias páginas aun con limit=1000. Con el rate limit de 5 req/min (ver sección 10), sincronizar por hora es más rápido y liviano que por día.

Límite de 7 días con updated_at: un request no puede cubrir más de 7 días (ver sección 7.2). Si tu proceso estuvo caído más de una semana, avanza en ventanas de ≤7 días hasta alcanzar el presente.

7. Referencia: endpoint y parámetros

7.1. Endpoint

  • GET /data — Devuelve órdenes e ítems de costos con todo su detalle.

7.2. Parámetros de GET /data

  • date (purchase_date o updated_at): Debes escoger uno de estos parámetros (obligatorio)
  • from: obligatorio, ISO 8601. Acepta 2025-01-31 o 2025-01-31T09:55:00
  • to: opcional, ISO 8601. Acepta 2025-02-01 o 2025-02-01T18:30:00
  • item_type: opcional. Filtra por tipo de fila: order, publication o marketplace. Acepta varios valores separados por coma. Los alias orders y publications siguen siendo válidos
  • payment_status: opcional. Filtra por estado de pago: paid, unpaid o noinformation. Acepta varios valores separados por coma
  • item_status: opcional. Filtra por estado de la orden: paid, canceled o returned. Acepta varios valores separados por coma
  • page: opcional
  • limit: opcional, tamaño de página. Default 1000, máximo 1000
  • categories: opcional, lista separada por comas: income, costs, reimbursement. Agrega a la respuesta las medidas de esas categorías y su total (ver sección 9). Si se omite, se devuelve solo el set base

Hora en from y to: si envías hora, se respeta. Si envías solo la fecha, from se completa a las 00:00:00 y to a las 23:59:59 de ese día. La zona en que se interpretan depende del campo que filtres (ver sección 11).

Ventana de fechas que incluye tu plan. Tu plan define desde cuándo puedes consultar:

PlanPuedes consultar desde
FreeEl día 1 del mes anterior al actual
ProEl 1 de enero de dos años atrás

Con purchase_date puedes pedir esa ventana completa en una sola petición y recorrerla paginando con limit (el ritmo lo marca el rate limit, ver sección 10).

Con date=updated_at una petición no puede cubrir más de 7 días, cualquiera sea tu plan.

Un to posterior al día de hoy se recorta a hoy, porque más allá no hay datos todavía. El valor efectivo viaja en meta.to.

Un from anterior a la ventana de tu plan retorna HTTP 400 Bad Request, con tu plan y la fecha desde la que puedes consultar en el mensaje. La petición falla completa: no se devuelve un rango recortado, para que puedas distinguir un tramo que no entró de uno que vino vacío.

Un parámetro inválido —fecha, rango excedido, o un valor no reconocido en item_type, payment_status o item_status— retorna HTTP 400 Bad Request indicando qué valor se rechazó y cuáles son los válidos.

Un nombre de parámetro que no esté en esta lista también retorna 400, con los nombres válidos en el mensaje. Es a propósito: si un parámetro mal escrito se ignorara en silencio, recibirías todas las filas creyendo que filtraste.

Ejemplos:

Con purchase_date:

curl "https://api.wivoanalytics.com/data?date=purchase_date&from=2025-01-01&to=2025-01-31&page=1" \
  -H "Ocp-Apim-Subscription-Key: TU_API_KEY_AQUI"

Con updated_at:

curl "https://api.wivoanalytics.com/data?date=updated_at&from=2025-01-01T20:55:00" \
  -H "Ocp-Apim-Subscription-Key: TU_API_KEY_AQUI"

7.3. Valores de los filtros y lo que devuelve cada columna

Los filtros se envían con la clave en inglés. Las columnas de la respuesta traen la etiqueta en español.

ParámetroValor a enviarColumnaValor que verás
item_typeorderTipo de DatoOrden
item_typepublicationTipo de DatoPublicación
item_typemarketplaceTipo de DatoMarketplace
payment_statuspaidEstado de PagoPagado
payment_statusunpaidEstado de PagoInformado
payment_statusnoinformationEstado de PagoSin Información
item_statuspaidEstado de OrdenRegular
item_statuscanceledEstado de OrdenCancelada
item_statusreturnedEstado de OrdenDevuelta

unpaid se muestra como Informado. Antes esa columna decía No Pagado. Lo que cambió es la etiqueta que viaja en la respuesta, no el contrato: el valor que envías en el filtro sigue siendo payment_status=unpaid. Si tu proceso concilia comparando el texto de la columna Estado de Pago, ajústalo a Informado; si filtra por la clave, no tienes que cambiar nada.

Ojo con item_status=paid: devuelve las órdenes en estado Regular, o sea las que no fueron canceladas ni devueltas. No tiene relación con el estado de pago; para eso está payment_status.

Los filtros son independientes entre sí y se combinan con AND. Los valores dentro de un mismo filtro se combinan con OR: payment_status=paid,unpaid trae las filas que estén en cualquiera de los dos estados.

Qué trae una fila marketplace

Son movimientos que el marketplace registra a nivel de cuenta y no de una venta puntual: tarifas de almacenamiento, cobros de publicidad, cargos de facturación, y también sus reembolsos y compensaciones.

Lo que caracteriza a estas filas:

  • Ventas y Unidades vienen en 0
  • SKU Producto viene en Sin SKU
  • Producto trae la descripción que el marketplace le da al movimiento, en el idioma de ese marketplace. Por ejemplo Cobro por Productos patrocinados, Cargos de facturación o Tarifa pelo serviço de armazenamento Full
  • Costo de Marketplace trae el monto, junto con la medida de la sección de costo que corresponda
  • Estado de Orden viene en Regular

Importan al calcular costos: traen costo y no traen ventas. Si las excluyes con item_type=order o item_type=order,publication, ese costo no aparece en la respuesta. Cuánto pesa depende de la cuenta y del marketplace.

Pedir el mismo recorte que el panel de Rentabilidad

El panel carga considerando órdenes y publicaciones, en estado Regular, y excluyendo las filas sin información de pago. Ese recorte se pide así:

curl "https://api.wivoanalytics.com/data?date=purchase_date&from=2025-01-01&item_type=order,publication&payment_status=paid,unpaid&item_status=paid" \
  -H "Ocp-Apim-Subscription-Key: TU_API_KEY_AQUI"

Si necesitas que los totales coincidan con la pantalla, revisa además la ventana de fechas y su zona horaria (ver sección 11).

8. Estructura de respuesta de GET /data

Ejemplo simplificado:

{
  "data": [
    {
      "Canal": "Marketplace A",
      "Cuenta": "Cuenta Demo 1",
      "Orden": "1000000000000001",
      "Nro. suborden": "1000000000000001",
      "Nro. Paquete": "1000000000000001",
      "N° de Liquidación": "1000000000000001",
      "SKU Producto": "SKU-DEMO-001",
      "SKU Marketplace": "9000000000001",
      "Producto": "Producto Demostración 1 - Talla: L",
      "Variante": "Talla: L",
      "SKU Variante": "SKU-DEMO-001",
      "Fecha de actualización": "2024-01-11T06:26:29.000Z",
      "Estado de Orden": "Regular",
      "Estado de Pago": "Pagado",
      "Estado de Despacho": "Entregado",
      "Tipo de Despacho": "No Fulfillment",
      "Fecha de compra": "2024-01-09T23:56:56.000",
      "Tipo de Dato": "Orden",
      "Ventas": "7500",
      "Unidades": "1",
      "Costo de Marketplace": "1500.00",
      "Rentabilidad Marketplace": "6000.00",
      "% Rentabilidad Marketplace": "80.00",
      "Costo Envío": "1000",
      "Costo de Comisiones": "500"
    },
    {
      "Canal": "Marketplace A",
      "Cuenta": "Cuenta Demo 1",
      "Orden": "1000000000000002",
      "Nro. suborden": "1000000000000003",
      "Nro. Paquete": "1000000000000002",
      "N° de Liquidación": "1000000000000002",
      "SKU Producto": "SKU-DEMO-002",
      "SKU Marketplace": "9000000000002",
      "Producto": "Producto Demostración 2 - Talla: L Tamaño: 10.2",
      "Variante": "Color: Azul, Tamaño: 10.2",
      "SKU Variante": "SKU-DEMO-002",
      "Fecha de actualización": "2024-01-11T06:29:13.000Z",
      "Estado de Orden": "Regular",
      "Estado de Pago": "Pagado",
      "Estado de Despacho": "Entregado",
      "Tipo de Despacho": "Fulfillment",
      "Fecha de compra": "2024-01-09T23:56:43.000",
      "Tipo de Dato": "Orden",
      "Ventas": "12000",
      "Unidades": "1",
      "Costo de Marketplace": "4000.00",
      "Rentabilidad Marketplace": "8000.00",
      "% Rentabilidad Marketplace": "66.67",
      "Costo Envío": "2000",
      "Costo de Comisiones": "2000"
    }
    // ... aquí podrías seguir agregando más items con los mismos campos
  ],
  "meta": {
    "page": 1,
    "pageSize": 100,
    "count": 100,
    "from": "2024-01-09T00:00:00",
    "to": "2024-01-09T23:59:59",
    "date": "purchase_date",
    "totalRows": 3282,
    "totalPages": 33
  },
  "correlation_id": "00000000-0000-4000-8000-000000000001"
}

El objeto meta te da todo lo necesario para paginar: page (página actual), totalPages (total de páginas del rango) y totalRows (total de ítems). Recorre desde page=1 hasta totalPages para traer el rango completo.

También trae window y fields, que declaran la zona horaria de la ventana y de cada campo de fecha (ver sección 11):

"meta": {
  "page": 1,
  "pageSize": 100,
  "count": 100,
  "from": "2024-01-09T00:00:00",
  "to": "2024-01-09T23:59:59",
  "date": "purchase_date",
  "totalRows": 3282,
  "totalPages": 33,
  "window": { "field": "purchase_date", "timezone": "local" },
  "fields": {
    "Fecha de compra": { "type": "datetime", "timezone": "local" },
    "Fecha de actualización": { "type": "datetime", "timezone": "UTC" }
  }
}

9. Categorías de medidas (categories)

Por defecto, cada ítem de data trae un set base de 7 medidas. Son las que ves en el ejemplo de la sección 8:

Ventas, Unidades, Costo de Marketplace, Rentabilidad Marketplace, % Rentabilidad Marketplace, Costo Envío, Costo de Comisiones.

El parámetro categories agrega columnas adicionales a cada ítem de data, con el desglose detrás de esos totales. Pedís una o más categorías separadas por coma (income, costs, reimbursement). Cada categoría agrega sus medidas más un campo de total.

Las columnas se identifican por su nombre exacto (el mismo que aparece como clave en el JSON). Si pides varias categorías y comparten alguna medida, la columna aparece una sola vez (no se duplica). Los totales Ventas y Costo de Marketplace ya vienen en el set base; las categorías agregan su desglose.

income — Ingresos de la orden

Columna
Ventas
Despacho pagado por comprador
Ingreso por Envío Flex
Ingreso de Compensación por Daños
Ingreso por promoción
Ingresos sin categorizar
Ingreso Totaltotal de la categoría

costs — Costos del marketplace

Refleja el análisis de costos de la plataforma, agrupado por sección. El total de cada sección está en negrita.

Ojo con el gran total. Costo de Marketplace es el costo total del canal y las ocho secciones de abajo son su desglose. Si necesitas el total exacto, usa Costo de Marketplace directamente en vez de sumar las secciones.

Comisiones: Cobro de Comisiones, Reembolso de Comisiones, Costo de Comisiones

Envío: Despacho pagado por comprador, Cobro Envío Flex, Ingreso por Envío Flex, Reembolso de envío, Cobro de Envío, Costo Envío

Publicidad: Cobro por publicidad, Reembolso por publicidad, Costos por publicidad

Almacenamiento Fulfillment: Cobro por Costo Logístico, Reembolso de Costo Logístico, Cobro por Servicio Almacenamiento, Cobro por Almacenamiento Prolongado, Cobro por Descarte de Stock, Reembolso por servicio almacenamiento, Reembolso por descarte de stock, Reembolso por almacenamiento prolongado, Costos de Almacenamiento Fulfillment

Otros costos: Cobro de Ajuste sobre la Comisión, Reembolso de Ajuste sobre la Comisión, Cobro de Penalizacion por Cancelación, Devolución de Penalización por Cancelación, Cobro Logística Inversa, Reembolso Logística Inversa, Cobro de Penalización por Daños, Ingreso de Compensación por Daños, Reembolso de Ajuste sobre Venta, Ingreso por promoción, Cobros sin categorizar, Ingresos sin categorizar, Reembolsos sin categorizar, Cobro de Impuestos, Reembolso de Impuestos, Otros costos

Descuentos y Promociones: Cobro por Cupones de Descuento, Reembolso por Cupones de Descuento, Costos de Descuentos y Promociones

Gestión de Cuenta: Cobro por Asesoría Comercial (KAM), Cobro por Uso de Mercado Pago, Cobro por Mantenimiento eShop, Cobro por Reputación, Cobro por Publicar, Reembolso por Asesoría Comercial (KAM), Reembolso por Uso de Mercado Pago, Reembolso por Mantenimiento eShop, Costos de Gestión de Cuenta

Financiamiento: Cobro por Financiación y Cuotas Mercado Pago, Cobro por Adelanto de Dinero, Reembolso por Financiación y Cuotas Mercado Pago, Costos de Financiamiento

Gran total: Costo de Marketplace

reimbursement — Reembolsos de cargos

Columna
Reembolso de Ajuste sobre la Comisión
Devolución de Penalizacion por Cancelación
Reembolso Logística Inversa
Reembolso de Ajuste sobre Venta
Reembolso de Comisiones
Reembolso de envío
Reembolso de Costo Logístico
Reembolso por publicidad
Reembolsos sin categorizar
Reembolso por servicio almacenamiento
Reembolso por descarte de stock
Reembolso por almacenamiento prolongado
Reembolso de Impuestos
Reembolso Totaltotal de la categoría

Ejemplo

curl "https://api.wivoanalytics.com/data?date=purchase_date&from=2025-01-01&to=2025-01-31&categories=income,costs" \
  -H "Ocp-Apim-Subscription-Key: TU_API_KEY_AQUI"

Cada ítem de data llega con el set base más las columnas de las categorías pedidas (en negrita las que aparecen solo por categories=income,costs):

{
  "Orden": "1000000000000001",
  "Ventas": "7500",
  "Unidades": "1",
  "Costo de Marketplace": "1500.00",
  "Rentabilidad Marketplace": "6000.00",
  "Ingreso Total": "7500.00",
  "Cobro de Comisiones": "500",
  "Costo de Comisiones": "500",
  "Cobro de Envío": "1000",
  "Costo Envío": "1000"
}

Una categoría no válida retorna HTTP 400 Bad Request.

10. Límites de uso (Rate limits)

  • 5 peticiones por minuto por API Key
  • 7.200 peticiones por día por API Key
  • Superar cualquiera de los dos retorna HTTP 429 Too Many Requests

Los dos límites se aplican, no son una recomendación. Con limit=1000 (ver sección 7.2), 5 peticiones por minuto equivalen a unas 5.000 filas por minuto, así que el techo real de tu sincronización lo marca el tamaño de página que pidas: cuanto más grande, menos peticiones necesitas para el mismo dato.

Como buenas prácticas, implementa reintentos con backoff exponencial y agrupa la lógica para aprovechar al máximo cada petición.

11. Fechas y zonas horarias

La respuesta trae dos campos de fecha, y cada uno viene en una zona distinta. Es importante para cualquier cálculo o cruce con tus propias fuentes.

CampoZonaFormato
Fecha de actualizaciónUTC2026-08-14T16:00:42.286Z — con designador Z y milisegundos
Fecha de compraHora local del canal de venta2026-08-14T08:12:59.000 — sin designador de zona

Fecha de actualización

Viene siempre en UTC, con la Z y con milisegundos. Es el mismo valor sin importar por qué campo filtres, así que puedes parsearla directamente como instante.

Marca cuándo Wivo actualizó por última vez ese registro, y es el campo que se usa como cursor del flujo incremental de la sección 6.2.

Fecha de compra

Viene en la hora local del canal de venta, sin designador de zona. No la interpretes como UTC: la mayoría de los parsers asumen UTC cuando falta la Z, y eso desplaza la fecha varias horas.

Como la zona depende del canal, dos órdenes compradas en el mismo instante en canales de países distintos traen relojes distintos en este campo. Si necesitas comparar instantes o cruzar con fuentes en UTC, usa Fecha de actualización.

Zona de from y to

Se interpretan en la misma zona que el campo que estás filtrando, y meta.window te lo indica en cada respuesta:

FiltroZona de from y to
date=updated_atUTC
date=purchase_dateHora local del canal, igual que el campo

Con date=updated_at, el valor de Fecha de actualización que recibes se puede reenviar tal cual como from en el siguiente request.

Alcance de la búsqueda por fecha de actualización

Con date=updated_at, la respuesta incluye las subórdenes cuya fecha de compra esté dentro de los 120 días previos al inicio del rango consultado.

Cada respuesta declara ese límite en meta.window.purchaseDateFrom:

"window": {
  "field": "updated_at",
  "timezone": "UTC",
  "purchaseDateFrom": "2026-04-16T00:00:00"
}

Para consultar compras anteriores a ese límite, usa date=purchase_date con el rango que necesites.

Declaración en la respuesta

meta.fields declara la zona de cada campo de fecha en cada respuesta, con las mismas claves que ves en data. Si tu integración necesita verificar el formato antes de parsear, léelo de ahí en vez de asumirlo.