Saltar al contenido
Pedidos

Devoluciones y reembolsos

Registra devoluciones, reembolsa pagos y repón stock con Admin API.

Andrea Ramos devuelve uno de los dos polos de su pedido. Registras la devolución, repones el stock y reembolsas su pago con Admin API.

Requisitos

  • Un token de Admin con el scope api_admin. Ver Integración con ERP.
  • Los permisos order:update y, para reembolsar, payment:create.
  • Un pedido con su pago capturado.
  • Node.js o Python, para los ejemplos.

Lee el pedido

Consulta el pedido antes de devolver o reembolsar. Guarda el id de cada item y el paymentTransactionId de cada pago.

curl https://api.ecomiq.pe/api/v1/orders/7204558912004325301 \
  -H "Authorization: Bearer $ECOMIQ_TOKEN"
Respuesta
{
  "id": "7204558912004325301",
  "orderNumber": "ORD-2026-0001",
  "status": "delivered",
  "returnStatus": "none",
  "currencyCode": "PEN",
  "total": 178,
  "items": [
    {
      "id": "7204558912004325302",
      "title": "Polo de algodón",
      "quantity": 2,
      "quantityReturned": 0
    }
  ],
  "payments": [
    {
      "paymentTransactionId": "7204558912004325320",
      "paymentMethod": "card",
      "amount": 178,
      "paymentStatus": "Captured",
      "refundedAmount": 0,
      "refundableAmount": 178
    }
  ],
  "financialSummary": {
    "paidAmount": 178,
    "refundedAmount": 0,
    "refundableAmount": 178,
    "shippingRefundableAmount": 0
  },
  "pendingRefund": null
}

payments[].refundableAmount es lo que aún puedes reembolsar de ese pago. Vale 0 si el pago no se capturó. financialSummary.refundableAmount es el tope de todo el pedido.

Los pasos siguientes reusan API, headers y orderId.

Marca el estado de la devolución

returnStatus sigue la devolución antes de que lleguen las unidades. Cuando Andrea Ramos pide devolver, marca requested. Para aprobar, pasa a inProgress con la dirección de envío.

curl -X PUT https://api.ecomiq.pe/api/v1/orders/7204558912004325301/return-status \
  -H "Authorization: Bearer $ECOMIQ_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "inProgress",
    "comment": "Aprobamos tu devolución. Envía el polo con su etiqueta.",
    "returnAddress": "Av. Larco 345, Miraflores, Lima"
  }'

La respuesta 200 devuelve el pedido con returnStatus: "inProgress".

EstadoSignificadoPor esta ruta
noneSin devolución.No, responde 409
requestedSolicitada.Sí
inProgressEn proceso.Sí
inspectedRevisada.Sí
rejectedRechazada.Sí
returnedHay unidades devueltas registradas.No, responde 409

Al pasar de requested a inProgress, el cliente recibe la aprobación con comment y returnAddress. Al pasar a rejected, recibe el rechazo con comment.

none y returned responden 409 con Orders.InvalidReturnTransition: returned se asigna al registrar la devolución.

Registra la devolución al final

Una devolución registrada, aunque sea parcial, deja returnStatus en returned. Desde ahí, esta ruta responde 409 con Orders.ReturnCompleted.

Registra la devolución

Registra las unidades que recibiste. Para un item, usa POST /v1/orders/{orderId}/items/{itemId}/return. Para todo el pedido, usa POST /v1/orders/{orderId}/return con el mismo cuerpo, sin quantity.

Este ejemplo devuelve un polo, lo repone en stock y reembolsa 89.

curl -X POST https://api.ecomiq.pe/api/v1/orders/7204558912004325301/items/7204558912004325302/return \
  -H "Authorization: Bearer $ECOMIQ_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "idempotencyKey": "devolucion-ORD-2026-0001-1",
    "quantity": 1,
    "comment": "Talla incorrecta.",
    "restock": true,
    "restockLocationId": "7204558912004325378",
    "refundAmount": 89,
    "paymentTransactionId": "7204558912004325320"
  }'
Respuesta
{
  "id": "7204558912004325301",
  "status": "partialReturned",
  "returnStatus": "returned",
  "items": [
    {
      "id": "7204558912004325302",
      "quantity": 2,
      "quantityReturned": 1
    }
  ],
  "payments": [
    {
      "paymentTransactionId": "7204558912004325320",
      "refundedAmount": 89,
      "refundableAmount": 89
    }
  ],
  "financialSummary": {
    "paidAmount": 178,
    "refundedAmount": 89,
    "refundableAmount": 89
  }
}
CampoUso
idempotencyKeyObligatorio, hasta 100 caracteres. Repetirlo no registra otra devolución.
quantityUnidades a devolver. Sin valor, devuelve todas las pendientes.
restocktrue suma las unidades al stock de restockLocationId.
restockLocationIdUbicación que recibe las unidades. Obligatoria con restock.
refundAmountMonto a reembolsar en la misma llamada.
paymentTransactionIdPago a reembolsar. Obligatorio con refundAmount.
commentNota de hasta 500 caracteres.

Los IDs de ubicación están en Listar ubicaciones logísticas. status pasa a partialReturned, o a returned si se devolvieron todas las unidades.

refundAmount no se limita al valor del item. Su tope es lo que queda del pago: payments[].refundableAmount. Este reembolso no cubre envío; para eso, usa Reembolsa un pago.

