# MD for: https://www.mercadopago.com.ar/developers/pt/docs/mp-point-v2/migrate-payment-intent-to-orders.md \# How to migrate from the Payment Intent API to the Orders API (SELF-SERVICE mode) 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 \*\*SELF\_SERVICE\*\* 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, terminal screen time control (\`screen\_time\`), configurable order expiration (\`expiration\_time\`), the ability to cancel after the order reaches the terminal, 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-v2/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\`, \`STANDALONE\`, and \`SELF\_SERVICE\`. In the Orders API, the \`UNDEFINED\` value is added for unrecognized configurations. The possible values are \`PDV\`, \`STANDALONE\`, \`SELF\_SERVICE\`, and \`UNDEFINED\`. | 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": "SELF\_SERVICE" }' \`\`\` ::: :::TabComponent{title="Orders API"} 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": "SELF\_SERVICE" } \] }' \`\`\` ::: :::: 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\`, \`STANDALONE\`, and \`SELF\_SERVICE\`. | 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": "buyer\_ticket", "screen\_time": "PT30S" } }, "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="Orders API"} 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": "buyer\_ticket", "screen\_time": "PT30S" } }, "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, SELF\_SERVICE mode only allows \`buyer\_ticket\` (prints customer ticket) or \`no\_ticket\` (no printing). The default value is \`buyer\_ticket\`. | Changes from boolean to enum string. | | \*(does not exist)\* | \`config.point.screen\_time\` | Time during which the terminal screens will remain enabled to process the order, in ISO 8601 format. This time resets every time the screen changes or the customer interacts with the terminal. If not sent, the default value is \`PT15S\` (15 seconds). If the order is not processed within the configured period, it will be automatically canceled and a new order must be created. The allowed range is \`PT5S\` to \`PT5M\`. \*\*Important:\*\* the card reading screen will be displayed for a maximum of 60 seconds, regardless of the configured value. \*\*Exclusive to SELF\_SERVICE mode.\*\* | New field with no equivalent in Legacy. | | \`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\` and \`debit\_card\`. In the Orders API, SELF\_SERVICE mode allows the values \`credit\_card\` and \`debit\_card\`. If not sent, the terminal accepts all available payment methods. | Changes node. | | \`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, SELF\_SERVICE mode returns it is returned as an enum string: \`buyer\_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. Applies to Argentina (MLA) only. | Moves to \`config.point\`. | | \`payment.type\` | \`config.payment\_method.default\_type\` | Payment method configured for the terminal. In the Orders API, SELF\_SERVICE mode allows the values \`credit\_card\` and \`debit\_card\`. | Changes node. | The Orders API also introduces the following fields with no equivalent in the Payment Intent API. | Field | Description | |---|---| | \`status\` | Current order status. When created it is \`created\`. | | \`status\_detail\` | Order status detail. When created it is \`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. When created it is \`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. | | \`config.point.screen\_time\` | Configured time for which the terminal screens remain enabled during order processing. Resets with each screen change or customer interaction. \*\*Exclusive to SELF\_SERVICE mode.\*\* | ::: :::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. In SELF\_SERVICE mode, the possible values are \`created\`, \`at\_terminal\`, \`canceled\`, \`processed\`, \`failed\`, \`refunded\`. | | \`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\`). | | \`config.point.print\_on\_terminal\` | Indicates the configured printing mode. SELF\_SERVICE mode allows the values \`buyer\_ticket\` (prints customer ticket) and \`no\_ticket\` (no printing). | | \`config.point.screen\_time\` | Configured time for which the terminal screens remain enabled during order processing. Resets with each screen change or customer interaction. \*\*Exclusive to SELF\_SERVICE mode.\*\* | ::: :::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. | | \`ERROR\` | \`failed\` | Renamed | | \`ABANDONED\` | \`expired\` | Renamed (timeout-based) | | \`CANCELED\` | \`canceled\` | Same meaning. Now lowercase | 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. > WARNING > > When migrating to the Orders API, do not use the Payments API to query the result of payments processed by Point. The \`processed\` and \`failed\` statuses are self-contained and include all payment information directly in the order. > NOTE > > The \`action\_required\` status (equivalent to \`CONFIRMATION\_REQUIRED\` in Legacy) is not available in SELF\_SERVICE mode. The Orders API also introduces the following status with no equivalent in the Payment Intent API. | Status (Orders API) | Note | |---|---| | \`refunded\` | \*\*New status.\*\* Must be handled explicitly in all flows. | ::: ## Update the webhook notification topic In the Payment Intent API, Point notifications were sent through the \`point\_integration\_wh\` topic. In the Orders API, they move to the \*\*Order (Mercado Pago)\*\* (\`orders\`) topic. Update your application settings in \[Your integrations\](https://www.mercadopago.com.ar/developers/panel/app), subscribing to the \*\*"Order (Mercado Pago)"\*\* topic and deactivating \`point\_integration\_wh\`, before going to production. For more information, see the \[notifications documentation\](https://www.mercadopago.com.ar/developers/en/docs/mp-point-v2/notifications). ## 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. | | \`403\` | \`forbidden\` | This error disappears in cancellation; terminal validation does not apply to this resource. | | \`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. | | \`500\` | Generic | Internal error. Verify the response and retry. | ### 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-v2/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="Terminal configured in SELF\_SERVICE mode" defaultChecked="false"} Terminal 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 SELF\_SERVICE operating mode configured 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-v2/integration-test).