Make a test payment
Learn how to simulate payments using dLocal’s sandbox environment before going live.
The dLocal Sandbox is a test environment that mirrors the production system. It allows you to safely simulate payments, check API behavior, and trigger webhooks without processing real transactions.
In Test mode, you can monitor test transactions through the Merchant Dashboard. You can manage both sandbox and production from the same account.
Step 1: Requirements to start testing
- A dLocal account. Sign up or log in if you already have one.
- Sandbox API credential. Get them from the Settings section in the Dashboard.
Step 2: How does it work?
Sandbox URL
Sandbox tools URL
For certain payments, such as cash or refunds, it is necessary to force the status. That's why you need to use this specific one:
Steps to test a payment
- Set up authentication headers.
- Build the API request you want to simulate using test data.
- Send the request to the sandbox endpoint and simulate different responses.
- Check the response and your webhook listener.
Simulate payment status
In Sandbox, you can control the payment result by passing a status code in the request body's description
field.
"description": "302"
Sample description values to simulate card responses
description | Simulated status | Meaning |
---|---|---|
"200" | PAID | Payment approved |
"300" | REJECTED | Generic rejection |
"302" | REJECTED | Insufficient funds |
Sample description values to simulate cash payments
status | Meaning |
---|---|
"PAID" | Payment approved |
"REJECTED" | Generic rejection |
"ERROR" | Generic error |
All possible status codes are listed in the API Reference. For specific operations like payments or refunds, you’ll find detailed status codes in their respective sections:
Step 3: Test payments
Below are common test cases using the sandbox. This is useful to test status-code-based UI messaging or error categorization.
General payment example
Refer to the example below and modify the relevant data to build and test payment requests in the sandbox environment. Modifies the description
field in the payment request to trigger specific outcomes.
curl -X POST \
-H 'X-Date: {x-date}' \
-H 'X-Login: {x-login}' \
-H 'X-Trans-Key: {x-trans-key}' \
-H 'Content-Type: application/json' \
-H 'X-Version: 2.1' \
-H 'User-Agent: MerchantTest / 1.0 ' \
-H 'Authorization: V2-HMAC-SHA256, Signature: {Signature}' \
-d '{body}'
https://sandbox.dlocal.com/payments
{
"amount": 100,
"currency": "USD",
"country": "BR",
"payment_method_id": "CARD",
"payment_method_flow": "DIRECT",
"payer":{
"name": "Thiago Gabriel",
"email": "[email protected]",
"document": "53033315550",
"user_reference": "12345",
"address": {
"state": "Rio de Janeiro",
"city": "Volta Redonda",
"zip_code": "27275-595",
"street": "Servidao B-1",
"number": "1106"
}
},
"order_id": "657434343",
"description": "200",
"notification_url": "http://merchantsite.com/notifications"
}
Test scenarios
Payment with credit card: approved
To test an approved payment with status PAID
, set the description
field to 200
.
Use the Create a payment API endpoint if you want to customize the example.
Example request
curl -X POST \
-H 'X-Date: {x-date}' \
-H 'X-Login: {x-login}' \
-H 'X-Trans-Key: {x-trans-key}' \
-H 'Content-Type: application/json' \
-H 'X-Version: 2.1' \
-H 'User-Agent: MerchantTest / 1.0 ' \
-H 'Authorization: V2-HMAC-SHA256, Signature: {Signature}' \
-d '{body}'
https://sandbox.dlocal.com/payments
{
"amount": 100,
"currency": "USD",
"country": "BR",
"payment_method_id": "CARD", // Must be "CARD" for card payments
"payment_method_flow": "DIRECT",
"payer":{
"name": "Thiago Gabriel",
"email": "[email protected]",
"document": "53033315550",
"user_reference": "12345",
"address": {
"state": "Rio de Janeiro",
"city": "Volta Redonda",
"zip_code": "27275-595",
"street": "Servidao B-1",
"number": "1106"
}
},
"order_id": "657434343",
"description": "200", // Use "200" to simulate approved (PAID) payment
"notification_url": "http://merchantsite.com/notifications"
}
Expected response
The response you should expect for the specified properties in this test:
{
"status" : "PAID",
"status_code" : "200",
"status_detail" : "The payment was paid.",
}
Payment with credit card: rejected
To test a rejected payment with status REJECTED
, set the description
field to 300
.
Example request
curl -X POST \
-H 'X-Date: {x-date}' \
-H 'X-Login: {x-login}' \
-H 'X-Trans-Key: {x-trans-key}' \
-H 'Content-Type: application/json' \
-H 'X-Version: 2.1' \
-H 'User-Agent: MerchantTest / 1.0 ' \
-H 'Authorization: V2-HMAC-SHA256, Signature: {Signature}' \
-d '{body}'
https://sandbox.dlocal.com/payments
{
"amount": 100,
"currency": "USD",
"country": "BR",
"payment_method_id": "CARD", // Must be "CARD" for card payments.
"payment_method_flow": "DIRECT",
"payer":{
"name": "Thiago Gabriel",
"email": "[email protected]",
"document": "53033315550",
"user_reference": "12345",
"address": {
"state": "Rio de Janeiro",
"city": "Volta Redonda",
"zip_code": "27275-595",
"street": "Servidao B-1",
"number": "1106"
}
},
"order_id": "657434343",
"description": "300", // Use "300" to simulate rejected (REJECTED) payment.
"notification_url": "http://merchantsite.com/notifications"
}
Expected response
The response you should expect for the specified properties in this test:
{
"status" : "REJECTED",
"status_code" : "300",
"status_detail" : "The payment was rejected.",
}
Direct cash payment: approve or expire
For direct cash payments, you can manually set the final status using the /sandbox-tools/payments
endpoint. It can be tested by either forcing an approval (PAID
) or an expiration (REJECTED
).
Visit the Coverage page to explore different payment methods.
Payment example request
curl -X POST \
-H 'X-Date: {x-date}' \
-H 'X-Login: {x-login}' \
-H 'X-Trans-Key: {x-trans-key}' \
-H 'Content-Type: application/json' \
-H 'X-Version: 2.1' \
-H 'User-Agent: MerchantTest / 1.0 ' \
-H 'Authorization: V2-HMAC-SHA256, Signature: {Signature}' \
-d '{body}'
https://sandbox.dlocal.com/payments
{
"amount": 100,
"currency": "USD",
"country": "BR",
"payment_method_id": "BL", // Must be the ID of a direct cash payment method.
"payment_method_flow": "DIRECT",
"payer":{
"name": "Thiago Gabriel",
"email": "[email protected]",
"document": "53033315550",
"user_reference": "12345",
"address": {
"state": "Rio de Janeiro",
"city": "Volta Redonda",
"zip_code": "27275-595",
"street": "Servidao B-1",
"number": "1106"
}
},
"order_id": "657434343",
"notification_url": "http://merchantsite.com/notifications"
}
Final status example request
curl -X POST \
-H 'X-Date: {x-date}' \
-H 'X-Login: {x-login}' \
-H 'X-Trans-Key: {x-trans-key}' \
-H 'Content-Type: application/json' \
-H 'X-Version: 2.1' \
-H 'User-Agent: MerchantTest / 1.0 ' \
-H 'Authorization: V2-HMAC-SHA256, Signature: {Signature}' \
-d '{body}'
https://sandbox.dlocal.com/sandbox-tools/payments
{
"payment_id" : "PAY4334346343", // Get the payment ID from the payment creation response.
"status": "PAID" // Use "PAID" to simulate an approved payment, or "REJECTED" to simulate a rejected payment.
}
Expected response
In both cases, if you receive a code 200
, it means your PAID
or REJECTED
request is successful. Also, this will trigger a notification with the new status.
If payment_id
doesn’t exist, you will receive a 404
response
{
"code": 0,
"status": "ERROR",
"message": "404 {\"code\":4000,\"message\":\"Payment not found\"}"
}
If payment_id
is not in PENDING
status, you will receive a 400
response.
{
"code": 5002,
"message": "Payment D-4-fdb6fe34-de6c-4f66-8895-ef87a1918b29 has not status PENDING. Actual status: PAID"
}
Refund for cash and bank transfer
To test refund flows, use the /sandbox-tools/refunds/update-status
endpoint to update the refund status.
For cash and bank transfer refunds, you will get a PENDING
status when calling the Make a refunds API.
To test other statuses, you can use the below PATCH method to force a refund to update to another status (SUCCESS
, REJECTED
, or CANCELLED
). Then, you will be able to receive a refund notification.
Example request
curl --location --request PATCH 'https://sandbox.dlocal.com/sandbox-tools/refunds/update-status' \
--header 'X-Login: {x-login}' \
--header 'X-Trans-Key: {x-trans-key}' \
--header 'Content-Type: application/json' \
--data-raw '
{
"id_refund": "R-462778-e60039e7-ed75-4cd5-ad47-fc7f05fa6347",
"status": "SUCCESS"
}'
Expected response
You will get an HTTP code 200
with the below response, which means the refund status is updated and will trigger a notification with the new status.
{
"code": 0,
"status": "ERROR",
"message": "404 {\"code\":4000,\"message\":\"Payment not found\"}"
}
If the refund is not in pending status, you will get the below response with HTTP code 400
.
{
"code": 5002,
"message": "Payment D-4-fdb6fe34-de6c-4f66-8895-ef87a1918b29 has not status PENDING. Actual status: PAID"
}
Updated 11 days ago
Once your integration is tested, move on to configuring the initial settings needed for production.