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

# Sandbox Environment

> Test your integration safely before going live

## Overview

The Monei sandbox environment allows you to test your integration without using real money or affecting production data. Test all features in a safe, isolated environment.

**What you'll learn:**

* Accessing the sandbox
* Test credentials
* Simulating transactions
* Test data
* Limitations
* Moving to production

***

## Sandbox vs Production

| Feature                 | Sandbox                    | Production             |
| ----------------------- | -------------------------- | ---------------------- |
| **API Base URL**        | `https://api.dev.monei.cc` | `https://api.monei.cc` |
| **API Key Prefix**      | `sk_test_...`              | `sk_live_...`          |
| **Real Money**          | No                         | Yes                    |
| **Real Bank Transfers** | No                         | Yes                    |
| **Real Bill Payments**  | No                         | Yes                    |
| **Blockchain**          | Testnet                    | Mainnet                |
| **Data Persistence**    | Temporary                  | Permanent              |

***

## Getting Started

### 1. Get Sandbox API Key

<Steps>
  <Step title="Sign Up">
    Create a Monei account at [monei.cc](https://monei.cc)
  </Step>

  <Step title="Access Dashboard">
    Log in to your dashboard
  </Step>

  <Step title="Navigate to API Keys">
    Go to Settings → API Keys → Sandbox
  </Step>

  <Step title="Copy Test Key">
    Copy your sandbox API key (starts with `sk_test_`)
  </Step>
</Steps>

### 2. Configure SDK

<CodeGroup>
  ```javascript Node.js theme={null}
  import MoneiSDK from 'monei-sdk';

  // Sandbox configuration
  const monei = new MoneiSDK({
    apiKey: process.env.MONEI_SANDBOX_API_KEY, // sk_test_...
    baseUrl: 'https://api.dev.monei.cc',
  });

  // Verify sandbox mode
  console.log('base url:', monei.baseUrl); // 'sandbox'
  ```

  ```python Python theme={null}
  from monei import MoneiClient

  # Sandbox configuration
  monei = MoneiClient(
      api_key=os.getenv('MONEI_SANDBOX_API_KEY'),  # sk_test_...
      base_url='https://api.dev.monei.cc'
  )

  # Verify sandbox mode
  print(f'Environment: {monei.environment}')  # 'sandbox'
  ```

  ```bash Environment Variables theme={null}
  # .env.sandbox
  MONEI_API_KEY=sk_test_abc123xyz456...
  MONEI_ENVIRONMENT=sandbox
  MONEI_BASE_URL=https://api.dev.monei.cc
  ```
</CodeGroup>

***

## Test Credentials

### Test Bank Accounts

Use these test bank accounts for payouts and verification:

| Bank            | Account Number | Account Name   | Status  |
| --------------- | -------------- | -------------- | ------- |
| **Access Bank** | 0690000031     | TEST USER      | Success |
| **Zenith Bank** | 1111111111     | FAILED ACCOUNT | Fails   |

### Test Cards

Use these test cards for deposits:

| Card Number      | Expiry | CVV | Outcome      |
| ---------------- | ------ | --- | ------------ |
| 5531886652142950 | 09/32  | 564 | Success      |
| 5438898014560229 | 10/32  | 123 | Requires PIN |
| 4187427415564246 | 09/32  | 828 | Requires OTP |
| 4242424242424242 | 12/25  | 100 | Declined     |

### Test Phone Numbers

Use these for airtime/data testing:

| Phone Number | Network | Outcome |
| ------------ | ------- | ------- |
| 08012345678  | MTN     | Success |
| 08098765432  | Airtel  | Success |
| 08011111111  | Glo     | Failed  |
| 08022222222  | 9mobile | Pending |

### Test Meter Numbers

For electricity testing:

| Meter Number | Disco | Outcome                 |
| ------------ | ----- | ----------------------- |
| 12345678901  | IKEDC | Success (returns token) |
| 98765432109  | EKEDC | Success (returns token) |
| 11111111111  | AEDC  | Failed                  |
| 22222222222  | PHED  | Invalid meter           |

***

## Testing Workflows

### Test Naira Deposit

<CodeGroup>
  ```javascript Node.js theme={null}
  // Test card deposit
  const deposit = await monei.wallet.depositWithCard({
    amount: 10000,
    reference: 'TEST-DEP-' + Date.now(),
    currency: 'NGN',
    card: {
      cardNumber: '5531886652142950',
      cvv: '564',
      expiryMonth: '09',
      expiryYear: '32',
      cardHolderName: 'TEST USER'
    },
    narration: 'Test deposit'
  });

  console.log('Deposit Reference:', deposit.reference);
  console.log('Status:', deposit.status);

  // Handle next action if needed
  if (deposit.nextAction) {
    console.log('Action required:', deposit.nextAction.type);
    // In sandbox, you can use test PIN: 1234
  }
  ```

  ```python Python theme={null}
  # Test card deposit
  deposit = monei.wallet.deposit_with_card(
      amount=10000,
      reference=f'TEST-DEP-{int(time.time())}',
      currency='NGN',
      card={
          'card_number': '5531886652142950',
          'cvv': '564',
          'expiry_month': '09',
          'expiry_year': '32',
          'card_holder_name': 'TEST USER'
      },
      narration='Test deposit'
  )

  print(f'Reference: {deposit.reference}')
  print(f'Status: {deposit.status}')
  ```
</CodeGroup>

### Test Bill Payment

<CodeGroup>
  ```javascript Node.js theme={null}
  // Test MTN airtime purchase
  const payment = await monei.bills.pay({
    billerId: 'mtn-ng',
    customerId: '08012345678', // Test number
    amount: 100,
    type: 'PREPAID',
    reference: 'TEST-BILL-' + Date.now()
  });

  console.log('Payment Reference:', payment.reference);
  console.log('Status:', payment.status);
  // In sandbox, status will be 'successful' immediately
  ```

  ```python Python theme={null}
  # Test airtime
  payment = monei.bills.pay(
      biller_id='mtn-ng',
      customer_id='08012345678',  # Test number
      amount=100,
      type='PREPAID',
      reference=f'TEST-BILL-{int(time.time())}'
  )

  print(f'Reference: {payment.reference}')
  print(f'Status: {payment.status}')
  ```
</CodeGroup>

### Test Offramp

<CodeGroup>
  ```javascript Node.js theme={null}
  // Test crypto to fiat
  const offramp = await monei.offramp.initiateSwap({
    amount: 100,
    token: 'USDT',
    network: 'base',
    fiatCurrency: 'NGN',
    bankCode: '058',
    accountNumber: '0123456789', // Test account
    accountName: 'TEST ACCOUNT'
  });

  console.log('Order Reference:', offramp.reference);
  console.log('Deposit Address:', offramp.onChain.depositAddress);
  console.log('Expected Amount:', offramp.onChain.expectedAmount);

  // In sandbox, you can simulate crypto deposit
  // The address will be a test address on testnet
  ```

  ```python Python theme={null}
  # Test offramp
  offramp = monei.offramp.initiate_swap(
      amount=100,
      token='USDT',
      network='base',
      fiat_currency='NGN',
      bank_code='058',
      account_number='0123456789',  # Test account
      account_name='TEST ACCOUNT'
  )

  print(f'Reference: {offramp.reference}')
  print(f'Deposit Address: {offramp.on_chain.deposit_address}')
  ```
</CodeGroup>

### Test EVM Transaction

<CodeGroup>
  ```javascript Node.js theme={null}
  // Test sending on EVM testnet
  const tx = await monei.evm.sendNativeToken({
    to: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
    amount: '0.01',
    chainId: 84532 // Base Sepolia testnet
  });

  console.log('Transaction Hash:', tx.txHash);
  console.log('View on Explorer:', `https://sepolia.basescan.org/tx/${tx.txHash}`);
  ```

  ```python Python theme={null}
  # Test EVM transaction
  tx = monei.evm.send_native_token(
      to='0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
      amount='0.01',
      chain_id=84532  # Base Sepolia testnet
  )

  print(f'TX Hash: {tx.tx_hash}')
  ```
</CodeGroup>

***

## Sandbox Limitations

<AccordionGroup>
  <Accordion icon="coins" title="No Real Money">
    **Limitation:** Sandbox uses test money, not real currency

    **Impact:**

    * No actual bank transfers
    * No real bill payments
    * Crypto uses testnets

    **Testing:**

    * Use test credentials
    * Simulate all scenarios
    * Verify integration logic
  </Accordion>

  <Accordion icon="database" title="Data Persistence">
    **Limitation:** Sandbox data may be reset periodically

    **Impact:**

    * Test data cleared monthly
    * Transaction history temporary
    * Don't rely on long-term storage

    **Best Practice:**

    * Export important test data
    * Document test scenarios
    * Use production for real data
  </Accordion>

  <Accordion icon="clock" title="Processing Times">
    **Limitation:** Instant processing in sandbox

    **Impact:**

    * No real delays
    * Instant confirmations
    * Can't test timeout handling

    **Testing:**

    * Manually simulate delays
    * Test timeout logic separately
    * Use production for real timing
  </Accordion>

  <Accordion icon="network-wired" title="Blockchain Networks">
    **Limitation:** Uses testnets only

    **Networks:**

    * Base Sepolia (not Base mainnet)
    * Polygon Mumbai (not Polygon mainnet)
    * Solana Devnet (not mainnet-beta)

    **Testing:**

    * Get testnet tokens from faucets
    * Use testnet explorers
    * Verify on testnet first
  </Accordion>

  <Accordion icon="bell" title="Webhooks">
    **Limitation:** Webhook behavior may differ

    **Impact:**

    * Faster delivery
    * May skip some retries
    * Different timing

    **Testing:**

    * Test webhook handling
    * Verify signature validation
    * Check idempotency
  </Accordion>
</AccordionGroup>

***

## Test Scenarios

### Successful Flow

<CodeGroup>
  ```javascript Node.js theme={null}
  // Complete successful deposit flow
  async function testSuccessfulDeposit() {
    console.log('Testing successful deposit...\n');
    
    // 1. Get wallet balance before
    const walletBefore = await monei.wallet.me();
    const balanceBefore = parseFloat(walletBefore.nairaBalance);
    console.log('Balance before:', balanceBefore);
    
    // 2. Make deposit
    const deposit = await monei.wallet.depositWithCard({
      amount: 5000,
      reference: 'TEST-SUCCESS-' + Date.now(),
      card: {
        cardNumber: '5531886652142950',
        cvv: '564',
        expiryMonth: '09',
        expiryYear: '32',
        cardHolderName: 'TEST USER'
      }
    });
    
    console.log('Deposit initiated:', deposit.reference);
    
    // 3. Wait a bit (in sandbox, instant)
    await new Promise(resolve => setTimeout(resolve, 1000));
    
    // 4. Check balance after
    const walletAfter = await monei.wallet.me();
    const balanceAfter = parseFloat(walletAfter.nairaBalance);
    console.log('Balance after:', balanceAfter);
    console.log('Difference:', balanceAfter - balanceBefore);
    
    // 5. Verify
    if (balanceAfter === balanceBefore + 5000) {
      console.log('✓ Test passed!');
    } else {
      console.log('✗ Test failed!');
    }
  }

  await testSuccessfulDeposit();
  ```

  ```python Python theme={null}
  # Test successful deposit
  async def test_successful_deposit():
      print('Testing successful deposit...\n')
      
      # Before
      wallet_before = monei.wallet.me()
      balance_before = float(wallet_before.naira_balance)
      print(f'Before: ₦{balance_before}')
      
      # Deposit
      deposit = monei.wallet.deposit_with_card(
          amount=5000,
          reference=f'TEST-SUCCESS-{int(time.time())}',
          card={
              'card_number': '5531886652142950',
              'cvv': '564',
              'expiry_month': '09',
              'expiry_year': '32',
              'card_holder_name': 'TEST USER'
          }
      )
      
      print(f'Initiated: {deposit.reference}')
      
      # Wait
      await asyncio.sleep(1)
      
      # After
      wallet_after = monei.wallet.me()
      balance_after = float(wallet_after.naira_balance)
      print(f'After: ₦{balance_after}')
      print(f'Difference: ₦{balance_after - balance_before}')
      
      # Verify
      if balance_after == balance_before + 5000:
          print('✓ Test passed!')
      else:
          print('✗ Test failed!')

  await test_successful_deposit()
  ```
</CodeGroup>

### Failed Flow

<CodeGroup>
  ```javascript Node.js theme={null}
  // Test failed payment
  async function testFailedPayment() {
    console.log('Testing failed payment...\n');
    
    try {
      // Use test account that fails
      const payment = await monei.bills.pay({
        billerId: 'mtn-ng',
        customerId: '08011111111', // Test number that fails
        amount: 100,
        type: 'PREPAID'
      });
      
      console.log('✗ Should have failed!');
    } catch (error) {
      console.log('✓ Failed as expected');
      console.log('Error:', error.message);
    }
  }

  await testFailedPayment();
  ```

  ```python Python theme={null}
  # Test failed payment
  async def test_failed_payment():
      print('Testing failed payment...\n')
      
      try:
          # Fails
          payment = monei.bills.pay(
              biller_id='mtn-ng',
              customer_id='08011111111',  # Fails
              amount=100,
              type='PREPAID'
          )
          
          print('✗ Should have failed!')
      except Exception as error:
          print('✓ Failed as expected')
          print(f'Error: {error}')

  await test_failed_payment()
  ```
</CodeGroup>

***

## Testing Checklist

<CardGroup cols={2}>
  <Card title="Deposits" icon="check">
    Card deposit success\
    Card deposit with PIN\
    Card deposit with OTP\
    Card declined\
    Bank transfer\
    USSD deposit
  </Card>

  <Card title="Payouts" icon="check">
    Bank transfer success\
    Bank transfer failed\
    P2P transfer\
    Insufficient balance\
    Invalid account
  </Card>

  <Card title="Bill Payments" icon="check">
    Airtime success\
    Data bundle\
    Cable TV\
    Electricity\
    Payment failed\
    Invalid customer
  </Card>

  <Card title="Offramp" icon="check">
    Initiate swap\
    Crypto deposit\
    Fiat transfer\
    Order tracking\
    Failed conversion
  </Card>

  <Card title="Crypto" icon="check">
    EVM transactions\
    Solana transactions\
    Token swaps\
    Portfolio tracking\
    Balance checks
  </Card>

  <Card title="Webhooks" icon="check">
    Signature verification\
    Event handling\
    Retry logic\
    Idempotency\
    Error handling
  </Card>
</CardGroup>

***

## Moving to Production

When ready to go live:

<Steps>
  <Step title="Complete Testing">
    * Test all workflows
    * Verify error handling
    * Check edge cases
    * Document test results
  </Step>

  <Step title="Get Production API Key">
    * Generate live API key (sk\_live\_...)
    * Store securely
    * Never commit to git
  </Step>

  <Step title="Update Configuration">
    * Change base URL to production
    * Use production API key
    * Update environment variables
  </Step>

  <Step title="Security Review">
    * Enable HTTPS
    * Verify webhook signatures
    * Implement rate limiting
    * Review access controls
  </Step>

  <Step title="Monitoring Setup">
    * Configure alerts
    * Set up logging
    * Enable error tracking
    * Monitor transactions
  </Step>

  <Step title="Start Small">
    * Test with small amounts
    * Monitor closely
    * Gradually increase
    * Keep sandbox for testing
  </Step>
</Steps>

***

## Best Practices

<CardGroup cols={2}>
  <Card title="Test Thoroughly" icon="vial">
    Test all scenarios before production
  </Card>

  <Card title="Use Test Data" icon="database">
    Always use provided test credentials
  </Card>

  <Card title="Document Tests" icon="file-lines">
    Keep record of test scenarios and results
  </Card>

  <Card title="Automate Testing" icon="robot">
    Create automated test suites
  </Card>

  <Card title="Keep Sandbox" icon="flask">
    Use sandbox for ongoing development
  </Card>

  <Card title="Monitor Both" icon="eye">
    Monitor sandbox and production separately
  </Card>
</CardGroup>

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Testing Tools" icon="wrench" href="/testing/tools">
    Tools for testing your integration
  </Card>

  <Card title="Security" icon="shield" href="/security/guidelines">
    Security best practices
  </Card>

  <Card title="Error Handling" icon="triangle-exclamation" href="/core-concepts/error-handling">
    Handle errors properly
  </Card>

  <Card title="Webhooks" icon="webhook" href="/security/webhooks">
    Test webhook integration
  </Card>
</CardGroup>
