---
updatedAt: 2026-07-27T09:12:27.000Z
agentTools:
  projectIndex: https://docs.dlocal.com/llms.txt
---

# 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](https://dashboard.dlocal.com/login). You can manage both sandbox and production from the same account.

# Step 1: Requirements to start testing

* **A dLocal account**. [Sign up](https://dashboard.dlocal.com/signup) or [log in](https://dashboard.dlocal.com/login) if you already have one.
* **Sandbox API credential**. Get them from the [Settings section](https://dashboard.dlocal.com/settings) in the Dashboard.

# Step 2: How does it work?

## Sandbox URL

[block:html]
{
  "html": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <title>URL Selector with Static Display</title>\n  <style>\n    .url-container-a, .url-container-b {\n      display: flex;\n      align-items: center;\n      border-radius: 16px;\n      background-color: #fff;\n      padding: 10px;\n      box-shadow: 0 0 0px 1px #F5F5F5;\n      box-sizing: border-box;\n      border-color: transparent;\n      margin-top: 20px;\n      margin-bottom: 20px;\n      gap: 10px;\n      width: 100%;\n    }\n    \n    [data-color-mode=\"dark\"] .url-container-a, [data-color-mode=\"dark\"] .url-container-b {\n      background-color: #F7F7F7;\n    }\n\n    .url-label {\n      padding: 5px 5px;\n      border: 1px solid #ccc;\n      border-radius: 8px;\n      font-size: 11px;\n      color: #333;\n      background-color: #f9f9f9;\n    }\n\n    .url-input {\n      flex-grow: 1;\n    }\n\n    .url-input input {\n      width: 100%;\n      border: none;\n      outline: none;\n      flex-grow: 1;\n      border-radius: 8px;\n      padding: 5px;\n      font-size: 12px;\n      color: #333;\n      user-select: all;\n    }\n\n    .url-input input:focus {\n      outline: 1px solid #F5F5F5;\n      border-radius: 16px;\n    }\n    \n    /* Mobile-specific styles */\n    @media screen and (max-width: 768px) {\n      .url-container-a, .url-container-b {\n        display: flex;\n        align-items: center;\n        flex-wrap: wrap; \n        width: 100%; \n        max-width: 100%; \n        box-sizing: border-box; \n      }\n      \n      .url-input input {\n        border: none;\n        outline: none;\n        border-radius: 8px;\n        padding: 5px;\n        font-size: 12px;\n        color: #333;\n        user-select: all;\n        width: 100%;\n        max-width: 100%;\n      }\n    }\n  </style>\n</head>\n<body>\n  <!-- First URL container -->\n  <div class=\"url-container-a\">\n    <span class=\"url-label\">Sandbox URL</span>\n    <div class=\"url-input\">\n      <input type=\"text\" readonly value=\"https://sandbox.dlocal.com/\">\n    </div>\n  </div>\n\n  </div>\n</body>\n</html>"
}
[/block]

### 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:

[block:html]
{
  "html": "\n<body>\n\n  <!-- Second URL container -->\n  <div class=\"url-container-b\">\n    <span class=\"url-label\">Sandbox tools URL</span>\n    <div class=\"url-input\">\n      <input type=\"text\" readonly value=\"https://sandbox.dlocal.com/sandbox-tools\">\n    </div>\n  </div>\n</body>\n"
}
[/block]

## Steps to test a payment

1. Set up [authentication headers](https://docs.dlocal.com/reference/payins-security#headers).
2. Build the API request you want to simulate using test data.
3. Send the request to the sandbox endpoint and simulate different responses.
4. 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.

```json Example
{
  "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](https://docs.dlocal.com/reference/postman-api-collection). For specific operations like payments or refunds, you’ll find detailed status codes in their respective sections:

* [Payment status codes →](https://docs.dlocal.com/reference/payment-status-codes)
* [Refund status codes →](https://docs.dlocal.com/reference/refund-status-codes)

# 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.

> 📘 Endpoint routing for card payments
>
> * For payments with raw credit card information (e.g., card number, expiration date, CVV), use `https://api.dlocal.com/secure_payments`.
> * For card payments utilizing a `card_id` or token, use `https://api.dlocal.com/payments`.

```json General payment example for testing
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/secure_payments

{
  "amount": 100,
  "currency": "USD",
  "country": "BR",
  "payment_method_id": "CARD",
  "payment_method_flow": "DIRECT",
  "payer": {
    "name": "Thiago Gabriel",
    "email": "thiago@example.com",
    "document": "53033315550",
    "user_reference": "12345",
    "address": {
      "state": "Rio de Janeiro",
      "city": "Volta Redonda",
      "zip_code": "27275-595",
      "street": "Servidao B-1",
      "number": "1106"
    }
  },
  "card": {
    "holder_name": "Thiago Gabriel",
    "number": "4111111111111111",
    "cvv": "123",
    "expiration_month": 10,
    "expiration_year": 2040
  },
  "order_id": "657434343",
  "description": "200",
  "notification_url": "http://merchantsite.com/notifications"
}
```

<br />

## Test scenarios

<br />

<details>
<summary class="summary_head">

### Payment with credit card: approved

</summary>

<br />

To test an approved payment with status `PAID`, set the `description` field to `200`.

Use the [Create a payment API](https://docs.dlocal.com/reference/create-payment) endpoint if you want to customize the example.

<br />

#### Example request

```json Example request data
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": "thiago@example.com",
    "document": "53033315550",
    "user_reference": "12345",
    "address": {
      "state": "Rio de Janeiro",
      "city": "Volta Redonda",
      "zip_code": "27275-595",
      "street": "Servidao B-1",
      "number": "1106"
    }
  },
  "card": {
    "holder_name": "Thiago Gabriel",
    "number": "4111111111111111",
    "cvv": "123",
    "expiration_month": 10,
    "expiration_year": 2040
  },
  "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:

```json Examaple response information
{
  "status" : "PAID",
  "status_code" : "200",
  "status_detail" : "The payment was paid."
}
```

<br />

</details>

***

<details>
<summary class="summary_head">

### Payment with credit card: rejected

</summary>

<br />

To test a rejected payment with status `REJECTED`, set the `description` field to `300`.

#### Example request

```json Example request data
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": "thiago@example.com",
    "document": "53033315550",
    "user_reference": "12345",
    "address": {
      "state": "Rio de Janeiro",
      "city": "Volta Redonda",
      "zip_code": "27275-595",
      "street": "Servidao B-1",
      "number": "1106"
    }
  },
  "card": {
    "holder_name": "Thiago Gabriel",
    "number": "4111111111111111",
    "cvv": "123",
    "expiration_month": 10,
    "expiration_year": 2040
  },
  "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:

```json Exmaple response information
{
  "status" : "REJECTED",
  "status_code" : "300",
  "status_detail" : "The payment was rejected."
}
```

</details>

***

<details>
<summary class="summary_head">

### Direct cash payment: approve or expire

</summary>

<br />

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](https://docs.dlocal.com/docs/payment-method) page to explore different payment methods.

<br />

#### Payment example request

```json Example request data
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": "thiago@example.com",
    "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"
}
```

<br />

#### Final status example request

```json Example request update status
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

```json Exmaple response information
{
   "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.

```json Exmaple response information
{
   "code": 5002,
   "message": "Payment D-4-fdb6fe34-de6c-4f66-8895-ef87a1918b29 has not status PENDING. Actual status: PAID"
}
```

<br />

</details>

***

<details>
<summary class="summary_head">

### Refund for cash and bank transfer

</summary>

<br />

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](https://docs.dlocal.com/reference/make-a-refund).

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.

<br />

#### Example request

```json Example request data
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.

```json Exmaple response information
{
 "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`.

```json Exmaple response information
{
 "code": 5002,
 "message": "Payment D-4-fdb6fe34-de6c-4f66-8895-ef87a1918b29 has not status PENDING. Actual status: PAID"
}
```

</details>