> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dollarpe.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Testing in Sandbox

> Test your full integration — API, Widget, or Client Dashboard — against the DollarPe sandbox environment before going live.

The DollarPe sandbox environment provides a safe, isolated testing ground for validating your integration before deploying to production. No real funds are involved, and all three integration paths are supported.

<Note>
  **Key benefits of sandbox testing:** Test the full integration flow without real funds — validate against our API specs, simulate success and error scenarios, and gain confidence before going live.
</Note>

## Testing approaches

<Tabs>
  <Tab title="API Integration">
    Use sandbox base URLs with your sandbox API credentials. The full flow — customer creation, KYC, bank linking, payin, and payout — works exactly as in production. Use the mock status endpoints to simulate transaction state changes without waiting for real blockchain confirmations.

    Sandbox base URL: `https://sandbox.dollarpe.xyz`
  </Tab>

  <Tab title="Widget Integration">
    Call the Widget Initialize API using your sandbox credentials. The widget session will load against sandbox data, giving you the full KYC, payin, and payout UI to test end-to-end without any real funds.

    ```html theme={null}
    <!-- Embed the session URL returned by the Widget Initialize API -->
    <iframe
      src="{sandbox_widget_session_url}"
      width="100%"
      height="700"
      allow="camera; microphone"
    ></iframe>
    ```
  </Tab>

  <Tab title="Client Dashboard">
    Open the dashboard with your sandbox `app_id` to test all flows without writing any code:

    ```
    https://app.dollarpe.xyz?app_id={your_sandbox_app_id}
    ```

    All operations (onboarding, KYC, payin, payout) run against sandbox data.
  </Tab>
</Tabs>

## Sandbox vs. production

| Feature             | Sandbox                                | Production                        |
| :------------------ | :------------------------------------- | :-------------------------------- |
| Base URL            | `https://sandbox.dollarpe.xyz`         | `https://production.dollarpe.xyz` |
| API Keys            | Sandbox-specific                       | Production-specific               |
| Funds               | Test funds only                        | Real funds                        |
| Blockchain Networks | Includes test networks (e.g., Sepolia) | Mainnet only                      |
| Processing Times    | Accelerated                            | Actual processing times           |

## Getting started with sandbox

### Step 1: Obtain sandbox credentials

<Warning>
  Sandbox credentials are different from production credentials and cannot be used interchangeably.
</Warning>

Contact our [support team](mailto:support@dollarpe.xyz) to request sandbox access. You'll receive your sandbox API key and API secret.

### Step 2: Configure your environment

```javascript theme={null}
const config = {
  baseUrl: "https://sandbox.dollarpe.xyz",
  apiKey: "YOUR_SANDBOX_API_KEY",
  apiSecret: "YOUR_SANDBOX_API_SECRET",
};
```

### Step 3: Set up authentication

Authentication works identically in sandbox and production. See the [Authentication guide](/guides/development-and-testing/authentication) for how to generate the required headers.

## Testing the KYC flow

### Creating test customers

```javascript theme={null}
const createTestCustomer = async () => {
  const requestBody = {
    full_name: "Test User",
    email: "testuser@example.com",
    phone: "9911002211",
    country: "IND",
    type: "individual",
  };

  const headers = generateHeaders(config.apiKey, config.apiSecret, requestBody);

  const response = await fetch(`${config.baseUrl}/cms/api/v1/customer/create`, {
    method: "POST",
    headers: headers,
    body: JSON.stringify(requestBody),
  });

  return await response.json();
};
```

### Submitting test KYC data

In sandbox, use test document URLs for KYC submission. Verification is automatically approved for most test submissions.

```javascript theme={null}
const submitTestKYC = async (customerId) => {
  const requestBody = {
    customer_id: customerId,
    full_name: "Test User",
    phone: "9911002211",
    full_address: "123 Test Street, Test City",
    dob: "01-01-1990",
    document_type: "AADHAAR",
    document_front_image_url:
      "https://sandbox.dollarpe.xyz/test-images/aadhaar-front.jpg",
    document_back_image_url:
      "https://sandbox.dollarpe.xyz/test-images/aadhaar-back.jpg",
    document_details: {
      document_number: "123456789012",
    },
  };

  const headers = generateHeaders(config.apiKey, config.apiSecret, requestBody);

  const response = await fetch(`${config.baseUrl}/cms/api/v1/kyc/add-kyc-data`, {
    method: "POST",
    headers: headers,
    body: JSON.stringify(requestBody),
  });

  return await response.json();
};
```

### Adding test bank accounts

```javascript theme={null}
const addTestBankAccount = async (customerId) => {
  const requestBody = {
    customer_id: customerId,
    account_number: "7627389201",
    ifsc: "SBI0001829IU",
    vpa: "abc@okbank",
  };

  const headers = generateHeaders(config.apiKey, config.apiSecret, requestBody);

  const response = await fetch(`${config.baseUrl}/cms/api/v1/bank/add-account`, {
    method: "POST",
    headers: headers,
    body: JSON.stringify(requestBody),
  });

  return await response.json();
};
```

## Testing the payin flow

### Fetch payin configuration

```javascript theme={null}
const fetchPayinConfiguration = async () => {
  const headers = generateHeaders(config.apiKey, config.apiSecret);
  const response = await fetch(`${config.baseUrl}/pis/api/v1/payin/configuration`, {
    method: "GET",
    headers: headers,
  });
  return await response.json();
};
```

### Create a payin quotation

