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

# Payment Simulation

> Test quote payments in staging environment using the simulation endpoint

# Payment Simulation

The simulation endpoint allows you to test payment flows in the staging environment without making actual payments. This is useful for testing your integration and webhook handlers.

<Warning>
  The simulation endpoint is only available in the **staging environment**: `https://staging.api.mavapay.co/api/v1`
</Warning>

## Endpoint

```
POST /api/v1/simulation/pay-in
```

## How It Works

1. Create a quote using the [Create Quote endpoint](/api-reference/endpoint/quote/get-quote)
2. Use the `quoteId` (or `orderId` if you don't have the quote) from the response
3. Call the simulation endpoint to simulate payment
4. Your webhook will receive `payment.received` event
5. If autopayout is enabled, you'll also receive `payment.sent` event

## Nigerian Naira (NGN) Simulation

### Request

```json theme={null}
{
  "currency": "NGN",
  "quoteId": "c523383d-d44c-4d2e-be48-b64bcaf7b403",
  "amount": 604300
}
```

### Response

```json theme={null}
{
  "status": "ok",
  "data": "PayIn simulation successful"
}
```

### Parameters

| Parameter  | Type          | Required | Description                                       |
| ---------- | ------------- | -------- | ------------------------------------------------- |
| `currency` | string        | Yes      | Must be `"NGN"`                                   |
| `quoteId`  | string (UUID) | No\*     | The quote ID from your created quote              |
| `orderId`  | string (UUID) | No\*     | The order ID (use if you don't have the quote ID) |
| `amount`   | number        | Yes      | Amount in kobo (must match quote amount)          |

\*Either `quoteId` or `orderId` is required.

## Bitcoin (BTC) Simulation

### Request

```json theme={null}
{
  "currency": "BTC",
  "quoteId": "a523383d-d44c-4d2e-be48-b64bcaf7b404"
}
```

### Response

```json theme={null}
{
  "status": "ok",
  "data": "PayIn simulation successful"
}
```

### Parameters

| Parameter  | Type          | Required | Description                                       |
| ---------- | ------------- | -------- | ------------------------------------------------- |
| `currency` | string        | Yes      | Must be `"BTC"`                                   |
| `quoteId`  | string (UUID) | No\*     | The quote ID from your created quote              |
| `orderId`  | string (UUID) | No\*     | The order ID (use if you don't have the quote ID) |

\*Either `quoteId` or `orderId` is required.

<Note>
  For BTC simulations, the `amount` parameter is not required as it's determined by the Lightning invoice.
</Note>

## Payment Link Simulation

For Payment Links (including on-chain Bitcoin purchases), you need to first retrieve the order ID.

### Step 1: Get the Order ID

Retrieve the order ID associated with your payment link:

```bash theme={null}
curl -X GET "https://staging.api.mavapay.co/api/v1/paymentlink/orders?id={paymentRef}" \
  -H "X-API-KEY: your_staging_api_key"
```

### Step 2: Simulate Payment

Use the order ID to simulate the bank transfer:

```bash theme={null}
curl -X POST https://staging.api.mavapay.co/api/v1/simulation/pay-in \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: your_staging_api_key" \
  -d '{
    "amount": 800000,
    "currency": "NGN",
    "orderId": "11110-0001"
}'
```

<Note>
  For Payment Link simulations, use `orderId` instead of `quoteId`. The amount should match the payment link amount in kobo.
</Note>

***

## Complete Testing Flow

### Step 1: Create a Quote

```bash theme={null}
curl -X POST https://staging.api.mavapay.co/api/v1/quote \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: your_staging_api_key" \
  -d 
  '{
    "amount": "604300",
    "sourceCurrency": "NGNKOBO",
    "targetCurrency": "KESCENT",
    "paymentMethod": "BANKTRANSFER",
    "paymentCurrency": "NGNKOBO",
    "autopayout": true,
    "beneficiary": {
      "identifierType": "paytophone",
      "identifiers": {
        "phoneNumber": "+254796980711",
        "accountName": "John Doe",
        "network": "mpesa"
      }
    }
  }'
```

### Step 2: Simulate Payment

```bash theme={null}
curl -X POST https://staging.api.mavapay.co/api/v1/simulation/pay-in \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: your_staging_api_key" \
  -d '{
    "currency": "NGN",
    "quoteId": "c523383d-d44c-4d2e-be48-b64bcaf7b403",
    "amount": 604300
  }'
```

### Step 3: Receive Webhook

Your registered webhook endpoint will receive a `payment.received` event:

```json theme={null}
{
  "event": "payment.received",
  "data": {
    "id": "0b234e32-d5ba-4c2a-8f71-0b820a477f01",
    "amount": 604300,
    "currency": "NGN",
    "type": "DEPOSIT",
    "status": "SUCCESS",
    ...
  }
}
```

If autopayout is enabled, you'll also receive a `payment.sent` event shortly after.

## Testing Different Scenarios

### Test Successful Payment

Use the simulation endpoint as shown above to test successful payment flows.

### Using Order ID Instead of Quote ID

If you don't have access to the quote ID, you can use the order ID instead:

```bash theme={null}
curl -X POST https://staging.api.mavapay.co/api/v1/simulation/pay-in \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: your_staging_api_key" \
  -d '{
    "currency": "NGN",
    "orderId": "5466-3532",
    "amount": 604300
  }'
```

### Test Different Currency Pairs

Create quotes for different currency pairs and simulate payments:

```javascript theme={null}
// BTCSAT => KESCENT
const btcToKes = await createQuote({
  amount: "100000",
  sourceCurrency: "BTCSAT",
  targetCurrency: "KESCENT",
  ...
});

await simulatePayment({
  currency: "BTC",
  quoteId: btcToKes.data.id
});

// NGNKOBO => ZARCENT
const ngnToZar = await createQuote({
  amount: "300000",
  sourceCurrency: "NGNKOBO",
  targetCurrency: "ZARCENT",
  ...
});

await simulatePayment({
  currency: "NGN",
  quoteId: ngnToZar.data.id,
  amount: 300000
});
```

### Test Webhook Handling

1. Set up a webhook endpoint using [webhook.site](https://webhook.site) or [ngrok](https://ngrok.com)
2. Register your webhook in staging
3. Create a quote and simulate payment
4. Verify your webhook receives and processes the events correctly

## Common Errors

| Error                | Description                                     | Solution                                      |
| -------------------- | ----------------------------------------------- | --------------------------------------------- |
| `Invalid quote ID`   | Quote doesn't exist or has expired              | Create a new quote and use the fresh quote ID |
| `Amount mismatch`    | Simulation amount doesn't match quote amount    | Use the exact amount from the quote response  |
| `Quote already paid` | Quote has already been paid (simulated or real) | Create a new quote for testing                |
| `Invalid currency`   | Currency doesn't match quote parameters         | Use the correct currency from your quote      |

## Best Practices

1. **Fresh Quotes**: Create new quotes for each test to avoid "already paid" errors
2. **Webhook Testing**: Test both `payment.received` and `payment.sent` events
3. **Error Handling**: Test how your system handles different payment statuses
4. **Idempotency**: Verify your webhook handler processes duplicate events correctly
5. **Timing**: Test scenarios where webhooks arrive out of order

## Integration Checklist

* [ ] Create quotes successfully
* [ ] Simulate NGN payments
* [ ] Simulate BTC payments
* [ ] Receive `payment.received` webhooks
* [ ] Receive `payment.sent` webhooks
* [ ] Handle webhook signature verification
* [ ] Implement idempotent webhook processing
* [ ] Test error scenarios
* [ ] Verify beneficiary payouts work correctly

## Next Steps

* Learn about [webhook integration](/webhooks/introduction)
* View [quote examples](/api-reference/quote-examples) for all currency pairs
* Explore [beneficiary formats](/api-reference/beneficiary-formats)
* Test in production with small amounts first

<Tip>
  Always thoroughly test your integration in staging before moving to production!
</Tip>
