# MD for: https://www.mercadopago.com.ar/developers/en/docs/mp-point/migrate-payment-intent-to-orders.md \# How to migrate from the Payment Intent API to the Orders API The Orders API unifies in-person payment processing for Mercado Pago Point, providing standardized endpoints, a more complete status model, and new native capabilities that did not exist in the Payment Intent API. In addition, all new Mercado Pago features will be developed on the Orders API. Migrating your Mercado Pago Point integration from the Payment Intent API to the Orders API involves \*\*updating endpoints and request fields\*\*, \*\*adapting the status model\*\*, and leveraging \*\*new native resources\*\*. The new API introduces self-contained statuses, configurable order expiration (\`expiration\_time\`), and a dedicated refund endpoint. The migration does not change the business flow: the terminal continues receiving orders created by the backend and processing payments autonomously. Read on to learn how to complete this migration. ## Map the endpoint changes Before starting the migration steps, see the table below for an overview of all endpoint changes. In the Payment Intent API, each operation had its own URL structure with the device identifier in the path. The Orders API consolidates these operations into standardized endpoints and removes the \`{deviceid}\` from the path in all operations. | Operation | Payment Intent API | Orders API | |---|---|---| | List terminals | :TagComponent{tag="API" text="GET /point/integration-api/devices" href="/developers/en/reference/integrations\_api/\_point\_integration-api\_devices/get"} | :TagComponent{tag="API" text="GET /terminals/v1/list" href="/developers/en/reference/in-person-payments/point/terminals/get-terminals/get"} | | Update terminal operating mode | :TagComponent{tag="API" text="PATCH /point/integration-api/devices/{device\_id}" href="/developers/en/reference/integrations\_api/\_point\_integration-api\_devices\_device-id/patch"} | :TagComponent{tag="API" text="PATCH /terminals/v1/setup" href="/developers/en/reference/in-person-payments/point/terminals/update-operation-mode/patch"} | | Create payment intent vs. Create order | :TagComponent{tag="API" text="POST /point/integration-api/devices/{deviceid}/payment-intents" href="/developers/en/reference/integrations\_api/\_point\_integration-api\_devices\_deviceid\_payment-intents/post"} | :TagComponent{tag="API" text="POST /v1/orders" href="/developers/en/reference/in-person-payments/point/orders/create-order/post"} | | Get payment intent vs. Get order | :TagComponent{tag="API" text="GET /point/integration-api/payment-intents/{paymentintentid}" href="/developers/en/reference/integrations\_api/\_point\_integration-api\_payment-intents\_paymentintentid/get"} | :TagComponent{tag="API" text="GET /v1/orders/{orderid}" href="/developers/en/reference/in-person-payments/point/orders/get-order/get"} | | Cancel payment intent vs. Cancel order | :TagComponent{tag="API" text="DELETE /point/integration-api/devices/{deviceid}/payment-intents/{paymentintentid}" href="/developers/en/reference/integrations\_api/\_point\_integration-api\_devices\_deviceid\_payment-intents\_paymentintentid/delete"} | :TagComponent{tag="API" text="POST /v1/orders/{orderid}/cancel" href="/developers/en/reference/in-person-payments/point/orders/cancel-order/post"} | | Refund order | No dedicated endpoint existed | :TagComponent{tag="API" text="POST /v1/orders/{orderid}/refund" href="/developers/en/reference/in-person-payments/point/orders/refund-order/post"} | ## Adapt the headers The Orders API introduces two mandatory \*header\* changes that affect all endpoints: the sandbox mechanism was removed and a new idempotency control was introduced. Apply the following changes before testing any other resource. :::AccordionComponent{title="Remove the x-test-scope header" pill="1"} The \`x-test-scope: sandbox\` header was used in the Payment Intent API to identify test requests. In the Orders API, the sandbox mechanism was restructured and this header no longer exists. Remove it from all integration requests. To operate in a test environment with the Orders API, use test users. See the \[integration test documentation\](https://www.mercadopago.com.ar/developers/en/docs/mp-point/integration-test) for more information. ::: :::AccordionComponent{title="Add the X-Idempotency-Key header" pill="2"} The \`X-Idempotency-Key\` header is required for order creation, cancellation, and refund operations. It ensures that a repeated request with the same key returns the original result without processing the operation again. Send a unique UUID v4 or random string per request. GET operations do not require this header. > WARNING > > If the same \`X-Idempotency-Key\` is reused with a different body, the API will return the \`idempotency\_key\_already\_used\` error. Generate a new key for each distinct operation. ::: ## Update terminal listing and configuration The terminal endpoints changed URL: listing moves from \`GET /point/integration-api/devices\` to \`GET /terminals/v1/list\` and mode update moves from \`PATCH /point/integration-api/devices/{device\_id}\` to \`PATCH /terminals/v1/setup\`. In the mode update, the terminal identifier also moves from the path to the body, allowing multiple terminals to be updated in a single call. :::AccordionComponent{title="Migrate the terminal listing" pill="1"} In the Payment Intent API, devices were returned in the \`devices\` array. In the Orders API, they move to \`data.terminals\`. The query params \`store\_id\`, \`pos\_id\`, \`limit\`, and \`offset\` remain the same. The table below describes the response changes. | Payment Intent API | Orders API | Description | Change | |---|---|---|---| | \`devices\[\]\` | \`data.terminals\[\]\` | List of terminals associated with the account. In the Payment Intent API, it was returned as a direct array in \`devices\`. In the Orders API, it is moved inside the \`data\` object and renamed to \`terminals\`. | Renamed and moved inside the \`data\` object. | | \`devices\[\].id\` | \`data.terminals\[\].id\` | Unique terminal identifier. The last characters match the serial number on the back label of the terminal. | Same concept. The ID format may vary depending on the terminal model. | | \`devices\[\].pos\_id\` | \`data.terminals\[\].pos\_id\` | Identifier of the point of sale associated with the terminal. | No changes. | | \`devices\[\].store\_id\` (integer) | \`data.terminals\[\].store\_id\` (string) | Identifier of the store associated with the terminal. In the Payment Intent API, it was returned as integer. In the Orders API, it is returned as string. | Changes from integer to string. | | \`devices\[\].external\_pos\_id\` | \`data.terminals\[\].external\_pos\_id\` | External point of sale identifier, defined by the integrator. | No changes. | | \`devices\[\].operating\_mode\` | \`data.terminals\[\].operating\_mode\` | Terminal operating mode. In the Payment Intent API, the possible values are \`PDV\` and \`STANDALONE\`. In the Orders API, the \`UNDEFINED\` value is added for unrecognized configurations. | Adds the \`UNDEFINED\` value for unrecognized configurations. | | \`paging.total\` / \`paging.offset\` / \`paging.limit\` | \`paging.total\` / \`paging.offset\` / \`paging.limit\` | Listing pagination data: total records, start point, and limit. | No changes. | In the terminal listing, errors are grouped by type of change. See the tables below for more details. ### Errors not documented in the Orders API The following errors exist in the Payment Intent API but are not documented in the Orders API. | HTTP | Payment Intent API | Note | |---|---|---| | \`400\` | \`bad\_request\` | Required parameter missing or with incorrect format. | | \`400\` | \`bad\_request\` | Invalid request format. | | \`403\` | \`forbidden\` | Present in the Payment Intent API. | ### Errors that remain unchanged The following errors have the same behavior in both APIs. | HTTP | Error | Note | |---|---|---| | \`401\` | \`unauthorized\` | Invalid or expired token. | | \`500\` | \`internal\_error\` | Internal error. Check the response and retry. | ::: :::::AccordionComponent{title="Migrate the operating mode update" pill="2"} In the Payment Intent API, only one terminal could be updated per call and its identifier was sent in the path. In the Orders API, the identifier moves to the body inside the \`terminals\[\]\` array, allowing multiple terminals to be updated in a single call. Below is a comparative example of an operating mode update. ::::TabsComponent :::TabComponent{title="Payment Intent API"} Operating mode update via the Payment Intent API. The terminal identifier is sent as a path param. \`\`\`curl curl -X PATCH \\ 'https://api.mercadopago.com/point/integration-api/devices/{{DEVICE\_ID}}' \\ -H 'Authorization: Bearer {{ACCESS\_TOKEN}}' \\ -d '{ "operating\_mode": "PDV" }' \`\`\` ::: :::TabComponent{title="API de Orders"} Update via the Orders API. The terminal identifier goes in the body, inside the \`terminals\[\]\` array. \`\`\`curl curl -X PATCH \\ 'https://api.mercadopago.com/terminals/v1/setup' \\ -H 'Authorization: Bearer {{ACCESS\_TOKEN}}' \\ -d '{ "terminals": \[ { "id": "{{TERMINAL\_ID}}", "operating\_mode": "PDV" } \] }' \`\`\` ::: :::: In the Payment Intent API, the response returns only the \`operating\_mode\` field. In the Orders API, the response returns the \`terminals\[\]\` array with \`id\` and \`operating\_mode\`, identifying each updated terminal. See the table below for the complete mapping. | Payment Intent API | Orders API | Description | Change | |---|---|---|---| | \`operating\_mode\` | \`terminals\[\].operating\_mode\` | Operating mode defined for the terminal. In the Payment Intent API, it was returned as a single field. In the Orders API, it is returned inside the \`terminals\[\]\` array. The possible values are \`PDV\` and \`STANDALONE\`. | Moves inside the \`terminals\[\]\` array. | The Orders API also introduces the following field with no equivalent in the Payment Intent API. | Field | Description | |---|---| | \`terminals\[\].id\` | Unique identifier of the updated terminal. It is returned only in the Orders API. | In the operating mode update, errors are grouped by type of change. See the tables below for more details. ### Errors that disappear The following error exists in the Payment Intent API but was removed in the Orders API. | HTTP | Payment Intent API | Note | |---|---|---| | \`424\` | \`failed\_dependency\` | Code removed in the Orders API. | ### Renamed errors The following error was renamed in the Orders API. | HTTP | Payment Intent API | Orders API | Note | |---|---|---|---| | \`403\` | \`forbidden\` | \`store\_pos\_not\_found\` | Terminal has no associated store or point of sale. | ### Errors that change behavior The following error exists in both APIs but with a different meaning in the Orders API. | HTTP | Payment Intent API | Orders API | Note | |---|---|---|---| | \`400\` | \`bad\_request\` | \`property\_value\` | Invalid \`device\_id\` or \`operating\_mode\` value. | ### Errors that remain unchanged The following errors have the same behavior in both APIs. | HTTP | Error | Note | |---|---|---| | \`401\` | \`unauthorized\` | Invalid or expired token. | | \`500\` | \`internal\_error\` | Internal error. Retry the request. | ### Errors introduced by the Orders API The following errors have no equivalent in the Payment Intent API. | HTTP | Orders API error | Note | |---|---|---| | \`400\` | \`unsupported\_site\` | Invalid site. | | \`400\` | \`required\_properties\` | Required property missing. | | \`400\` | \`unsupported\_properties\` | Unsupported field sent. | | \`400\` | \`invalid\_payload\` | Invalid payload. Check the submitted fields. | | \`403\` | \`terminal\_not\_allowed\_action\` | Action not allowed for this terminal model. | | \`404\` | \`not\_found\` | Resource not found or invalid ID. | | \`412\` | \*(no string code)\* | Operation not allowed: a terminal is already associated with the point of sale in PDV mode. Only one terminal per point of sale is allowed in PDV mode. | ::::: ## Migrate payment intent creation to order creation The creation endpoint changes from \`POST /point/integration-api/devices/{deviceid}/payment-intents\` to \`POST /v1/orders\`. Beyond the URL change, the request structure was significantly reorganized: the terminal identifier moves from the path to the body, new required fields were introduced, and the Orders API has a distinct structure. Follow the steps below to adapt the request, response, and error handling. \`\`\`curl curl -X POST \\ 'https://api.mercadopago.com/v1/orders' \\ -H 'Content-Type: application/json' \\ -H 'X-Idempotency-Key: {{IDEMPOTENCY\_KEY}}' \\ -H 'Authorization: Bearer {{ACCESS\_TOKEN}}' \\ -d '{ "type": "point", "external\_reference": "ext\_ref\_1234", "transactions": { "payments": \[ { "amount": "24.00" } \] }, "config": { "point": { "terminal\_id": "{{TERMINAL\_ID}}", "print\_on\_terminal": "no\_ticket" } }, "description": "Point Smart 2" }' \`\`\` :::::AccordionComponent{title="Map the request body fields" pill="1"} The Orders API has a different structure from the Payment Intent API: the terminal identifier must be sent in the body, payment and printing configuration fields are placed in new nodes, and identification headers become part of the body. The new required fields are \`type\` (with value \`"point"\`) and \`external\_reference\`. See the table below for the complete field mapping. Below is a comparative example between creating a payment intent and creating an order, followed by the complete field mapping table. ::::TabsComponent :::TabComponent{title="Payment Intent API"} Request to create a payment intent. The terminal identifier is sent as a path param and \`amount\` is an integer value. \`\`\`curl curl -X POST \\ 'https://api.mercadopago.com/point/integration-api/devices/{{DEVICE\_ID}}/payment-intents' \\ -H 'Authorization: Bearer {{ACCESS\_TOKEN}}' \\ -H 'x-test-scope: sandbox' \\ -d '{ "amount": 1500, "additional\_info": { "external\_reference": "order-ref-001", "print\_on\_terminal": true }, "description": "Test product" }' \`\`\` ::: :::TabComponent{title="API de Orders"} Request to create an order. The terminal identifier goes in the body and \`type: "point"\` is required. \`\`\`curl curl -X POST \\ 'https://api.mercadopago.com/v1/orders' \\ -H 'Authorization: Bearer {{ACCESS\_TOKEN}}' \\ -H 'X-Idempotency-Key: {{IDEMPOTENCY\_KEY}}' \\ -d '{ "type": "point", "external\_reference": "order-ref-001", "description": "Test product", "config": { "point": { "terminal\_id": "{{TERMINAL\_ID}}", "print\_on\_terminal": "seller\_ticket" } }, "transactions": { "payments": \[ { "amount": "15.00" } \] } }' \`\`\` ::: :::: | Payment Intent API | Orders API | Description | Change | |---|---|---|---| | \`{deviceid}\` (path param) | \`config.point.terminal\_id\` | Identifies the terminal that will receive the order. In the Payment Intent API, it is sent as a path parameter. In the Orders API, it is sent in the body in the format \`{terminal\_type}\_\_{terminal\_serial}\`. | Moves from path param to body field. | | \`amount\` (integer) | \`transactions.payments\[\].amount\` (string) | Amount to charge. In the Payment Intent API, it is represented as an integer with implicit two decimals (e.g.: \`1500\` for $15.00). In the Orders API, it is represented as a string inside the \`transactions.payments\` array. Accepts two decimal places (e.g.: \`"15.00"\`) or none. Only 1 transaction per order is allowed when \`type\` is \`point\`. | Changes from integer to string and enters the \`transactions.payments\` array. | | \`additional\_info.external\_reference\` | \`external\_reference\` | Alphanumeric identifier for the transaction in the integrator's system, returned in webhook notifications. In the Orders API, it is required, with a maximum of 64 characters, only letters, numbers, \`-\` and \`\_\`. Must be unique per order and cannot contain PII data. | Moves to root level and becomes \*\*required\*\*. | | \`additional\_info.print\_on\_terminal\` (boolean) | \`config.point.print\_on\_terminal\` (string) | Controls ticket printing on the terminal. In the Payment Intent API, it accepts the boolean values \`true\` and \`false\`. In the Orders API, it accepts the values \`seller\_ticket\` (prints) and \`no\_ticket\` (does not print). Default value: \`seller\_ticket\`. | Changes from boolean to enum string. | | \`payment.type\` | \`config.payment\_method.default\_type\` | Defines the payment method accepted by the terminal. In the Payment Intent API, the possible values are \`credit\_card\`, \`debit\_card\`. In the Orders API, the possible values are \`credit\_card\`, \`debit\_card\`, and \`qr\`. If not sent, the terminal accepts all payment methods. | Changes node and now also accepts \`qr\`. | | \`description\` | \`description\` | Describes the product, service, or payment reason. In the Orders API, it accepts up to 150 characters. | No changes. | | \`X-platform-id\` (header) | \`integration\_data.platform\_id\` | Identifies the integration platform, assigned by Mercado Pago. In the Payment Intent API, it was sent as a header. In the Orders API, it is sent in the body inside \`integration\_data\`. | Moves from header to body. | | \`X-integrator-id\` (header) | \`integration\_data.integrator\_id\` | Identifies the integrator, assigned by Mercado Pago. In the Payment Intent API, it was sent as a header. In the Orders API, it is sent in the body inside \`integration\_data\`. | Moves from header to body. | | \`additional\_info.ticket\_number\` | \`config.point.ticket\_number\` | Alphanumeric value to identify the invoice or ticket number, printed on the terminal when printing is enabled. | Moves to \`config.point\`. | ------------ The Orders API also introduces the following fields with no equivalent in the Payment Intent API. | Field | Description | |---|---| | \`integration\_data.sponsor.id\` | USER\_ID of the Mercado Pago account of the integrating system. | | \`type\` | Order type. For Point, the only accepted value is \`"point"\`. \*\*Required.\*\* | | \`expiration\_time\` | Defines the order validity period from creation, in ISO 8601 format. The minimum value is \`PT30S\` (30 seconds), the maximum value is \`PT3H\` (3 hours) and the default value is \`PT15M\` (15 minutes). Examples: \`PT30S\` for 30 seconds, \`PT10M\` for 10 minutes, \`PT1H15M\` for 1 hour and 15 minutes. If the order expires without being processed, it is automatically canceled. \*\*Optional.\*\* | The order ID format changes from UUID (e.g.: \`7f25f9aa-eea6-...\`) to alphanumeric (e.g.: \`ORD00001111222233334444555566\`). Update any storage or query logic that depends on the ID format before proceeding. > SUCCESS\_MESSAGE > > Check all available parameters in the :TagComponent{tag="API" text="API Reference" href="/developers/en/reference/in-person-payments/point/orders/create-order/post"}. ::::: :::AccordionComponent{title="Adapt the creation response fields" pill="2"} The table below shows the creation response fields that existed in both APIs and were updated during the migration. | Payment Intent API | Orders API | Description | Change | |---|---|---|---| | \`id\` (UUID) | \`id\` (alphanumeric) | Order identifier, generated by Mercado Pago. In the Payment Intent API, it is returned in UUID format. In the Orders API, it is returned in alphanumeric format with \`ORD\` prefix. | ID format changes to \`ORD...\`. | | \`device\_id\` | \`config.point.terminal\_id\` | Identifier of the terminal that received the order. | Moves to \`config.point\`. | | \`amount\` (integer) | \`transactions.payments\[\].amount\` (string) | Payment amount. In the Payment Intent API, it is returned as an integer. In the Orders API, it is returned as a decimal string inside the payments array. | Moves to the payments array. | | \`additional\_info.external\_reference\` | \`external\_reference\` | External reference of the order in the integrator's system. | Moves to root level. | | \`additional\_info.print\_on\_terminal\` (boolean) | \`config.point.print\_on\_terminal\` (string) | Indicates whether the terminal printed the ticket. In the Payment Intent API, it is returned as a boolean. In the Orders API, it is returned as an enum string: \`seller\_ticket\` or \`no\_ticket\`. | Changes from boolean to enum string. | | \`additional\_info.ticket\_number\` | \`config.point.ticket\_number\` | Alphanumeric value to identify the invoice or ticket number, printed on the terminal when printing is enabled. | Moves to \`config.point\`. | The Orders API also introduces the following fields with no equivalent in the Payment Intent API. | Field | Description | |---|---| | \`status\` | Current order status. On creation: \`created\`. | | \`status\_detail\` | Order status detail. On creation: \`created\`. | | \`type\` | Order type. For Point: always \`point\`. | | \`expiration\_time\` | Order validity period in ISO 8601 format. If the order expires without being processed, it is automatically canceled. | | \`created\_date\` / \`last\_updated\_date\` | Records the order creation and last update dates in \`yyyy-MM-ddTHH:mm:ss.sssZ\` format. | | \`transactions.payments\[\].id\` | Payment transaction identifier, generated by Mercado Pago. Required for partial refunds. | | \`transactions.payments\[\].status\` | Payment transaction status. On creation: \`created\`. | | \`user\_id\` | Identifier of the Mercado Pago user who created the order. | | \`processing\_mode\` | Order processing mode. For Point: always \`automatic\`. | | \`country\_code\` | Application site/country identifier. | | \`integration\_data.application\_id\` | Mercado Pago application identifier. | | \`integration\_data.platform\_id\` | Platform identifier, assigned by Mercado Pago. | | \`integration\_data.integrator\_id\` | Integrator identifier, assigned by Mercado Pago. | | \`integration\_data.sponsor.id\` | USER\_ID of the integrating system. | ::: :::AccordionComponent{title="Update error handling in creation" pill="3"} In creation, errors are grouped by type of change. See the tables below for more details. ### Errors that change behavior In the Payment Intent API, the following errors returned the generic \`bad\_request\` code. In the Orders API, they are replaced by specific codes. | HTTP | Payment Intent API | Orders API | Note | |---|---|---|---| | \`400\` | \`bad\_request\` | \`required\_properties\` | Required property missing. | | \`400\` | \`bad\_request\` | \`property\_value\` | Invalid value in a property. | | \`400\` | \`bad\_request\` | \`property\_type\` | Incorrect type. For example: \*integer\* instead of \*string\*. | | \`400\` | \`bad\_request\` | \`json\_syntax\_error\` | Invalid JSON. | | \`400\` | \`bad\_request\` | \`unsupported\_properties\` | Unsupported property sent. | ### Renamed errors The following errors were renamed in the Orders API. | HTTP | Payment Intent API | Orders API | Note | |---|---|---|---| | \`403\` | \`forbidden\` | \`forbidden\_checking\_terminal\_owner\` | Terminal not linked to the account. | | \`409\` | \`conflict\_error\` | \`already\_queued\_order\_for\_terminal\` | An order is already queued for this terminal. | ### Errors that disappear The following error exists in the Payment Intent API but was removed in the Orders API. | HTTP | Payment Intent API | Note | |---|---|---| | \`424\` | \`failed\_dependency\` | Code removed in the Orders API. | ### Errors that remain unchanged The following error has the same behavior in both APIs. | HTTP | Error | Note | |---|---|---| | \`401\` | \`unauthorized\` | Invalid or expired token. | | \`500\` | \`internal\_error\` | Internal error. Check the response and retry the request. | ### Errors introduced by the Orders API The following errors have no equivalent in the Payment Intent API. | HTTP | Orders API error | Note | |---|---|---| | \`400\` | \`empty\_required\_header\` | \`X-Idempotency-Key\` missing. | | \`400\` | \`minimum\_properties\` | Minimum number of required properties not sent. | | \`400\` | \`minimum\_items\` / \`maximum\_items\` | Invalid number of items in the \`transactions.payments\` array. | | \`409\` | \`idempotency\_key\_already\_used\` | Idempotency key reused with a different body. | | \`500\` | \`idempotency\_validation\_failed\` | Idempotency validation failure. Retry the request. | ::: ## Update the query mechanism from Payment Intent to Orders The query endpoint changes from :TagComponent{tag="API" text="GET /point/integration-api/payment-intents/{paymentintentid}" href="/developers/en/reference/integrations\_api/\_point\_integration-api\_payment-intents\_paymentintentid/get"} to :TagComponent{tag="API" text="GET /v1/orders/{orderid}" href="/developers/en/reference/in-person-payments/point/orders/get-order/get"}. The order identifier in the path also changes from UUID to alphanumeric format. The response includes new fields with information about the payment result, refunds, and card data. \`\`\`curl curl -X GET \\ 'https://api.mercadopago.com/v1/orders/{{ORDER\_ID}}' \\ -H 'Content-Type: application/json' \\ -H 'Authorization: Bearer {{ACCESS\_TOKEN}}' \`\`\` :::AccordionComponent{title="Adapt the query response fields" pill="1"} In addition to the fields documented in the creation response, the \*\*GET\*\* response includes additional fields relevant to the migration. See the table below for details. | Payment Intent API | Orders API | Description | Change | |---|---|---|---| | \`state\` | \`status\` | Order status. In the Payment Intent API, \`state\` field with uppercase values. In the Orders API, \`status\` field with lowercase values and an expanded set of statuses. | Renamed. See the complete mapping in \[Update status handling\](#bookmark\_update\_status\_handling). | | \`payment.id\` (integer) | \`transactions.payments\[\].reference\_id\` (string) | Identifier of the processed payment, available when the flow completes successfully. In the Payment Intent API, it was returned as an integer in \`payment.id\`. In the Orders API, it is returned as a string in \`transactions.payments\[\].reference\_id\`. | Processed payment identifier. Changes from integer to string. | The Orders API also introduces the following fields with no equivalent in the Payment Intent API. | Field | Description | |---|---| | \`status\_detail\` | Order status detail. Possible values: \`accredited\`, \`canceled\_by\_api\`, \`bad\_filled\_card\_data\`, \`insufficient\_amount\`, among others. See the \[API Reference\](https://www.mercadopago.com.ar/developers/en/reference/in-person-payments/point/orders/get-order/get) for the complete list. | | \`transactions.payments\[\].paid\_amount\` | Amount effectively paid in the transaction. | | \`transactions.payments\[\].refunded\_amount\` | Amount refunded in the transaction. | | \`transactions.payments\[\].status\` | Payment transaction status. | | \`transactions.payments\[\].status\_detail\` | Transaction status detail. Same possible values as \`status\_detail\` of the order. | | \`transactions.payments\[\].payment\_method.type\` | Payment method used in the transaction (e.g.: \`credit\_card\`, \`debit\_card\`). | | \`transactions.payments\[\].payment\_method.installments\` | Number of installments selected in the transaction. | | \`transactions.payments\[\].payment\_method.id\` | Payment method or card brand identifier. See :TagComponent{tag="API" text="GET /v1/payment\_methods" href="/developers/en/reference/online-payments/checkout-api/payment-methods/get"}. | | \`transactions.payments\[\].card.first\_digits\` / \`last\_digits\` | First and last digits of the card used in the transaction, available when payment was made by card. | | \`transactions.refunds\[\]\` | \*Array\* with the refund data for the order (\`id\`, \`transaction\_id\`, \`reference\_id\`, \`amount\`, \`status\`). | ::: :::AccordionComponent{title="Update error handling in query" pill="2"} In the query, errors are grouped by type of change. See the tables below for more details. ### Errors that disappear The following errors exist in the Payment Intent API but have no equivalent in the Orders API. | HTTP | Payment Intent API | Note | |---|---|---| | \`401\` | \`unauthorized\` (Unauthorized use of live credentials) | The \`x-test-scope\` header was removed in the Orders API. | | \`403\` | \`forbidden\` | Terminal ownership validation occurs only during creation. | | \`429\` | \`too\_many\_requests\` | Present in the Payment Intent API. Not documented in the Orders API. | ### Renamed errors The following error was renamed in the Orders API. | HTTP | Payment Intent API | Orders API | Note | |---|---|---|---| | \`404\` | \`not\_found\` | \`order\_not\_found\` | Order not found. Verify that the submitted ID is correct. | ### Errors that change behavior The following error exists in both APIs but with a different meaning in the Orders API. | HTTP | Payment Intent API | Orders API | Note | |---|---|---|---| | \`400\` | \`bad\_request\` | \`bad\_request\` | Invalid \`order\_id\` format. The ID changes from UUID to alphanumeric. | ### Errors that remain unchanged The following errors have the same behavior in both APIs. | HTTP | Error | Note | |---|---|---| | \`401\` | \`unauthorized\` | Invalid or expired token. | | \`500\` | \`internal\_error\` | Internal error. Retry the request. | ::: ## Update status handling One of the most significant changes between the Payment Intent API and the Orders API is the \`state\` field, which is renamed to \`status\` in the new API and receives new values. In the Payment Intent API, the \`FINISHED\` status required additional calls to determine the actual payment result. In the Orders API, the \`processed\` and \`failed\` statuses are self-contained and eliminate that need. Update all status checks in your integration according to the table below. :::AccordionComponent{title="Map status values" pill="1"} | Payment Intent API (\`state\`) | Orders API (\`status\`) | Note | |---|---|---| | \`OPEN\` | \`created\` | Renamed | | \`ON\_TERMINAL\` | \`at\_terminal\` | Renamed | | \`PROCESSING\` | Absorbed | No intermediate status in the Orders API | | \`PROCESSED\` | Absorbed | No intermediate status in the Orders API | | \`FINISHED\` (approved payment) | \`processed\` | The approved payment result is contained in the order itself, without requiring additional queries. | | \`FINISHED\` (rejected payment) | \`failed\` | The rejected payment result is contained in the order itself, without requiring additional queries. | | \`CONFIRMATION\_REQUIRED\` | \`action\_required\` | Renamed | | \`ERROR\` | \`failed\` | Renamed | | \`ABANDONED\` | \`expired\` | Renamed (timeout-based) | | \`CANCELED\` | \`canceled\` | Same meaning. Now lowercase | | Does not exist | \`refunded\` | \*\*New status.\*\* Must be handled explicitly in all flows | In the Payment Intent API, confirming the result of a payment with \`state: FINISHED\` required inspecting \`payment.state\` in the webhook, calling \`GET /v1/payments/{id}\`, or searching by \`external\_reference\`. In the Orders API, the \`processed\` and \`failed\` statuses are self-contained: the payment result is available directly in the order, without additional queries. ::: ## Update the webhook notification topic In the Payment Intent API, notifications were sent through the \`point\_integration\_wh\` topic. In the Orders API, they move to the \*\*Order (Mercado Pago)\*\* (\`orders\`) topic. Before going to production, update your application settings in \[Your integrations\](https://www.mercadopago.com.ar/developers/panel/app). To do so, select the \*\*"Order (Mercado Pago)"\*\* topic and deactivate the \`point\_integration\_wh\` topic. For more information, see the \[Configure notifications\](https://www.mercadopago.com.ar/developers/en/docs/mp-point/notifications) documentation. ## Update order cancellation The new endpoint to cancel an order is \`POST /v1/orders/{orderid}/cancel\`, replacing the \`DELETE\` from the Payment Intent API. The \`{deviceid}\` is removed from the path and the cancellation is now identified solely by the \`{orderid}\`. In the Payment Intent API, it was only possible to cancel payment intents that had not yet reached the terminal. In the Orders API, it is possible to cancel an order even after it has reached the terminal, using a new specific header. \`\`\`curl curl -X POST \\ 'https://api.mercadopago.com/v1/orders/{{ORDER\_ID}}/cancel' \\ -H 'Content-Type: application/json' \\ -H 'X-Idempotency-Key: {{IDEMPOTENCY\_KEY}}' \\ -H 'Authorization: Bearer {{ACCESS\_TOKEN}}' \`\`\` :::AccordionComponent{title="Adapt cancellation headers" pill="1"} The response now returns the complete order object with \`status: "canceled"\`, instead of just the \`id\`. The headers required for this operation are: | Header | Required | Description | |---|---|---| | \`X-Idempotency-Key\` | Required | Unique key per request | | \`x-allow-cancelable-status\` | Conditional | Required to cancel orders in \`at\_terminal\`. Value: \`"at\_terminal"\` | To cancel orders with \`at\_terminal\` status, send the \`x-allow-cancelable-status: at\_terminal\` header. Without this header, only orders with \`status: created\` will be canceled. ::: :::AccordionComponent{title="Update error handling in cancellation" pill="2"} In cancellation, errors are grouped by type of change. See the tables below for more details. ### Errors that disappear The following errors exist in the Payment Intent API but have no equivalent in the Orders API. | HTTP | Payment Intent API | Note | |---|---|---| | \`400\` | \`bad\_request\` (deviceID format) | \`deviceid\` was removed from the path in the Orders API. | | \`429\` | \`too\_many\_requests\` | Present in the Payment Intent API. Not documented in the Orders API. | ### Renamed errors The following error was renamed in the Orders API. | HTTP | Payment Intent API | Orders API | Note | |---|---|---|---| | \`409\` | \`conflict\_error\` | \`cannot\_cancel\_order\` | Order status does not allow cancellation. For \`at\_terminal\`, send \`x-allow-cancelable-status: at\_terminal\`. | ### Errors that change behavior The following errors exist in both APIs but with different behavior in the Orders API. | HTTP | Payment Intent API | Orders API | Note | |---|---|---|---| | \`400\` | \`bad\_request\` | \`bad\_request\` | Invalid \`order\_id\` format. The ID changes from UUID to alphanumeric. | | \`404\` | \`101\` | \`order\_not\_found\` | Order not found. In the Payment Intent API, the \`error\` field uses the numeric code \`"101"\`. | | \`409\` | \`101\` | \`order\_already\_canceled\` | In the Payment Intent API, non-existent orders and already-canceled orders returned the same \`"101"\` error. In the Orders API, they are differentiated into two distinct errors: \`404\` for order not found and \`409\` for order already canceled. | | \`500\` | \`internal\_error\` | \`idempotency\_validation\_failed\` | Idempotency validation failure. Retry the request. | ### Errors that remain unchanged The following error has the same behavior in both APIs. | HTTP | Error | Note | |---|---|---| | \`401\` | \`unauthorized\` | Invalid or expired token. | ### Errors introduced by the Orders API The following errors have no equivalent in the Payment Intent API. | HTTP | Orders API error | Note | |---|---|---| | \`400\` | \`empty\_required\_header\` | \`X-Idempotency-Key\` missing. | | \`409\` | \`idempotency\_key\_already\_used\` | Idempotency key reused. | ::: ## Implement refunds with the dedicated endpoint The Orders API introduces the dedicated endpoint \`POST /v1/orders/{orderid}/refund\` for refunds, which did not exist in the Payment Intent API. Previously, it was necessary to receive the payment webhook, obtain the \`payment\_id\`, and execute the refund through the Payments API separately. Now, the refund is performed directly on the order. :::::AccordionComponent{title="Replace the Payment Intent API refund flow" pill="1"} Choose between a full or partial refund based on the amount to return. ::::TabsComponent :::TabComponent{title="Full refund"} To refund the full order amount, send the request to the :TagComponent{tag="API" text="POST /v1/orders/{orderid}/refund" href="/developers/en/reference/in-person-payments/point/orders/refund-order/post"} endpoint without a 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}}' \`\`\` ::: :::TabComponent{title="Partial refund"} To refund a partial amount, send the request to the :TagComponent{tag="API" text="POST /v1/orders/{orderid}/refund" href="/developers/en/reference/in-person-payments/point/orders/refund-order/post"} endpoint with the \`transactions\[\]\` array indicating the transaction identifier and the amount to refund. The \`transactions\[\].id\` field corresponds to the \`transactions.payments\[\].id\` returned in the order creation or query response. \`\`\`curl curl -X POST \\ 'https://api.mercadopago.com/v1/orders/{{ORDER\_ID}}/refund' \\ -H 'Authorization: Bearer {{ACCESS\_TOKEN}}' \\ -H 'X-Idempotency-Key: {{IDEMPOTENCY\_KEY}}' \\ -d '{ "transactions": \[ { "id": "{{TRANSACTION\_ID}}", "amount": "10.00" } \] }' \`\`\` ::: :::: Refunds are accepted up to 90 days from the payment date. > SUCCESS\_MESSAGE > > See all possible error codes for this operation in \[Refund errors\](https://www.mercadopago.com.ar/developers/en/docs/mp-point/resources/refund-errors). ::::: :::AccordionComponent{title="Adapt the refund response fields" pill="2"} The refund response varies depending on the type of operation performed. | Field | Type | Description | |---|---|---| | \`id\` | string | Identifier of the refunded order | | \`status\` | string | \`refunded\` for full refund. \`processed\` for partial refund (balance still available) | | \`status\_detail\` | string | \`refunded\` for full refund. \`partially\_refunded\` for partial refund | | \`transactions.refunds\[\].id\` | string | Refund identifier, generated by Mercado Pago | | \`transactions.refunds\[\].transaction\_id\` | string | Identifier of the payment transaction being refunded | | \`transactions.refunds\[\].reference\_id\` | string | Identifier linking the payment and its refund | | \`transactions.refunds\[\].amount\` | string | Refund amount | | \`transactions.refunds\[\].status\` | string | \`processing\` when a full refund was requested and is being processed. \`processed\` when a partial refund was successfully completed | ::: ## Validate the migration After applying the changes, verify that the integration works correctly across all flows before going to production. :::CheckboxComponent{label="x-test-scope header removed" defaultChecked="false"} The \`x-test-scope\` \*header\* was removed from all integration requests. ::: :::CheckboxComponent{label="X-Idempotency-Key header configured" defaultChecked="false"} The \`X-Idempotency-Key\` \*header\* must be present in all creation, cancellation, and refund operations. ::: :::CheckboxComponent{label="Terminals configured" defaultChecked="false"} Terminals listed with the :TagComponent{tag="API" text="GET /terminals/v1/list" href="/developers/en/reference/in-person-payments/point/terminals/get-terminals/get"} endpoint and operating mode updated with :TagComponent{tag="API" text="PATCH /terminals/v1/setup" href="/developers/en/reference/in-person-payments/point/terminals/update-operation-mode/patch"}. ::: :::CheckboxComponent{label="Order creation validated" defaultChecked="false"} Orders successfully created with the new \*payload\* at the :TagComponent{tag="API" text="POST /v1/orders" href="/developers/en/reference/in-person-payments/point/orders/create-order/post"} endpoint and received by the terminal. ::: :::CheckboxComponent{label="Order query validated" defaultChecked="false"} Orders successfully retrieved via the :TagComponent{tag="API" text="GET /v1/orders/{orderid}" href="/developers/en/reference/in-person-payments/point/orders/get-order/get"} endpoint. ::: :::CheckboxComponent{label="Webhook topic updated" defaultChecked="false"} \*\*"Order (Mercado Pago)"\*\* (\`orders\`) topic configured in \[Your integrations\](https://www.mercadopago.com.ar/developers/panel/app) replacing \`point\_integration\_wh\`, and order statuses monitored with the new values: \`created\`, \`at\_terminal\`, \`processed\`, \`failed\`, \`canceled\`, and \`refunded\`. ::: :::CheckboxComponent{label="Order cancellation validated" defaultChecked="false"} Orders successfully canceled via the :TagComponent{tag="API" text="POST /v1/orders/{orderid}/cancel" href="/developers/en/reference/in-person-payments/point/orders/cancel-order/post"} endpoint. ::: :::CheckboxComponent{label="Refunds validated" defaultChecked="false"} Refunds processed via the dedicated :TagComponent{tag="API" text="POST /v1/orders/{orderid}/refund" href="/developers/en/reference/in-person-payments/point/orders/refund-order/post"} endpoint. ::: See the documentation to learn how to \[test the integration\](https://www.mercadopago.com.ar/developers/en/docs/mp-point/integration-test).