```javascript theme={null}
const createPayinQuotation = async (customerId, bankId, ipAddress, deviceId) => {
  const requestBody = {
    asset: "USDC",
    fiat: "INR",
    sending_amount: "10000",
    customer_id: customerId,
    bank_id: bankId,
    payment_method: "IMPS",
    risk_parameters: {
      ip_address: ipAddress,
      device_id: deviceId,
      suspicious_activity_report: "False",
      law_enforcement_agency_report: "False",
    },
  };

  const headers = generateHeaders(config.apiKey, config.apiSecret, requestBody);

  const response = await fetch(`${config.baseUrl}/pis/api/v1/payin/quotation`, {
    method: "POST",
    headers: headers,
    body: JSON.stringify(requestBody),
  });

  return await response.json();
};
```

### Initiate a test payin

```javascript theme={null}
const initiateTestPayin = async (quotationId, customerId, utr) => {
  const requestBody = {
    quotation_id: quotationId,
    customer_id: customerId,
    client_reference_id: "test123",
    utr: utr,
  };

  const headers = generateHeaders(config.apiKey, config.apiSecret, requestBody);

  const response = await fetch(`${config.baseUrl}/pis/api/v1/payin/initiate`, {
    method: "POST",
    headers: headers,
    body: JSON.stringify(requestBody),
  });

  return await response.json();
};
```

## Testing the payout flow

### Create a payout quotation

```javascript theme={null}
const createPayoutQuotation = async (customerId) => {
  const requestBody = {
    asset: "usdt",
    fiat: "inr",
    network: "sepolia",
    sending_amount: "10",
    customer_id: customerId,
  };

  const headers = generateHeaders(config.apiKey, config.apiSecret, requestBody);

  const response = await fetch(`${config.baseUrl}/pos/api/v1/payout/quotation`, {
    method: "POST",
    headers: headers,
    body: JSON.stringify(requestBody),
  });

  return await response.json();
};
```

### Send test cryptocurrency

<Warning>
  Even in sandbox, you must send funds to the exact wallet address provided in the quotation response. Use test networks like Sepolia instead of mainnet.
</Warning>

1. Get test tokens from a Sepolia faucet.
2. Send the exact amount of test USDT/USDC to the wallet address from the quotation.
3. Obtain the transaction hash for the next step.

### Initiate a test payout

```javascript theme={null}
const initiateTestPayout = async (quotationId, customerId, bankId, txHash) => {
  const requestBody = {
    quotation_id: quotationId,
    customer_id: customerId,
    client_reference_id: "test123",
    bank_id: bankId,
    tx_hash: txHash,
  };

  const headers = generateHeaders(config.apiKey, config.apiSecret, requestBody);

  const response = await fetch(`${config.baseUrl}/pos/api/v1/payout/initiate`, {
    method: "POST",
    headers: headers,
    body: JSON.stringify(requestBody),
  });

  return await response.json();
};
```

## Testing webhook integration

```javascript theme={null}
const configureWebhook = async () => {
  const requestBody = {
    url: "https://your-test-server.com/webhook/dollarpe",
  };

  const headers = generateHeaders(config.apiKey, config.apiSecret, requestBody);

  const response = await fetch(
    `${config.baseUrl}/org/api/v1/organizations/api-webhooks`,
    {
      method: "POST",
      headers: headers,
      body: JSON.stringify(requestBody),
    }
  );

  return await response.json();
};
```

<Tip>
  For local development, use [ngrok](https://ngrok.com/) to create a public HTTPS URL that forwards to your local webhook handler.
</Tip>

## Sandbox testing checklist

<Accordion title="Customer and KYC">
  * [ ] Create a test customer profile
  * [ ] Submit KYC details for verification
  * [ ] Confirm successful KYC approval flow
  * [ ] Simulate KYC rejection and error responses
  * [ ] Update and resubmit failed KYC information
  * [ ] Add and verify bank account details
</Accordion>

<Accordion title="Payin flow">
  * [ ] Retrieve payin configurations
  * [ ] Fetch exchange rates
  * [ ] Generate and review quotations
  * [ ] Handle expired quotation scenarios
  * [ ] Initiate payin with transaction reference
  * [ ] Use mock status endpoint to change transaction status
  * [ ] Monitor status updates throughout the payin flow
  * [ ] Simulate and handle payin failure scenarios
</Accordion>

<Accordion title="Payout flow">
  * [ ] Retrieve payout configurations
  * [ ] Fetch exchange rates
  * [ ] Generate and review quotations
  * [ ] Handle expired quotation scenarios
  * [ ] Simulate crypto transfer using testnet
  * [ ] Initiate payout with transaction reference
  * [ ] Use mock status endpoint to change transaction status
  * [ ] Monitor status updates throughout the payout flow
  * [ ] Simulate and handle payout failure scenarios
</Accordion>

<Accordion title="Webhook testing">
  * [ ] Set up and configure your webhook endpoint
  * [ ] Confirm webhook receives KYC status events
  * [ ] Confirm webhook receives transaction status events
  * [ ] Test webhook retry and failure handling
</Accordion>

<Accordion title="Error handling">
  * [ ] Simulate invalid or expired API credentials
  * [ ] Submit invalid or incomplete request payloads
  * [ ] Test rate limiting responses
  * [ ] Simulate network timeouts
  * [ ] Verify user-facing error messages are clear and actionable
</Accordion>

## Transitioning to production

Once sandbox testing is complete:

1. Request production API credentials from our [support team](mailto:support@dollarpe.xyz).
2. Update your configuration to use production URLs and credentials.
3. Remove or condition all sandbox-specific logic and test data.
4. Implement production logging and monitoring.
5. Set up alerts for critical error conditions.
6. Test with small amounts first before full deployment.

<Warning>
  Before going live, ensure you have proper error handling, logging, and monitoring in place. Real funds will be at stake in production.
</Warning>
