Enrollment Links
With Enrollment Links, sellers generate a secure link and share it with the buyer so the buyer can link their card to an automatic payments profile — without the seller handling sensitive card data at any point. Card capture and tokenization are managed entirely by Mercado Pago.
When the buyer opens the enrollment link, they go through the following flow managed entirely by Mercado Pago:
- Introduction: the buyer sees a welcome screen prompting them to register their card so the seller can make the charge.
- Card data entry: the buyer fills in the secure Mercado Pago form with their card number, expiry date, security code, cardholder name, and ID.
- Success: if the process completes successfully, the buyer sees a confirmation screen and the link transitions to
vinculated. - Card error: if the card data is invalid or the card is rejected, the buyer can correct the data and retry. The link remains in
createdstate. - Inactive link: if the link has expired, was already used, or was cancelled, the buyer sees an error message indicating the link is no longer valid.
customer_id and a profile_id already created. Refer to the Customers documentation and the Payment Profiles documentation to complete these prerequisite steps.Send a request to /v1/payment-method-enrollmentsPOST using your APP_ACCESS_TOKENProduction Access Token of the integrator's application. Available under Your integrations > Production credentials. to generate the link you will share with the buyer.
Body parameters
| Parameter | Type | Required | Description | Example |
profile_id | String | Yes | ID of the automatic payments profile associated with the buyer. Alphanumeric characters only. Only one active link can exist per profile. | 7036b192b541454fa9b9990660dfa1b5 |
expiration_time | String | No | Link validity period in ISO 8601 format. Minimum: P1D. Maximum: P90D. Default: P7D. | P7D |
curl -X POST \
'https://api.mercadopago.com/v1/payment-method-enrollments' \
-H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
-H 'X-Idempotency-Key: 0d5020ed-1af6-469c-ae06-c3bec19954bb' \
-H 'Content-Type: application/json' \
-d '{
"profile_id": "7036b192b541454fa9b9990660dfa1b5",
"expiration_time": "P7D"
}'
If the request is successful, you will receive a 201 Created response with the following body:
json{ "id": "bea0ffb8-6c94-40a3-bc31-c2e7a0d46ed7", "profile_id": "7036b192b541454fa9b9990660dfa1b5", "enrollment_link": "https://mpago.la/1alzDGT", "state": "created", "expiration_time": "P7D", "expired_date": "2026-06-05T17:11:41.000-03:00", "created_date": "2026-05-29T17:11:41.000-03:00", "last_update_date": "2026-05-29T17:11:41.000-03:00" }
Save the id value to check the link status later. The enrollment_link value is the URL you must share with the buyer.
Possible errors
| HTTP | Code | Cause |
| 400 | enrollment_link.profile_id_invalid_format | The profile_id contains non-alphanumeric characters or is empty. |
| 400 | enrollment_link.expiration_time_invalid_format | The expiration_time does not follow ISO 8601 format. Correct example: P7D. |
| 400 | enrollment_link.expiration_time_out_of_range | The duration is less than 1 day or more than 90 days. |
| 401 | enrollment_link.unauthorized | Access Token missing or invalid. |
| 404 | enrollment_link.profile_not_found | The profile_id does not exist in Automatic Payments. |
| 404 | enrollment_link.resource_not_found | The profile_id exists but does not belong to the authenticated seller. |
| 409 | enrollment_link.conflict | An active enrollment link already exists for this profile_id. Cancel the existing one before creating a new link. |
| 500 | enrollment_link.internal_error | Internal error. Retry the request. |
Share the enrollment_link URL with the buyer through any channel you prefer: WhatsApp, email, SMS, or another. The buyer opens the URL in their browser, fills in the Mercado Pago card form, and the card is linked to the profile. The seller does not participate in this step and never accesses the card data.
The link has an expiration date defined by expiration_time. If the buyer does not use it before expired_date, the state automatically transitions to expired.
Instead of polling the link status, you can receive real-time notifications. When the buyer successfully links their card, Automatic Payments sends a webhook with the profile status changing to READY.
To configure notifications:
- Go to Your integrations in the Developer Dashboard and select your application.
- Go to Webhooks and register the HTTPS URL of your receiver endpoint. The endpoint must respond with
200within 22 seconds. - Enable the Payment Profile event (
payment_profile). - Copy the generated secret key to validate the
x-signatureheader of each incoming notification.
When the buyer successfully links their card, you will receive a webhook with the following payload:
json{ "id": "7036b192b541454fa9b9990660dfa1b5", "type": "payment_profile", "action": "payment_profile.updated", "version": 1, "live_mode": true, "data": { "status": "ready", "payment_methods": [{ "unique_id": "pm_001", "type": "credit_card", "status": "ready", "card_id": 9453094596 }] } }
The version field is an incremental counter per profile. If notifications arrive out of order, always process the one with the highest version and discard earlier ones.
GET /v1/customers/{customerId}/payment-profiles/{id} after receiving the notification.To learn more about notification format and signature validation, refer to the Webhooks documentation.
Send a request to /v1/payment-method-enrollments/{id}GET including the link id in the path to verify whether the buyer completed the linking process.
curl -X GET \
'https://api.mercadopago.com/v1/payment-method-enrollments/bea0ffb8-6c94-40a3-bc31-c2e7a0d46ed7' \
-H 'Authorization: Bearer YOUR_ACCESS_TOKEN'
If the buyer completed the linking process, you will receive a 200 OK response with the following body:
json{ "id": "bea0ffb8-6c94-40a3-bc31-c2e7a0d46ed7", "profile_id": "7036b192b541454fa9b9990660dfa1b5", "enrollment_link": "https://mpago.la/1alzDGT", "state": "vinculated", "expiration_time": "P7D", "expired_date": "2026-06-05T17:11:41.000-03:00", "created_date": "2026-05-29T17:11:41.000-03:00", "last_update_date": "2026-05-29T18:02:14.000-03:00" }
When state is vinculated, the card is linked to the profile and ready to use for automatic charges.
Possible link states
| State | Description |
created | Link generated and active. The buyer has not completed the form yet. |
vinculated | The buyer completed the process. The card is linked to the profile. |
cancelled | The seller cancelled the link before the buyer used it. |
expired | The link expired before the buyer completed the process. |
error | An error occurred during the linking process. |
The states vinculated, cancelled, expired, and error are terminal: once reached, the link cannot transition to any other state.
GET scenarios
| Scenario | Link state | Expected result |
| Newly created link | created | 200 — state: created |
| Buyer completed the form | vinculated | 200 — state: vinculated |
| Link cancelled by seller | cancelled | 200 — state: cancelled |
| Expired link | expired | 200 — state: expired |
Possible errors
| HTTP | Code | Cause |
| 400 | enrollment_link.bad_request | The id is not a valid UUID format. |
| 401 | enrollment_link.unauthorized | Access Token missing or invalid. |
| 404 | enrollment_link.resource_not_found | The link does not exist or does not belong to the authenticated seller. |
| 500 | enrollment_link.internal_error | Internal error. |
Send a request to /v1/payment-method-enrollments/{id}DELETE including the link id in the path to deactivate it before the buyer uses it. Only links in created state can be cancelled.
curl -X DELETE \
'https://api.mercadopago.com/v1/payment-method-enrollments/bea0ffb8-6c94-40a3-bc31-c2e7a0d46ed7' \
-H 'Authorization: Bearer YOUR_ACCESS_TOKEN'
A 204 No Content response confirms the link was cancelled. Verify the result with a GET request: state will be cancelled.
Possible errors
| HTTP | Code | Cause |
| 401 | enrollment_link.unauthorized | Access Token missing or invalid. |
| 404 | enrollment_link.resource_not_found | The link does not exist or does not belong to the authenticated seller. |
| 409 | enrollment_link.invalid_state_transition | The link is in vinculated, expired, or error state and cannot be cancelled. |
| 500 | enrollment_link.internal_error | Internal error. |
Use the test credentialsTest credentials available in the Developer Dashboard under Your integrations > Test credentials. from your Mercado Pago account to validate the full flow without processing real transactions.
Prerequisites
- Retrieve your test
APP_ACCESS_TOKENfrom Your integrations > Test credentials. - Get test cards to simulate approval and rejection scenarios from the test cards documentation.
- Create a test customer with an email in the format
xxxx@testuser.com. - Create a Payment Profile from that test customer's
customer_id.
Scenarios — POST /v1/payment-method-enrollments
| Scenario | Request | Expected result |
| Create link with default validity (7 days) | {"profile_id": "{PROFILE_ID}"} | 201 — state: created, enrollment_link starts with https://mpago.la/ |
Create link with explicit expiration_time | {"profile_id": "{PROFILE_ID}", "expiration_time": "P7D"} | 201 — expired_date is 7 days from now |
Minimum valid expiration_time | "expiration_time": "P1D" | 201 |
Maximum valid expiration_time | "expiration_time": "P90D" | 201 |
profile_id with special characters | "profile_id": "abc!@#" | 400 — enrollment_link.profile_id_invalid_format |
Empty profile_id | "profile_id": "" | 400 — enrollment_link.profile_id_invalid_format |
| Invalid ISO 8601 format | "expiration_time": "7D" | 400 — enrollment_link.expiration_time_invalid_format |
| Duration less than 1 day | "expiration_time": "PT23H59M59S" | 400 — enrollment_link.expiration_time_out_of_range |
| Duration more than 90 days | "expiration_time": "P100D" | 400 — enrollment_link.expiration_time_out_of_range |
| Active link already exists for same profile | Second POST with same profile_id | 409 — enrollment_link.conflict |
Non-existent profile_id | profile_id not registered in AP | 404 — enrollment_link.profile_not_found |
profile_id belonging to another seller | profile_id of a different seller | 404 — enrollment_link.resource_not_found |
| Missing authentication | No Authorization header | 401 — enrollment_link.unauthorized |
Scenarios — GET /v1/payment-method-enrollments/{id}
| Scenario | Link state | Expected result |
| Newly created link | created | 200 — state: created |
| Buyer completed the form | vinculated | 200 — state: vinculated |
| Link cancelled by seller | cancelled | 200 — state: cancelled |
| Expired link | expired | 200 — state: expired |
| Error during linking process | error | 200 — state: error |
| Invalid ID format (not UUID) | — | 400 — enrollment_link.bad_request |
| Link not found or from another seller | — | 404 — enrollment_link.resource_not_found |
Scenarios — DELETE /v1/payment-method-enrollments/{id}
| Scenario | Link state | Expected result |
| Cancel active link | created | 204 — subsequent GET returns state: cancelled |
| Cancel already linked | vinculated | 409 — enrollment_link.invalid_state_transition |
| Cancel expired link | expired | 409 — enrollment_link.invalid_state_transition |
| Cancel link with error | error | 409 — enrollment_link.invalid_state_transition |
| Link not found | — | 404 — enrollment_link.resource_not_found |