Cómo migrar de la API QR Modelo dinámico a la API de Orders
La API de Orders unifica el procesamiento de pagos con Código QR en Mercado Pago, consolidando en un único endpoint los dos métodos de creación de la API QR Modelo dinámico y extendiendo los recursos de consulta y cancelación para ambos modos. Además, todas las nuevas funcionalidades de Mercado Pago se desarrollarán sobre la API de Orders.
La API QR Modelo dinámico poseía dos métodos de creación con comportamientos distintos:
POST /qrs, modo QR dinámico: crea un pedido y retorna una trama QR única por transacción en el campoqr_data, sin asociarla a ninguna caja. La aplicación es responsable de convertirqr_dataen Código QR y mostrarlo al cliente.PUT /qrs, modo QR híbrido: crea un pedido, lo asocia a la caja indicada con el{external_pos_id}, actualizando el QR estático vinculado, y retorna también el QR dinámico en el campoqr_data.
La API de Orders unifica estos dos métodos en un único endpoint POST /v1/ordersAPI, diferenciando el comportamiento por el parámetro config.qr.mode: el valor dynamic corresponde al flujo POST legacy y el valor hybrid corresponde al flujo PUT legacy.
Esta distinción impactaba también los recursos de consulta y cancelación, disponibles en la API QR Modelo dinámico solo para el flujo PUT. En la API de Orders, estos recursos pasan a estar disponibles para los dos flujos vía order_id.
Para realizar la migración de tu integración de la API QR Modelo dinámico a la API de Orders, sigue las indicaciones a continuación.
Mapear los cambios de endpoint
Antes de iniciar los pasos de migración, consulta la tabla a continuación para tener una visión general de todos los cambios de endpoint. La API de Orders unifica los dos métodos de creación en un único POST /v1/ordersAPI y extiende los recursos de consulta y cancelación para ambos modos.
| Operación | API QR Modelo dinámico | API de Orders |
| Crear order (modo dinámico) | POST /instore/orders/qr/seller/collectors/{user_id}/pos/{external_pos_id}/qrsAPI | POST /v1/ordersAPI con config.qr.mode: dynamic |
| Crear order (modo híbrido) | PUT /instore/orders/qr/seller/collectors/{user_id}/pos/{external_pos_id}/qrsAPI | POST /v1/ordersAPI con config.qr.mode: hybrid |
| Consultar order | GET /instore/qr/seller/collectors/{user_id}/pos/{external_pos_id}/ordersAPI (solo flujo PUT) | GET /v1/orders/{order_id}API (ambos modos) |
| Cancelar order | DELETE /instore/orders/qr/seller/collectors/{user_id}/pos/{external_pos_id}/qrsAPI (solo flujo PUT) | POST /v1/orders/{order_id}/cancelAPI (ambos modos) |
| Reembolsar order | Vía API de Payments (sin endpoint dedicado en la API QR Modelo dinámico) | POST /v1/orders/{order_id}/refundAPI |
Actualizar el modelo de estado y notificaciones
Uno de los cambios más significativos entre la API QR Modelo dinámico y la API de Orders es el modelo de estado. En la API QR Modelo dinámico, el estado de una transacción se determinaba mediante el monitoreo de notificaciones de dos tópicos independientes: payments y merchant_orders con campos y valores distintos para cada uno. La API de Orders unifica ese comportamiento en un único campo status en la order. Consulta el mapeo completo a continuación.
Además, la API de Orders también introduce el campo status_detail, que permite identificar con mayor detalle el estado de la transacción. Los valores posibles son created, canceled, accredited, refunded y expired.
En la API QR Modelo dinámico, la merchant_order se crea en el momento en que se genera el pedido, por lo tanto las notificaciones del tópico merchant_orders están disponibles desde el inicio del flujo. El objeto payment, por otro lado, solo se crea cuando existe un intento de pago, aprobado o rechazado. Quien monitoreaba solo el tópico payments no recibía ninguna notificación hasta que el usuario iniciara el proceso de pago. En la API de Orders, ese comportamiento está unificado: el campo status de la order refleja el estado completo desde la creación, sin necesidad de monitorear dos tópicos independientes.
Tópico payments (status) | Tópico merchant_orders (status / order_status) | API de Orders (status) | Observación |
| — | opened (sin pago o con pago rechazado) | created | En la API QR Modelo dinámico, opened indicaba que el pedido aún no tenía un pago aprobado. En la API de Orders, ese estado es explícito desde la creación. |
approved | closed + order_status: "paid" | processed | Ambos tópicos convergían en el mismo resultado: pago aprobado. En la API de Orders, el estado es autocontenido. |
rejected | opened (la merchant_order no cambia de estado y permanece abierta) | Sin equivalente | En la API QR Modelo dinámico, un pago rechazado dejaba la merchant_order en opened esperando un nuevo intento. En la API de Orders, los pagos rechazados no se exponen. El estado permanece en created hasta recibir un pago aprobado. |
refunded | closed + order_status: "reverted" | refunded | Reembolso total. En el tópico merchant_orders, identificable por order_status: "reverted". |
refunded (parcial, status_detail: "partially_refunded") | closed + pago con status_detail: "partially_refunded" | refunded | Reembolso parcial. En la API QR Modelo dinámico, era necesario inspeccionar el status_detail del pago dentro de la merchant_order. En la API de Orders, el status_detail indica partially_refunded. |
| — | — | canceled | Nuevo estado sin equivalencia en la API QR Modelo dinámico. |
| — | — | expired | Nuevo estado sin equivalencia en la API QR Modelo dinámico. |
En cuanto a las notificaciones, en la API Legacy podían configurarse mediante el campo notification_url en el body de la solicitud (modelo IPN) o mediante webhooks con los tópicos payments y merchant_orders. En la API de Orders, el campo notification_url no existe y los tópicos payments y merchant_orders no son compatibles. Configura las notificaciones en Tus integraciones, suscribiéndote al tópico "Order (Mercado Pago)" (orders), antes de ir a producción. Para más información, consulta la documentación de notificaciones.
Adaptar los headers
La API de Orders introduce un cambio obligatorio de header que afecta todos los endpoints. El Access Token debe enviarse vía header Authorization. Aplica el cambio a continuación antes de probar cualquier otro recurso.
El header X-Idempotency-Key es obligatorio en las operaciones de creación, cancelación y reembolso de orders. Garantiza que una solicitud repetida con la misma clave retorne el resultado original sin procesar la operación nuevamente. Envía un UUID v4 o string aleatoria única por solicitud. Las operaciones de tipo GET no requieren este header.
X-Idempotency-Key con un body diferente, la API retornará el error idempotency_key_already_used. Genera una nueva clave para cada operación distinta.Migrar la creación de orders
La API de Orders unifica los dos métodos de creación en un único POST /v1/ordersAPI, diferenciando el comportamiento por el parámetro config.qr.mode. El endpoint POST /qrs, modo QR dinámico, equivale a config.qr.mode: dynamic, y el endpoint PUT /qrs, modo QR híbrido, equivale a config.qr.mode: hybrid. En ambos casos, el {user_id} deja de ser parámetro de path, el {external_pos_id} pasa al body, y el campo type: "qr" pasa a ser obligatorio. Sigue los pasos a continuación para adaptar la solicitud, la respuesta y el tratamiento de errores de cada modo.
in_store_order_id. En la API de Orders, ese identificador pasa al campo id, con formato alfanumérico, por ejemplo ORD00001111222233334444555566. Captura el valor de id del response de creación, ya que es necesario para consultas, cancelaciones y reembolsos posteriores.La tabla a continuación presenta el mapeo de campos del body para ambos modos de creación. La columna de la API QR Modelo dinámico indica el comportamiento de cada campo en los flujos POST y PUT.
| API QR Modelo dinámico (POST / PUT) | API de Orders | Descripción | Cambio |
{user_id} (path param, ambos) | No existe | Identificador del usuario. En la API de Orders, la identidad se obtiene directamente del Access Token. | Deja de ser parámetro de path. |
{external_pos_id} (path param, ambos) | config.qr.external_pos_id | Identificador externo de la caja. En la API QR Modelo dinámico, se enviaba en el path. En la API de Orders, se envía en el body dentro de config.qr. | Deja de ser parámetro de path y pasa al body. |
external_reference (obligatorio en ambos) | external_reference | Referencia que puede sincronizarse con el sistema de venta. En la API de Orders, máx. 64 caracteres, solo letras, números, - y _. No puede contener datos PII. | Sin cambio en la obligatoriedad. |
title (obligatorio en POST, opcional en PUT) | No existe | Título de la compra. | Eliminado. La descripción es suficiente. |
description (obligatorio en POST, opcional en PUT) | description | Descripción de la compra. En la API QR Modelo dinámico, existía tanto en el nivel raíz como dentro de items[]. En la API de Orders, existe solo en el nivel raíz. Máx. 150 caracteres. | En la API de Orders, pasa a ser opcional y se gestiona solo en el nivel raíz. |
items[].description | No existe | Descripción del ítem. | Eliminado. La descripción se gestiona solo en el nivel raíz de la order. |
notification_url | No existe | URL para recibir notificaciones. | Eliminado. Configura las notificaciones webhook en tu aplicación dentro de Tus integraciones, seleccionando el tópico "Order (Mercado Pago)". Para más información, accede a la documentación de notificaciones. |
expiration_date | expiration_time | Validez del pedido. En la API QR Modelo dinámico, era una fecha absoluta. En la API de Orders, es una duración relativa en formato ISO 8601. En todos los modos, el valor predeterminado es de 15 minutos y el valor enviado siempre se respeta. | Cambia de fecha absoluta a duración relativa en formato ISO 8601. |
total_amount (obligatorio en ambos) | total_amount | Valor total de la order. En la API QR Modelo dinámico, era number. En la API de Orders, es string decimal y representa la suma de todas las transacciones. No acepta decimales (ej.: "15"). | Cambia de number a string decimal. |
sponsor.id | integration_data.sponsor.id | USER_ID de la cuenta de Mercado Pago del sistema integrador. | Pasa al nodo integration_data.sponsor. |
items[].sku_number | items[].external_code | Código del ítem en el sistema externo. | Renombrado a items[].external_code. |
items[].category | No existe | Categoría del ítem. | Eliminado. No tiene equivalente en la API de Orders. |
items[].title (obligatorio en ambos) | items[].title | Nombre del ítem. Máx. 150 caracteres. | Sin cambio en la obligatoriedad. |
items[].unit_price (obligatorio en ambos) | items[].unit_price | Precio unitario. En la API QR Modelo dinámico, era number. En la API de Orders, es string decimal. No acepta decimales (ej.: "15"). | Cambia de number a string decimal. |
items[].quantity (obligatorio en ambos) | items[].quantity | Cantidad de ítems. En la API QR Modelo dinámico, era number. En la API de Orders, es integer. | Cambia de number a integer. |
items[].unit_measure (obligatorio en ambos) | items[].unit_measure | Unidad de medida del ítem. Máx. 10 caracteres. | Sin cambio en la obligatoriedad. |
items[].total_amount (obligatorio en ambos) | No existe | Total del ítem (precio unitario × cantidad). | Eliminado. No tiene equivalente en la API de Orders. |
items[].currency_id | No existe | Identificador de la moneda del ítem. | Eliminado. La moneda se determina automáticamente por la cuenta del vendedor. |
items[].external_categories[].id | items[].external_categories[].id | Identificador de categoría del ítem. Habilita descuentos por categoría. No puede usarse junto con discounts. | Sin cambio. |
discount.total_amount | discounts.payment_methods[].new_total_amount | Nuevo valor total cuando se aplica un descuento. No acepta decimales (ej.: "15"). No puede usarse junto con items[].external_categories. | Reestructurado dentro de discounts.payment_methods[]. Cambia de number a string decimal. |
discount.details[] | discounts.payment_methods[].type | Medio de pago al que se aplica el descuento. Valores: debit_card, credit_card, account_money, prepaid_card. Hasta 4 medios. | Reestructurado. El array de detalles pasa a indicar el tipo de medio de pago. |
taxes[].type | No existe | Tipo de impuesto. | Eliminado. La nueva API no soporta este campo en el request. |
taxes[].value | No existe | Valor del impuesto. | Eliminado. |
taxes[].percentage | No existe | Porcentaje del impuesto. | Eliminado. |
marketplace | No existe | Identificador del marketplace. | Eliminado. El marketplace se identifica por el Access Token OAuth. |
internal_metadata | No existe | Metadata interna. | Eliminado. |
customization | No existe | Objeto de personalización. | Eliminado. |
La API de Orders también introduce los siguientes campos sin equivalencia en la API QR Modelo dinámico.
| Campo | Descripción |
type | Tipo de order. Para pagos con Código QR, el único valor posible es "qr". Obligatorio. |
config.qr.mode | Modo de Código QR. dynamic para el flujo equivalente al POST legacy (QR único por transacción). hybrid para el flujo equivalente al PUT legacy. Encola el pedido en la caja y retorna el QR dinámico en el campo qr_data. |
transactions.payments[].amount | Valor del pago dentro del nodo transactions. No acepta decimales (ej.: "15"). Solo 1 transacción de pago por order. |
marketplace_fee | Valor de la tarifa del marketplace. Exclusivo para integraciones con OAuth. No acepta decimales (ej.: "15"). |
integration_data.platform_id | Identificador de la plataforma, asignado por Mercado Pago. |
integration_data.integrator_id | Identificador del integrador, asignado por Mercado Pago. Debe tener el prefijo dev_. |
taxes[].payer_condition | Indica si la order se genera con IVA o no. Valores: payment_taxable_iva (predeterminado) o payment_exempt_iva. |
La tabla a continuación presenta el mapeo de los campos del response. Las columnas indican el origen en cada flujo de la API QR Modelo dinámico.
| API QR Modelo dinámico | API de Orders | Descripción | Cambio |
qr_data (POST y PUT) | type_response.qr_data | Trama QR EMVCo para conversión en Código QR. En la API de Orders, presente solo cuando config.qr.mode es dynamic o hybrid. | Renombrado y movido al nodo type_response. |
in_store_order_id (POST y PUT) | id | Identificador de la order creada. En la API QR Modelo dinámico, era un UUID (ej.: d4e8ca59-...). En la API de Orders, es un ID alfanumérico con prefijo ORD (ej.: ORD00001111222233334444555566). | Renombrado de in_store_order_id. El formato cambia de UUID a ID alfanumérico. |
La API de Orders también introduce los siguientes campos en el response de creación.
| Campo | Descripción |
user_id | Identificador del usuario que creó la order. |
type | Tipo de order. Para Código QR: siempre qr. |
external_reference | Referencia externa de la order. |
description | Descripción del producto o servicio. |
expiration_time | Duración de expiración en formato ISO 8601. |
processing_mode | Modo de procesamiento. Para Código QR: siempre automatic. |
total_amount | Valor total de la order. |
country_code | Identificador del sitio/país (ej.: "AR"). |
marketplace_fee | Tarifa del marketplace. Exclusivo para integraciones con OAuth. |
status | Estado actual de la order. Al crear: created. |
status_detail | Detalle del estado actual de la order. Los valores posibles son created, canceled, accredited, refunded, expired. |
currency | Moneda de la order. Valores: ARS, BRL, CLP, UYU. |
created_date | Fecha de creación. Formato yyyy-MM-ddTHH:mm:ss.sssZ. |
last_updated_date | Fecha de la última actualización. Formato yyyy-MM-ddTHH:mm:ss.sssZ. |
config.qr.external_pos_id | Identificador externo de la caja asociada a la order. |
config.qr.mode | Modo de Código QR configurado (dynamic o hybrid). |
transactions.payments[].id | Identificador de la transacción de pago. |
transactions.payments[].amount | Valor del pago. |
transactions.payments[].status | Estado del pago. Al crear: created. |
transactions.payments[].status_detail | Detalle del estado del pago. Al crear: ready_to_process. |
integration_data.application_id | Identificador de la aplicación de Mercado Pago. |
integration_data.platform_id | Identificador de la plataforma. |
integration_data.integrator_id | Identificador del integrador. |
integration_data.sponsor.id | USER_ID del sistema integrador. |
taxes[].payer_condition | Indica si la order fue generada con IVA o no. Valores: payment_taxable_iva o payment_exempt_iva. |
Los errores del flujo POST y PUT son idénticos en la API QR Modelo dinámico. La API de Orders consolida la mayoría de los errores de validación específicos por campo en los códigos genéricos property_value y property_type, con el detalle del campo en el cuerpo de la respuesta. Además, los mensajes de respuesta son más descriptivos, facilitando la identificación y resolución de problemas. Consulta las tablas a continuación para más detalles.
Errores que cambian de comportamiento
Los siguientes errores existen en ambas APIs pero con un comportamiento diferente en la API de Orders.
| HTTP | API QR Modelo dinámico | API de Orders | Observación |
400 | Múltiples: invalid_collectorId, invalid_externalPosId, invalid_external_reference, invalid_total_amount, invalid_items.*, invalid_sponsor.* y otros | property_value | property_value consolida los errores de validación por campo. El campo con error está indicado en el detalle de la respuesta. |
400 → 401 | (autenticación vía middleware, 400) | unauthorized | En la API QR Modelo dinámico, era 400. En la API de Orders, es 401 explícito. |
Errores que permanecen iguales
El siguiente error tiene el mismo comportamiento en ambas APIs.
| HTTP | Error | Observación |
500 | Genérico | Error interno. Verifica el retorno y repite la solicitud. |
Errores introducidos por la API de Orders
Los siguientes errores no tienen equivalente en la API QR Modelo dinámico.
| HTTP | Error | Observación |
400 | sponsor_id_not_valid | Valor inválido como integration_data.sponsor.id. |
400 | marketplace_not_valid | El Access Token no fue obtenido vía OAuth. |
400 | empty_required_header | X-Idempotency-Key ausente. |
400 | unsupported_site | País no soportado. |
400 | unsupported_properties | Propiedad no soportada en el body. El campo con error está indicado en el detalle de la respuesta. |
401 | unauthorized | Access Token inválido o expirado. |
404 | pos_not_found | El external_pos_id no pertenece a ninguna caja. |
404 | marketplace_fee_not_allowed | No se permite enviar marketplace_fee. El marketplace no fue encontrado. |
409 | idempotency_key_already_used | El X-Idempotency-Key ya fue utilizado con una solicitud distinta en las últimas 24 horas. |
Actualizar la consulta de orders
El endpoint de consulta GET /v1/orders/{order_id}API está disponible para los modos dinámico e híbrido en la API de Orders. En la API QR Modelo dinámico, la consulta existía solo para el flujo PUT y consultaba por caja, no por order. El flujo POST no tenía endpoint de consulta. El estado se obtenía exclusivamente vía notificaciones de payments y merchant_orders.
La API de Orders permite consultar el estado completo de la order directamente por el order_id, incluyendo estado, pagos, reembolsos y datos del medio de pago.
curl
curl -X GET \ 'https://api.mercadopago.com/v1/orders/{{ORDER_ID}}' \ -H 'Authorization: Bearer {{ACCESS_TOKEN}}'
Los campos legacy de esta tabla corresponden al endpoint de consulta del flujo PUT únicamente. En el flujo POST, todos los campos del response son nuevos.
La tabla a continuación presenta los campos del flujo PUT que existían en ambas APIs y sufrieron cambios en la migración.
| API QR Modelo dinámico, flujo PUT | API de Orders | Descripción | Cambio |
| No existe | id | Identificador de la order. | Campo nuevo. El endpoint de consulta legacy no retornaba el ID del pedido. |
external_reference | external_reference | Referencia externa de la order. | Sin cambio. |
description | description | Descripción de la compra. | Sin cambio. |
title | No existe | Título de la compra. | Eliminado. |
notification_url | No existe | URL configurada para notificaciones. | Eliminado. |
expiration_date | expiration_time | Validez del pedido. En la API QR Modelo dinámico, era fecha absoluta. En la API de Orders, es duración relativa en ISO 8601. En todos los modos, el valor predeterminado es de 15 minutos y el valor enviado siempre se respeta. | Cambia de fecha absoluta a duración relativa. |
total_amount | total_amount | Valor total de la order. En la API QR Modelo dinámico, era number. En la API de Orders, es string decimal. | Cambia de number a string decimal. |
marketplace_fee | marketplace_fee | Tarifa del marketplace. En la API QR Modelo dinámico, era number. En la API de Orders, es string decimal. | Cambia de number a string decimal. |
sponsor.id | integration_data.sponsor.id | USER_ID del sistema integrador. En la API QR Modelo dinámico, era integer. En la API de Orders, es string. | Pasa a integration_data.sponsor. Cambia de integer a string. |
La API de Orders también introduce los siguientes campos en la respuesta de consulta.
| Campo | Descripción |
status | Estado actual de la order. Valores: created, canceled, processed, refunded, expired. En el flujo POST, el estado se obtenía solo vía webhooks. |
status_detail | Detalle del estado actual de la order. Los valores posibles son created, canceled, accredited, refunded, expired. |
currency | Moneda de la order. Valores: ARS, BRL, CLP, UYU. |
created_date / last_updated_date | Fechas de creación y última actualización. Formato yyyy-MM-ddTHH:mm:ss.sssZ. |
config.qr.external_pos_id | Identificador externo de la caja asociada a la order. |
config.qr.mode | Modo de Código QR configurado. |
transactions.payments[].id | Identificador de la transacción de pago. |
transactions.payments[].amount | Valor del pago. |
transactions.payments[].refunded_amount | Valor reembolsado. Presente solo cuando hubo reembolso. |
transactions.payments[].paid_amount | Valor total pagado. |
transactions.payments[].status | Estado actual del pago. |
transactions.payments[].status_detail | Estado detallado del pago. |
transactions.payments[].reference_id | Identificador del pago asociado a la order. |
transactions.payments[].payment_method.type | Medio de pago seleccionado. |
transactions.payments[].payment_method.installments | Cantidad de cuotas. |
transactions.payments[].payment_method.id | Identificador del medio de pago o marca. |
transactions.payments[].discounts.type | Medio de pago con el que se aplicó el descuento. Presente solo si se aplicó un descuento. |
transactions.refunds[].id | Identificador del reembolso. |
transactions.refunds[].transaction_id | Identificador del pago que está siendo reembolsado. |
transactions.refunds[].amount | Valor del reembolso. |
transactions.refunds[].status | Estado del reembolso. |
En la consulta, los errores se agruparon según el tipo de cambio. Consulta las tablas a continuación para más detalles.
Errores que desaparecen
Los siguientes errores existen en la API QR Modelo dinámico en el flujo PUT, pero no tienen equivalencia en la API de Orders.
| HTTP | API QR Modelo dinámico | Observación |
400 | invalid_collectorId | Eliminado en la API de Orders. La consulta opera sobre el order_id. |
400 | invalid_externalPosId | Eliminado. La consulta opera sobre order_id, no sobre la caja. |
400 | pos_obtainment_by_external_id_error | Eliminado. El concepto de POS como parámetro de consulta desaparece. |
400 | pos_deleted_error | Eliminado en la API de Orders. |
403 | forbidden | Eliminado en la API de Orders. |
Errores renombrados
Los siguientes errores fueron renombrados en la API de Orders.
| HTTP | API QR Modelo dinámico | API de Orders | Observación |
404 | point_of_sale_in_store_order_not_found y in_store_order_not_found | order_not_found | Los dos casos se unifican en order_not_found. |
Errores que cambian de comportamiento
Los siguientes errores existen en ambas APIs pero con un comportamiento diferente en la API de Orders.
| HTTP | API QR Modelo dinámico | API de Orders | Observación |
400 → 401 | autenticación vía middleware | unauthorized | En la API QR Modelo dinámico, era 400. En la API de Orders, es 401 explícito. |
Errores introducidos por la API de Orders
Los siguientes errores no tienen equivalente en la API QR Modelo dinámico.
| HTTP | Error | Observación |
400 | invalid_path_param | El order_id tiene formato inválido. Debe comenzar con ORD seguido de 26 caracteres. |
401 | unauthorized | Access Token inválido o expirado. |
404 | order_not_found | El order_id no corresponde a ninguna order creada. |
500 | Genérico | Error interno. Verifica el retorno y repite la solicitud. |
Actualizar la cancelación de orders
El endpoint de cancelación POST /v1/orders/{order_id}/cancelAPI está disponible para ambos modos en la API de Orders. En la API QR Modelo dinámico, la cancelación existía solo para el flujo PUT y cancelaba la order asociada a la caja vía DELETE. El flujo POST no tenía endpoint de cancelación.
El método HTTP cambia de DELETE a POST, el {user_id} y el {external_pos_id} salen del path, y la operación pasa a identificar la order por el order_id. El response pasó de vacío (HTTP 204) al objeto completo de la order con status: "canceled" (HTTP 200).
| Header | Obligatoriedad | Descripción |
X-Idempotency-Key | Obligatorio | Clave única por solicitud. |
El response incluye los siguientes campos de la order cancelada.
| Campo | Descripción |
id | Identificador de la order cancelada. |
user_id | Identificador del usuario que creó la order. |
type | Tipo de order. Para QR: siempre qr. |
external_reference | Referencia externa de la order. |
description | Descripción del producto o servicio. |
expiration_time | Tiempo de expiración en formato ISO 8601. |
processing_mode | Modo de procesamiento. Para QR: siempre automatic. |
total_amount | Valor total de la order. |
country_code | Identificador del sitio/país. |
marketplace_fee | Tarifa del marketplace. Exclusivo para integraciones con OAuth. |
integration_data.application_id | Identificador de la aplicación de Mercado Pago. |
integration_data.platform_id | Identificador de la plataforma, asignado por Mercado Pago. |
integration_data.integrator_id | Identificador del integrador, asignado por Mercado Pago. |
integration_data.sponsor.id | USER_ID del sistema integrador. |
status | Estado actual de la order. Al cancelar: canceled. |
status_detail | Detalle del estado. Al cancelar: canceled. |
currency | Identificador de la moneda. Valores: ARS, BRL, CLP, UYU. |
created_date | Fecha de creación. Formato yyyy-MM-ddTHH:mm:ss.sssZ. |
last_updated_date | Fecha de la última actualización. Formato yyyy-MM-ddTHH:mm:ss.sssZ. |
config.qr.external_pos_id | Identificador externo de la caja asociada a la order. |
config.qr.mode | Modo de Código QR configurado. |
transactions.payments[].id | Identificador de la transacción de pago. |
transactions.payments[].amount | Valor del pago. |
transactions.payments[].status | Estado del pago. Al cancelar: canceled. |
transactions.payments[].status_detail | Detalle del estado del pago. Al cancelar: canceled_by_api. |
items[].title | Nombre del ítem. |
items[].unit_price | Precio unitario del ítem. |
items[].quantity | Cantidad de ítems. |
items[].unit_measure | Unidad de medida del ítem. |
items[].external_code | Código externo del ítem. |
items[].external_categories[].id | Identificador de categoría del ítem en el sistema externo. |
discounts.payment_methods[].new_total_amount | Nuevo valor total cuando se aplica un descuento. |
discounts.payment_methods[].type | Medio de pago al que se aplica el descuento. |
En la cancelación, los errores se agruparon según el tipo de cambio. Consulta las tablas a continuación para más detalles.
Errores que desaparecen
Los siguientes errores existen en la API QR Modelo dinámico en el flujo PUT, pero no tienen equivalencia en la API de Orders.
| HTTP | API QR Modelo dinámico | Observación |
400 | invalid_collectorId | Eliminado en la API de Orders. |
400 | invalid_externalPosId | Eliminado. El {external_pos_id} deja de ser parámetro de path. |
400 | pos_deleted_error | Eliminado en la API de Orders. |
403 | forbidden | Eliminado. La identidad se valida internamente por el Access Token. |
Errores renombrados
Los siguientes errores fueron renombrados en la API de Orders.
| HTTP | API QR Modelo dinámico | API de Orders | Observación |
400 → 404 | pos_obtainment_by_external_id_error y in_store_order_delete_error (order no encontrada) | order_not_found | En la API QR Modelo dinámico, era 400. En la API de Orders, es 404. La cancelación pasa a operar sobre el order_id. |
409 | in_store_order_delete_error (Cannot delete a locked order) | instore_order_locked_error | Mismo concepto. El nombre del código de error cambia. |
Errores que cambian de comportamiento
Los siguientes errores existen en ambas APIs pero con un comportamiento diferente en la API de Orders.
| HTTP | API QR Modelo dinámico | API de Orders | Observación |
400 → 401 | autenticación vía middleware | unauthorized | En la API QR Modelo dinámico, era 400. En la API de Orders, es 401 explícito. |
Errores que permanecen iguales
El siguiente error tiene el mismo comportamiento en ambas APIs.
| HTTP | Error | Observación |
500 | Genérico | Error interno. Verifica el retorno y repite la solicitud. |
Errores introducidos por la API de Orders
Los siguientes errores no tienen equivalente en la API QR Modelo dinámico.
| HTTP | Error | Observación |
400 | empty_required_header | X-Idempotency-Key ausente. |
400 | invalid_path_param | El order_id tiene formato inválido. |
401 | unauthorized | Access Token inválido o expirado. |
404 | order_not_found | El order_id no corresponde a ninguna order creada. |
409 | idempotency_key_already_used | El X-Idempotency-Key ya fue utilizado con una solicitud distinta. |
409 | order_already_canceled | La order ya está cancelada. Las orders solo pueden cancelarse con status: created. |
Implementar reembolsos con el endpoint dedicado
La API de Orders introduce el endpoint dedicado POST /v1/orders/{order_id}/refundAPI para reembolsos, que no existía en la API QR Modelo dinámico en ninguno de los dos flujos. Antes era necesario recibir el webhook del pago, obtener el payment_id y ejecutar el reembolso por la API de Payments por separado. Ahora, el reembolso se realiza directamente sobre la order, para ambos modos.
Elige entre reembolso total o parcial según el valor a devolver.
Para reembolsar el valor total de la order, envía la solicitud al endpoint POST /v1/orders/{order_id}/refundAPI sin body.
curl
curl -X POST \ 'https://api.mercadopago.com/v1/orders/{{ORDER_ID}}/refund' \ -H 'Authorization: Bearer {{ACCESS_TOKEN}}' \ -H 'X-Idempotency-Key: {{IDEMPOTENCY_KEY}}'
Los reembolsos se aceptan hasta 360 días a partir de la fecha del pago.
El response del reembolso varía según el tipo de operación realizada.
| Campo | Tipo | Descripción |
id | string | Identificador de la order reembolsada. |
status | string | refunded para reembolso total. processed para reembolso parcial (aún hay saldo disponible). |
status_detail | string | refunded para reembolso total. partially_refunded para reembolso parcial. |
transactions.refunds[].id | string | Identificador del reembolso, generado por Mercado Pago. |
transactions.refunds[].transaction_id | string | Identificador de la transacción de pago que está siendo reembolsada. |
transactions.refunds[].amount | string | Valor del reembolso. Si el pago fue realizado con descuento, refleja ese valor. |
transactions.refunds[].status | string | processing cuando el reembolso total fue solicitado y está en procesamiento. processed cuando el reembolso parcial fue completado con éxito. |
transactions.refunds[].reference_id | string | Identificador que asocia el pago a su respectivo reembolso. |
Validar la migración
Después de aplicar los cambios, verifica que la integración opera correctamente en todos los flujos antes de ir a producción.
El header X-Idempotency-Key debe estar presente en todas las operaciones de creación, cancelación y reembolso.
Orders creadas con éxito a través del endpoint POST /v1/ordersAPI con config.qr.mode: dynamic (equivalente al flujo POST de la API legacy).
Orders creadas con éxito a través del endpoint POST /v1/ordersAPI con config.qr.mode: hybrid (equivalente al flujo PUT de la API legacy).
El campo id fue capturado del response de creación para uso en consultas, cancelaciones y reembolsos posteriores.
Orders consultadas con éxito a través del endpoint GET /v1/orders/{order_id}API en ambos modos.
Estado de orders monitoreado vía webhook con el tópico "Order (Mercado Pago)" y los nuevos valores: created, processed, canceled, refunded y expired.
Orders canceladas con éxito a través del endpoint POST /v1/orders/{order_id}/cancelAPI en ambos modos.
Reembolsos ejecutados a través del endpoint dedicado POST /v1/orders/{order_id}/refundAPI.
Accede a la documentación para saber cómo probar la integración.