Si el reembolso falla, la devolución no se registra. Reintenta con la misma idempotencyKey. Un pedido cerrado o cancelado responde 409.

La devolución del pedido completo envía el webhook order.returned. La devolución de un item no lo envía.

Reembolsa un pago

Usa POST /v1/orders/{orderId}/refunds para reembolsar sin devolución o para reembolsar envío. Para un reembolso completo, envía en amount el refundableAmount del pago. Para uno parcial, envía menos.

curl -X POST https://api.ecomiq.pe/api/v1/orders/7204558912004325301/refunds \
  -H "Authorization: Bearer $ECOMIQ_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "paymentTransactionId": "7204558912004325320",
    "idempotencyKey": "reembolso-ORD-2026-0001-1",
    "amount": 20,
    "reason": "Compensación por demora en la entrega.",
    "notifyCustomer": true
  }'
Respuesta
{
  "id": "7204558912004325301",
  "hasRefund": true,
  "financialSummary": {
    "paidAmount": 178,
    "refundedAmount": 109,
    "refundableAmount": 69,
    "shippingRefundableAmount": 0
  },
  "pendingRefund": null
}
CampoUso
paymentTransactionIdPago a reembolsar, tomado de payments[].
idempotencyKeyObligatorio, hasta 100 caracteres.
amountTotal a reembolsar, con hasta dos decimales. Incluye shippingAmount.
shippingAmountParte de amount que reembolsa envío. Por defecto 0.
reasonMotivo, hasta 500 caracteres.
notifyCustomerAvisa al cliente. Por defecto true.
linesItems y unidades reembolsados. Obligatorio con restock.
restockCon restockLocationId, devuelve las unidades de lines al stock.

amount no puede superar payments[].refundableAmount ni financialSummary.refundableAmount. Si los supera, la API responde 400 con Orders.RefundExceedsBalance. shippingAmount tiene como tope financialSummary.shippingRefundableAmount.

Repetir la misma idempotencyKey con el mismo cuerpo no reembolsa dos veces. Con otro cuerpo, la API responde 409 con Orders.RefundKeyConflict.

El stock cambia según la llamada:

LlamadaStock
Devolución sin restockNo cambia.
Devolución con restockSuma las unidades devueltas en restockLocationId.
Reembolso sin linesNo cambia.
Reembolso con lines, sin restockLas unidades aún sin despachar salen de la preparación y liberan su reserva.
Reembolso con lines y restockRegistra las unidades como devueltas y las suma en restockLocationId.

restock en un reembolso exige un pedido inTransit, delivered, partialDelivered o partialReturned. Solo acepta unidades despachadas que no se devolvieron. Solo vuelven al stock items vinculados a una variante, en unidades enteras.

Reintenta un reembolso pendiente

El reembolso se guarda antes de pedirlo al proveedor de pagos. Si el proveedor falla o no confirma, la API responde con error y el pedido muestra pendingRefund.

Pedido con reembolso pendiente
{
  "id": "7204558912004325301",
  "pendingRefund": {
    "id": "7204558912004325340",
    "idempotencyKey": "reembolso-ORD-2026-0001-1",
    "payments": [
      { "paymentTransactionId": "7204558912004325320", "amount": 20 }
    ],
    "amount": 20,
    "shippingAmount": 0,
    "reason": "Compensación por demora en la entrega.",
    "restockLocationId": null,
    "notifyCustomer": true,
    "lines": [],
    "createdOn": "2026-10-04T15:30:00Z"
  }
}

Mientras exista, otros reembolsos y devoluciones responden 409 con Orders.RefundPending. Reintenta con pendingRefund.id: la API repite la solicitud con su misma idempotencyKey.

curl -X POST https://api.ecomiq.pe/api/v1/orders/7204558912004325301/refunds/7204558912004325340/retry \
  -H "Authorization: Bearer $ECOMIQ_TOKEN"

Si el reembolso ya se completó, la API devuelve el pedido sin reembolsar otra vez. Si el proveedor confirma más tarde, el reembolso pendiente se completa solo.

Revisa los movimientos

GET /v1/orders/{orderId}/transactions lista el dinero que entró y salió del pedido. Cada reembolso es un movimiento out con amount negativo.

curl https://api.ecomiq.pe/api/v1/orders/7204558912004325301/transactions \
  -H "Authorization: Bearer $ECOMIQ_TOKEN"
Respuesta
[
  {
    "id": "7204558912004325350",
    "type": "in",
    "amount": 178,
    "paymentMethod": "card",
    "referenceId": "7204558912004325320",
    "referenceType": "paymentTransaction",
    "createdOn": "2026-10-01T10:12:00Z"
  },
  {
    "id": "7204558912004325351",
    "type": "out",
    "amount": -89,
    "paymentMethod": "card",
    "referenceId": "7204558912004325320",
    "referenceType": "paymentTransaction",
    "content": "Talla incorrecta.",
    "createdOn": "2026-10-04T15:10:00Z"
  },
  {
    "id": "7204558912004325352",
    "type": "out",
    "amount": -20,
    "paymentMethod": "card",
    "referenceId": "7204558912004325320",
    "referenceType": "paymentTransaction",
    "content": "Compensación por demora en la entrega.",
    "createdOn": "2026-10-04T15:30:00Z"
  }
]

referenceId es el pago de cada movimiento. content guarda el motivo del reembolso o el comentario de la devolución.

Siguientes pasos

Última actualización:

En esta página