Referencia de la API · MOVEQIA Delivery

Envía pedidos de reparto a MOVEQIA desde tu sistema

MOVEQIA es una red de reparto de última milla. Esta API permite que cualquier sistema —una web de comercio, un TPV, un ERP o un conector como Delinode— cree pedidos de reparto en nombre de un comercio y reciba el estado del pedido en tiempo real.

Versión 1 · Última actualización: septiembre de 2026 · ¿Prefieres una guía paso a paso? →

Cómo funciona

Una integración con MOVEQIA tiene dos mitades. Las dos usan HTTPS y una firma HMAC-SHA256, en sentidos opuestos:

  • Tú → MOVEQIA: envías un pedido de reparto a un único endpoint (ordersWebhook), firmado con la clave de tu comercio.
  • MOVEQIA → tú: MOVEQIA envía cada cambio de estado del pedido (aceptado, recogido, en reparto, entregado…) a la URL que hayas registrado, firmado con un secreto compartido.

MOVEQIA se ocupa del emparejamiento con el rider, del precio del reparto y del cobro al comercio. Tú solo envías el pedido y consumes los estados.

Alta asistida MOVEQIA da de alta cada integración manualmente. Antes de empezar, el equipo te entrega tu api_key, tu secreto de webhook, y registra la URL donde quieres recibir los estados. No hay auto-registro público.

Autenticación

Cada petición que envías a MOVEQIA se autentica con tres cabeceras. No se usan tokens de sesión ni OAuth: la identidad del comercio es su api_key, y la integridad del mensaje la garantiza la firma.

CabeceraValor
x-api-keyLa api_key de tu comercio (64 caracteres hexadecimales).
x-timestampMarca de tiempo Unix en segundos del momento de la petición.
x-signatureFirma HMAC-SHA256 en hexadecimal (ver abajo).

Cómo se calcula la firma

La firma se calcula sobre la marca de tiempo y el cuerpo crudo, unidos por un punto, usando tu propia api_key como secreto:

x-signature = HMAC_SHA256( clave = api_key ,  mensaje = "{x-timestamp}.{cuerpo_crudo}" )   →  hex
El cuerpo firmado debe ser byte a byte el que envías Firma el texto JSON exacto que va en el cuerpo de la petición. Si serializas el objeto dos veces (una para firmar y otra para enviar) y el resultado difiere en un espacio, la firma no validará. Firma una vez y envía ese mismo string.

Ventana anti-repetición

MOVEQIA rechaza peticiones cuya x-timestamp se aleje más de 5 minutos del reloj del servidor. Mantén tu reloj sincronizado por NTP. La comparación de firmas se hace en tiempo constante.

Ejemplo — Node.js
const crypto = require("crypto");
const rawBody   = JSON.stringify(pedido);
const timestamp = Math.floor(Date.now() / 1000).toString();
const signature = crypto
  .createHmac("sha256", apiKey)
  .update(`${timestamp}.${rawBody}`)
  .digest("hex");

Crear un pedido

POST https://app.moveqia.com/functions/ordersWebhook

Envía un pedido de reparto en el formato canónico de MOVEQIA. El comercio en cuyo nombre creas el pedido es el dueño de la api_key con la que firmas.

Cuerpo de la petición

CampoTipoDescripción
external_order_idstringRequeridoTu identificador del pedido. MOVEQIA te lo devuelve en cada webhook de estado para que concilies. Debe ser único por pedido.
recipient.namestringRequeridoNombre del destinatario final.
recipient.phonestringRequeridoTeléfono de contacto para la entrega, en formato E.164 (p. ej. +34600112233).
recipient.addressstringRequeridoDirección de entrega completa.
recipient.emailstringOpcionalCorreo del destinatario.
recipient.lat / lngnumberOpcionalCoordenadas de entrega. Si faltan, MOVEQIA geocodifica la dirección.
pickupobjectOpcionalPunto de recogida (name, address, lat, lng). Si lo omites, MOVEQIA usa la dirección de la sede del comercio.
items_countintegerOpcionalNúmero de bultos.
weight_kgnumberOpcionalPeso total en kilos.
vehicle_requiredstringOpcionalVehículo requerido: bici, moto o coche.
fragilebooleanOpcionalMarca el envío como frágil.
cash_on_deliverynumberOpcionalImporte a cobrar contra entrega, si aplica.
prioritystringOpcionalPrioridad del pedido, si tu acuerdo la contempla.
tipnumberOpcionalPropina para el rider.
notesstringOpcionalInstrucciones de entrega (piso, portal, referencias).
Petición
POST /functions/ordersWebhook
x-api-key: e82fbf5a…9ed5f1
x-timestamp: 1758560400
x-signature: 7542710c59fa…c0a1
Content-Type: application/json

