Wallet payments

Wallet payments (WALLET) let customers pay by authenticating with their wallet provider (the wallet app or service that confirms the customer's payment). Once a customer completes the first payment using a tokenized wallet, dLocal returns a wallet.token that you can use for all future payments — no redirect or re-authentication required.

Use this page for the global Payins wallet flow. Payment-method and country-specific sections can add requirements or exceptions, so always confirm the behavior for the wallet you are integrating before you go live.

Prerequisites

Complete these steps before you create a wallet payment:

  1. Use the Create payment endpoint for the wallet payment or enrollment.
  2. Identify the wallet payment_method_id for the customer’s country in the Payment method section.
  3. Set payment_method_flow based on the payment flow:
    • Use REDIRECT for one-time payments and token enrollment.
    • Use DIRECT only after you receive and store a valid wallet.token.
  4. Include notification_url to receive the final asynchronous payment or enrollment status.
  5. Include callback_url for REDIRECT flows so the wallet provider can return the customer to your site.
  6. Include device.type for all REDIRECT requests.

For tokenized wallets, also send wallet.save = true during enrollment and store only tokens returned with VERIFIED (700) or PAID (200) status.

Related references

Use these pages when you build and validate your integration:

  • Create payment: create one-time wallet payments, token enrollments, and recurring DIRECT charges.
  • The wallet object: review the supported wallet fields, including save, verify, capture, and token.
  • Payment method section: confirm wallet availability, country support, and payment-method-specific requirements.
  • Receive notifications: implement webhook handling for asynchronous PENDING, PAID, REJECTED, and VERIFIED updates.
  • Cancel a wallet.token: cancel a stored token when a customer cancels or changes their payment method.

Available wallets

To integrate wallet payments, identify each wallet you want to support and set its payment_method_id in the payment request.

📘

Payment method list

Get the payment method list or view all available wallets by country in the Payment method section.

Payment flow

Choose one of these flows based on whether you need a one-time payment or future DIRECT charges. Create the initial payment with the Create payment endpoint.

FlowDescriptionBest for
One-time payments (REDIRECT)Redirect the customer to the wallet's website to authenticate and complete the payment. After authentication, the wallet provider redirects the customer back to your site. dLocal does not issue a wallet.token.One-time purchases
Tokenized (recurring) payments (REDIRECT, then DIRECT)Redirect the customer to the wallet's website to authenticate and authorize future payments. If you send wallet.save = true in the request, the asynchronous notification includes a wallet.token. Use that wallet.token for subsequent DIRECT payments without redirecting the customer again.Subscriptions, recurring billing

One-time (one-shot) payments

In this flow, redirect the customer to the wallet's app/website to authenticate and complete the payment.

Sale

{
    "amount": 26,
    "currency": "BRL",
    "country": "BR",
    "payment_method_id": "MP",
    "payment_method_flow": "REDIRECT",
    "payer": {
      "name": "Example Payer",
      "email": "[email protected]",
      "document": "<DOCUMENT_NUMBER>"
    },
    "device": {
      "type": "WEB"
    },
    "order_id": "5346523564",
    "notification_url": "http://merchantsite.com/notifications",
    "callback_url": "http://merchantsite.com/callback"
  }
{
  "id": "R-4-41f8628f-b6ec-4c02-96d5-c5b03cac7cb0",
  "amount": 26,
  "currency": "BRL",
  "payment_method_id": "MP",
  "payment_method_type": "WALLET",
  "payment_method_flow": "REDIRECT",
  "country": "BR",
  "created_date": "2018-12-26T20:37:20.000+0000",
  "status": "PENDING",
  "status_detail": "The payment is pending.",
  "status_code": "100",
  "order_id": "5346523564",
  "notification_url": "http://merchantsite.com/notifications",
  "redirect_url": "https://pay.dlocal.com/gmf-apm/payments-redirect/M-0aa0cc00-..."
}
{
  "id": "R-4-41f8628f-b6ec-4c02-96d5-c5b03cac7cb0",
  "amount": 26,
  "currency": "BRL",
  "payment_method_id": "MP",
  "payment_method_type": "WALLET",
  "payment_method_flow": "REDIRECT",
  "country": "BR",
  "created_date": "2018-12-26T20:37:20.000+0000",
  "status": "PAID",
  "status_detail": "The payment was paid.",
  "status_code": "200",
  "order_id": "5346523564",
  "notification_url": "http://merchantsite.com/notifications"
}

After you receive the synchronous response, redirect the customer to redirect_url. dLocal sends the final PAID or REJECTED status by webhook to your notification_url.

Tokenized wallets

The enrollment and recurring charge are two separate API calls.

Step 1 — Enrollment (REDIRECT)

In this flow, redirect the customer to the wallet's website to authenticate and authorize future payments. If you send wallet.save = true in the request, the asynchronous notification includes a wallet.token. Use that wallet.token for future payments without authenticating the customer again. See The wallet object for the supported wallet fields.

Option A — Sale + verify flow

Enroll and charge simultaneously (wallet.verify: false, amount > 0). Use this option to charge the customer and issue a wallet.token in the same flow.

{
  "amount": 26,
  "currency": "BRL",
  "country": "BR",
  "payment_method_id": "PZ",
  "payment_method_flow": "REDIRECT",
  "payer": {
    "name": "Example Payer",
    "email": "[email protected]",
    "document": "<DOCUMENT_NUMBER>"
  },
  "wallet": {
    "save": true,
    "verify": false,
    "capture": true
  },
  "device": {
    "type": "WEB"
  },
  "order_id": "5346523564",
  "notification_url": "http://merchantsite.com/notifications",
  "callback_url": "http://merchantsite.com/callback"
}
{
  "id": "R-4-41f8628f-b6ec-4c02-96d5-c5b03cac7cb0",
  "amount": 26,
  "currency": "BRL",
  "payment_method_id": "PZ",
  "payment_method_type": "WALLET",
  "payment_method_flow": "REDIRECT",
  "country": "BR",
  "created_date": "2018-12-26T20:37:20.000+0000",
  "status": "PENDING",
  "status_detail": "The payment is pending.",
  "status_code": "100",
  "order_id": "5346523564",
  "notification_url": "http://merchantsite.com/notifications",
  "redirect_url": "https://pay.dlocal.com/gmf-apm/payments-redirect/M-0aa0cc00-..."
}
{
  "id": "R-4-41f8628f-b6ec-4c02-96d5-c5b03cac7cb0",
  "amount": 26,
  "currency": "BRL",
  "payment_method_id": "PZ",
  "payment_method_type": "WALLET",
  "payment_method_flow": "REDIRECT",
  "country": "BR",
  "created_date": "2018-12-26T20:37:20.000+0000",
  "status": "PAID",
  "status_detail": "The payment was paid.",
  "status_code": "200",
  "order_id": "5346523564",
 "wallet": {
    "token": "<WALLET_TOKEN>"
 },
  "notification_url": "http://merchantsite.com/notifications"
}
⚠️

Payment failed, enrollment succeeded

The notification includes a wallet.token as long as the user authenticated successfully, regardless of whether dLocal approved the payment.

Option B — Verify flow

Enroll without charging (wallet.verify: true, amount: 0). dLocal verifies the wallet and issues a wallet.token without making a charge. Use this for free trials or deferred billing.

{
  "amount": 0,
  "currency": "BRL",
  "country": "BR",
  "payment_method_id": "MP",
  "payment_method_flow": "REDIRECT",
  "payer": {
    "name": "Example Payer",
    "email": "[email protected]",
    "document": "<DOCUMENT_NUMBER>"
  },
  "wallet": {
    "save": true,
    "verify": true,
    "capture": false
  },
  "device": {
    "type": "WEB"
  },
  "order_id": "5346523564",
  "notification_url": "http://merchantsite.com/notifications",
  "callback_url": "http://merchantsite.com/callback"
}
{
  "id": "D-4-75c7473a-ab86-4e43-bd39-c840268747d3",
  "amount": 0,
  "currency": "BRL",
  "payment_method_id": "MP",
  "payment_method_type": "WALLET",
  "payment_method_flow": "REDIRECT",
  "country": "BR",
  "created_date": "2018-12-26T20:37:20.000+0000",
  "status": "PENDING",
  "status_detail": "The payment is pending",
  "status_code": "100",
  "order_id": "5346523564",
  "notification_url": "http://merchantsite.com/notifications",
  "redirect_url": "https://pay.dlocal.com/gmf-apm/payments-redirect/M-0aa0cc00-..."
}
{
  "id": "D-4-75c7473a-ab86-4e43-bd39-c840268747d3",
  "amount": 0,
  "status": "VERIFIED",
  "status_detail": "The wallet was verified.",
  "status_code": "700",
  "currency": "BRL",
  "country": "BR",
  "payment_method_id": "MP",
  "payment_method_type": "WALLET",
  "payment_method_flow": "REDIRECT",
  "payer": {
    "name": "Example Payer",
    "email": "[email protected]",
    "document": "<DOCUMENT_NUMBER>"
  },
  "wallet": {
    "token": "<WALLET_TOKEN>"
  },
  "order_id": "5346523564",
  "notification_url": "http://merchantsite.com/notifications",
  "created_date": "2018-12-26T20:37:20.000+0000"
}

Expect the asynchronous response at notification_url after the user approves the enrollment in the wallet provider.

Persist wallet.token for all future charges. Only store tokens from VERIFIED (700) or PAID (200) status. Tokens from rejected flows are invalid.

Step 2 — Recurring charge (DIRECT)

Pay with a wallet.token; the request does not redirect the user.

⚠️

Recurring wallet payments

For recurring wallet payments in the Philippines and Indonesia, include the customer's mobile number in the payer.phone field of the payment request.

Example

{
    "amount": 10,
    "currency": "BRL",
    "country": "BR",
    "payment_method_id": "MP",
    "payment_method_flow": "DIRECT",
    "payer": {
        "name": "Example Payer",
        "email": "[email protected]",
        "phone": "<PHONE_NUMBER>",
        "document": "<DOCUMENT_NUMBER>",
        "address": {
            "country": "BR",
            "state": "Example State",
            "city": "Example City",
            "zip_code": "<ZIP_CODE>",
            "street": "Example Street",
            "number": "123"
        }
    },
    "wallet": {
        "token": "<WALLET_TOKEN>"
    },
    "order_id": "fe32a6ef-3954-4b5f-8712-d1c1079beba3",
    "description": "test-wallet",
    "notification_url": "https://notifications.merchant.com"
}
{
  "id": "F-4-b302affe-e590-4b29-98cc-57ec2dd10592",
  "amount": 10,
  "currency": "BRL",
  "payment_method_id": "MP",
  "payment_method_type": "WALLET",
  "payment_method_flow": "DIRECT",
  "country": "BR",
  "created_date": "2022-09-29T06:52:48.000+0000",
  "expiration_date": "2022-10-04T06:52:48.000+0000",
  "status": "PAID",
  "status_detail": "The payment was paid.",
  "status_code": "200",
  "order_id": "fe32a6ef-3954-4b5f-8712-d1c1079beba3",
  "description": "test-wallet",
  "notification_url": "https://notifications.merchant.com"
}
⚠️

Synchronous response

For most wallets, the synchronous response to a DIRECT charge is the final status (PAID or REJECTED) — no need to wait for a notification/webhook. Yape (YE) is the exception: it returns PENDING synchronously, and dLocal delivers the final status by notification/webhook within seconds.

Always confirm per-payment-method behavior in the relevant section.

📘

Device ID for Mercado Pago

Add the Device ID by following The DeviceId Object (for Mercado Pago only).

Include it in the wallet object. It improves fraud detection on Mercado Pago's side and can improve authorization rates.

Device type

Include device.type in all REDIRECT payment requests. This applies even when a payment method does not currently differentiate between web and mobile flows. Wallet providers can use different experiences, such as deep links, app-to-app redirects, or push notifications. dLocal uses this field to route the best experience for each context without requiring integration changes.

Use device.type only for REDIRECT flows where the user is present. These flows send the user a redirect or notification.

Omit device.type from DIRECT charges that use a wallet.token. Those are customer-not-present requests.

ValueDescription
WEBThe user is on a desktop or mobile browser.
MOBILE_APPThe user is inside your native iOS or Android app.
{
  "amount": 26,
  "currency": "BRL",
  "country": "BR",
  "payment_method_id": "MP",
  "payment_method_flow": "REDIRECT",
  "payer": {
    "name": "Example Payer",
    "email": "[email protected]",
    "document": "<DOCUMENT_NUMBER>"
  },
  "device": {
    "type": "MOBILE_APP"
  },
  "order_id": "5346523564",
  "notification_url": "http://merchantsite.com/notifications",
  "callback_url": "http://merchantsite.com/callback"
}

For payment methods where device.type is already mandatory, such as Yape, see the payment-method-specific sections for full behavior details.

Cancel a wallet.token

Cancel with the API

Call the cancel endpoint when a user unsubscribes, changes their payment method, or you need to cancel access programmatically.

To cancel an existing wallet.token, send a cancellation request through the API. This prevents future payments with that wallet.token.

See Cancel a wallet.token in the API reference section.

Example request

curl --request POST \
  --url "https://api.dlocal.com/payments/wallet/<WALLET_TOKEN>/cancel"
{
  "wallet": {
    "token": "<WALLET_TOKEN>"
  },
  "status": "CANCELLED",
  "status_detail": "The wallet token was cancelled."
}

Customer-initiated cancellation

Customers can cancel a subscription or recurring authorization directly from their wallet app (e.g., Nequi, GCash, Mercado Pago). When this happens, the next DIRECT charge attempt returns status_code 328 (invalid token). Handle 328 by stopping all future charge attempts and triggering a new enrollment flow.

Cancellation — whether merchant-initiated or customer-initiated — permanently invalidates the wallet.token. Always call the cancel endpoint on your side when a customer unsubscribes so your records stay in sync with the wallet provider.

How wallet providers notify dLocal of user-initiated cancellations:

Not all wallet providers behave the same way when a user cancels access from within their app:

Proactive notification: The wallet provider notifies dLocal in real time. dLocal sends a webhook to your Payins Notification URL configured in dLocal's merchant dashboard to confirm that the wallet.token has been canceled. Listen for this webhook and update your records before the next scheduled charge.

Silent cancellation: The wallet provider does not notify dLocal. Your integration discovers the cancellation when the next DIRECT charge attempt returns status_code 328. Stop retrying that token and start a new enrollment flow.

Sandbox Testing

Use the description field in your request body to control payment behavior in the sandbox environment.

Enrollment flows (REDIRECT)

To simulate a successful enrollment that transitions from PENDING to PAID or VERIFIED:

description ValueBehavior
OmittedReturns PENDING. Use the mock playground UI to manually approve or reject. Recommended for UX testing.
"100:approved"Returns PENDING, then auto-sends a PAID (or VERIFIED) webhook after ~60 seconds. Recommended for automated testing.
"100:rejected"Returns PENDING, then auto-sends a REJECTED webhook after ~60 seconds.

Recurring charges (DIRECT)

To simulate a successful enrollment that transitions from PENDING to PAID or VERIFIED:

description ValueBehavior
"200"Returns PAID immediately.
"300"Returns REJECTED immediately.
⚠️

Mock server vs. Real provider environment

By default, all sandbox payments are routed through dLocal's mock server, which provides stable, predictable behavior across all wallet payment methods. If you need to test against the actual sandbox environment of a specific wallet provider (e.g., to validate provider-side behavior or UX), check with your assigned dLocal TAM — some providers require additional configuration or have limited sandbox availability.