{
  "external_order_id": "PEDIDO-2026-000123",
  "recipient": {
    "name": "Ana Martín",
    "phone": "+34600112233",
    "address": "Calle de Alcalá 100, 28009 Madrid"
  },
  "items_count": 1,
  "notes": "Portal, 3º B. Llamar al llegar."
}
Respuesta — 200 OK
{
  "ok": true,
  "order_id": "6ab2d29406429152e81ad62e",
  "external_order_id": "PEDIDO-2026-000123",
  "status": "buscando_rider"
}

Respuestas y errores

CódigoSignificado
200Pedido creado. A partir de aquí recibirás los estados por webhook.
401Firma inválida o x-timestamp fuera de la ventana de 5 minutos.
404api_key desconocida.
409El comercio aún no puede recibir pedidos (cuenta no verificada o sin medio de cobro activo). Ver nota.
422El pedido no pasa validación: falta un campo requerido, la dirección no se puede geocodificar, o la zona no tiene cobertura.
El comercio debe estar verificado MOVEQIA solo acepta pedidos de comercios con la cuenta verificada y un medio de cobro activo. Si recibes un 409, el comercio tiene que completar su verificación en MOVEQIA antes de operar. Esto se resuelve una vez, en el alta.

Webhooks de estado

Cuando el pedido avanza, MOVEQIA hace un POST a la URL que registraste. No tienes que consultar (no hay polling): los estados llegan solos.

POST https://tu-sistema.example.com/webhooks/moveqia (la URL que tú registras)

Eventos

eventCuándo
order.acceptedUn rider ha aceptado el pedido.
order.picked_upEl rider ha recogido el pedido en el comercio.
order.in_transitEl pedido va camino del destinatario.
order.deliveredEntregado.
order.cancelledEl pedido se ha cancelado.
order.no_coverageNingún rider aceptó tras las rondas de búsqueda; el pedido queda sin cobertura.
order.dispatch_failedEl pedido se aceptó pero falló su despacho al rider; requiere atención.

Cuerpo del webhook

CampoTipoDescripción
eventstringUno de los eventos de la tabla anterior.
external_order_idstringTu identificador — úsalo como clave para actualizar tu pedido.
order_idstringIdentificador del pedido en MOVEQIA.
statusstringEstado interno del pedido en el momento del evento.
tracking_urlstringEnlace de seguimiento público (cuando aplica).
riderobject{ id, name } del rider asignado, cuando lo hay.
timestampstringMomento del evento.
Ejemplo de webhook recibido
X-Moveqia-Signature: 5b1c…e9af
Content-Type: application/json

{
  "event": "order.accepted",
  "order_id": "6ab2d29406429152e81ad62e",
  "external_order_id": "PEDIDO-2026-000123",
  "status": "accepted",
  "tracking_url": "https://app.moveqia.com/track/6ab2d294…",
  "rider": { "id": "218", "name": "Carlos R." },
  "timestamp": "2026-09-22T18:04:11Z"
}

Verificar la firma del webhook

Cada webhook llega firmado en la cabecera X-Moveqia-Signature. Verifícala antes de procesar el evento: calcula el HMAC-SHA256 del cuerpo crudo con tu secreto de webhook y compáralo en tiempo constante.

X-Moveqia-Signature = HMAC_SHA256( clave = tu_secreto_webhook , mensaje = cuerpo_crudo )  →  hex
Responde 200 rápido Devuelve 200 en cuanto aceptes el webhook y procesa después. Si tu endpoint tarda o falla, MOVEQIA reintenta la entrega (hasta 5 veces, cada ~10 minutos).

Conciliación e idempotencia

  • Concilia por external_order_id. Es tu clave del pedido de principio a fin: viaja en la creación y vuelve en cada webhook.
  • Los webhooks pueden repetirse. Por los reintentos, un mismo evento puede llegarte más de una vez. Haz que tu procesamiento sea idempotente (por ejemplo, ignora un estado que ya registraste).
  • Un comercio, una cuenta. Cada comercio tiene una única cuenta y una única api_key. Un comercio con varias sedes las gestiona dentro de su cuenta, no como cuentas separadas.

Checklist de integración

  • Reloj sincronizado por NTP (la firma caduca a los 5 minutos).
  • Firmas y envías el mismo cuerpo crudo, sin re-serializar.
  • Guardas tu api_key y tu secreto de webhook fuera del código (variables de entorno / gestor de secretos).
  • Verificas X-Moveqia-Signature en cada webhook antes de procesarlo.
  • Tu receptor responde 200 rápido y es idempotente.
  • Manejas order.no_coverage y order.dispatch_failed como estados que requieren tu atención.