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

# Webhook Simulators

> Test SPEI, PayCash, and CIE Cash Net payment flows without real bank transfers or cash deposits

## Overview

Webhook simulators let you test offline payment flows in development without real money movement:

* **SPEI (STP/OPM):** simulate bank deposits using a CLABE
* **PayCash:** simulate a cash deposit using the PayCash reference
* **CIE Cash Net:** simulate BBVA deposit reconciliation using the CIE reference

This accelerates development and lets you test both success and failure scenarios.

<CardGroup cols={2}>
  <Card title="No Real Transfers" icon="shield-check">
    Test without moving real money
  </Card>

  <Card title="Instant Feedback" icon="bolt">
    No waiting for actual bank processing
  </Card>

  <Card title="Test Failures" icon="triangle-exclamation">
    Simulate failed payments and refunds
  </Card>

  <Card title="Full Webhooks" icon="webhook">
    Receive the same webhooks as production
  </Card>
</CardGroup>

## How It Works

<Steps>
  <Step title="Create SPEI Payment">
    Create a SPEI payment using the payments API. The payment will be in `PENDING_CAPTURE` status with a CLABE assigned.
  </Step>

  <Step title="Trigger Simulator">
    Call the simulator endpoint with the CLABE and desired action (`pass` or `fail`).
  </Step>

  <Step title="Receive Webhook">
    Your webhook endpoint receives the same payment status change webhook as production.
  </Step>
</Steps>

## Available Simulators

### STP Simulator

```http theme={null}
POST /ps/webhook/stp/simulator
Content-Type: application/json
```

**Availability:** Development environment only

**Request Body:**

```json theme={null}
{
  "clabe": "646180157000000001",
  "action": "pass"
}
```

### OPM Simulator

```http theme={null}
POST /ps/webhook/opm/simulator
Content-Type: application/json
```

**Availability:** Development environment only

**Request Body:**

```json theme={null}
{
  "clabe": "684180338000000186",
  "action": "pass"
}
```

### PayCash Simulator

```http theme={null}
POST /ps/webhook/paycash/simulator
Content-Type: application/json
```

**Availability:** Development environment only

**Request Body:**

```json theme={null}
{
  "reference": "7041621293386809",
  "action": "pass"
}
```

| Field       | Description                                                              |
| ----------- | ------------------------------------------------------------------------ |
| `reference` | `paymentMethod.paycashDetails.reference` from the payment order response |
| `action`    | `pass` (capture) or `fail` (simulated capture failure)                   |

<Note>
  PayCash does not auto-complete in sandbox like SPEI. Use this simulator (or a full deposit webhook flow) to move the payment to `CAPTURED` and receive `payment.capture.success` on your merchant webhook.
</Note>

### CIE Cash Net Simulator

```http theme={null}
POST /ps/webhook/cie-cash-net/simulator
Content-Type: application/json
```

**Availability:** Development environment only

**Request Body:**

```json theme={null}
{
  "reference": "01234567",
  "action": "pass"
}
```

| Field       | Description                                                          |
| ----------- | -------------------------------------------------------------------- |
| `reference` | `paymentMethod.cieDetails.reference` from the payment order response |
| `action`    | `pass` (capture) or `fail` (simulated capture failure)               |

<Note>
  CIE Cash Net does not auto-complete in sandbox like SPEI. Use this simulator to mimic BBVA reconciliation, move the payment to `CAPTURED`, and receive `payment.capture.success` on your merchant webhook.
</Note>

## Available Actions

### Payment Capture

| Action | Description                         | Payment Status |
| ------ | ----------------------------------- | -------------- |
| `pass` | Simulates successful deposit        | `CAPTURED`     |
| `fail` | Simulates deposit with wrong amount | `FAILED`       |

### Refunds (SPEI only)

| Action        | Description                 | Payment Status               |
| ------------- | --------------------------- | ---------------------------- |
| `refund-pass` | Simulates successful refund | `REFUNDED`                   |
| `refund-fail` | Simulates failed refund     | `PENDING_REFUND` (unchanged) |

## Testing Payment Capture

### Step 1: Create a SPEI Payment

```bash theme={null}
curl -X POST https://api.sandbox.cheqpay.mx/pos/v2/payment-orders \
  -H "x-api-key: YOUR_API_KEY" \
  -H "x-merchant-id: YOUR_MERCHANT_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "externalId": "order_123",
    "customer": {
      "firstName": "John",
      "lastName": "Doe",
      "email": "john@example.com"
    },
    "amount": 10000,
    "currency": "MXN",
    "description": "SPEI test payment",
    "paymentMethod": {
      "type": "spei"
    }
  }'
```

**Response:**

```json theme={null}
{
  "paymentOrder": {
    "id": "ord_abc123",
    "externalId": "order_123",
    "amount": 10000,
    "currency": "MXN",
    "status": "PENDING",
    "description": "SPEI test payment"
  },
  "customer": {
    "id": "cus_xyz789",
    "firstName": "John",
    "lastName": "Doe",
    "email": "john@example.com"
  },
  "paymentMethod": {
    "type": "spei",
    "speiDetails": {
      "clabe": "646180157000000001"
    }
  }
}
```

<Note>
  Save the CLABE from `paymentMethod.speiDetails.clabe`. You'll need it to trigger the simulator.
</Note>

### Step 2: Simulate Successful Deposit

```bash theme={null}
curl -X POST https://api.sandbox.cheqpay.mx/ps/webhook/stp/simulator \
  -H "Content-Type: application/json" \
  -d '{
    "clabe": "646180157000000001",
    "action": "pass"
  }'
```

**Response:**

```json theme={null}
{
  "success": true,
  "message": "Webhook for CLABE 646180157000000001 simulated successfully with action pass"
}
```

### Step 3: Receive Webhook

Your webhook endpoint will receive a `payment.capture.success` event:

```json theme={null}
{
  "id": "evt_xyz789",
  "event": "payment.capture.success",
  "data": {
    "paymentOrder": {
      "id": "order_123"
    },
    "paymentMethod": {
      "type": "spei",
      "options": {
        "clabe": "646180157000000001"
      }
    },
    "amount": "10000",
    "currency": "MXN",
    "status": "CAPTURED"
  }
}
```

## Testing PayCash Capture

### Step 1: Create a PayCash Payment Order

```bash theme={null}
curl -X POST https://api.sandbox.cheqpay.mx/pos/v2/payment-orders \
  -H "x-api-key: YOUR_API_KEY" \
  -H "x-merchant-id: YOUR_MERCHANT_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "externalId": "order_paycash_123",
    "customer": {
      "firstName": "Laura",
      "lastName": "Ramirez",
      "email": "laura@example.com"
    },
    "amount": 10000,
    "currency": "MXN",
    "description": "PayCash test payment",
    "paymentMethod": {
      "type": "paycash"
    }
  }'
```

<Note>
  **PayCash amount limit:** For now, PayCash orders are supported up to **20,000 MXN** only. Amounts in the API are in centavos, so the maximum `amount` for MXN is `2000000` (20,000.00 MXN). Use card or SPEI for higher values.
</Note>

**Response:**

```json theme={null}
{
  "paymentOrder": {
    "id": "ord_paycash_123",
    "externalId": "order_paycash_123",
    "amount": 10000,
    "currency": "MXN",
    "status": "PENDING",
    "description": "PayCash test payment"
  },
  "customer": {
    "id": "cus_abc123",
    "firstName": "Laura",
    "lastName": "Ramirez",
    "email": "laura@example.com"
  },
  "paymentMethod": {
    "type": "paycash",
    "paycashDetails": {
      "reference": "7041621293386809"
    }
  }
}
```

<Note>
  Save the reference from `paymentMethod.paycashDetails.reference`. You'll need it to trigger the simulator.
</Note>

### Step 2: Simulate Successful Deposit

```bash theme={null}
curl -X POST https://api.sandbox.cheqpay.mx/ps/webhook/paycash/simulator \
  -H "Content-Type: application/json" \
  -d '{
    "reference": "7041621293386809",
    "action": "pass"
  }'
```

**Response:**

```json theme={null}
{
  "success": true,
  "message": "PayCash webhook for reference 7041621293386809 simulated with action pass"
}
```

### Step 3: Receive Webhook

Your webhook endpoint receives `payment.capture.success` with `data.paymentMethod.options.paycash.reference` set to the same reference:

```json theme={null}
{
  "id": "evt_paycash_001",
  "event": "payment.capture.success",
  "data": {
    "paymentOrder": {
      "id": "ord_paycash_123",
      "merchantReference": "order_paycash_123",
      "externalId": "order_paycash_123"
    },
    "customer": {
      "id": "cus_abc123",
      "externalId": "customer-2001"
    },
    "paymentMethod": {
      "type": "paycash",
      "options": {
        "paycash": {
          "reference": "7041621293386809"
        }
      }
    },
    "amount": "10000",
    "currency": "MXN",
    "createdAt": "2026-05-22T12:45:00.000Z"
  }
}
```

<Note>
  You may receive `payment.auth.pending` earlier while the payment is still `PENDING_CAPTURE`. Fulfill the order only after `payment.capture.success`.
</Note>

## Testing CIE Cash Net Capture

### Step 1: Create a CIE Cash Net Payment Order

```bash theme={null}
curl -X POST https://api.sandbox.cheqpay.mx/pos/v2/payment-orders \
  -H "x-api-key: YOUR_API_KEY" \
  -H "x-merchant-id: YOUR_MERCHANT_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "externalId": "order_cie_123",
    "customer": {
      "firstName": "Ana",
      "lastName": "López",
      "email": "ana@example.com"
    },
    "amount": 10000,
    "currency": "MXN",
    "description": "CIE Cash Net test payment",
    "paymentMethod": {
      "type": "cie_cash_net"
    }
  }'
```

**Response:**

```json theme={null}
{
  "paymentOrder": {
    "id": "ord_cie_123",
    "externalId": "order_cie_123",
    "amount": 10000,
    "currency": "MXN",
    "status": "PENDING",
    "description": "CIE Cash Net test payment"
  },
  "customer": {
    "id": "cus_abc123",
    "firstName": "Ana",
    "lastName": "López",
    "email": "ana@example.com"
  },
  "paymentMethod": {
    "type": "CIE_CASH_NET",
    "cieDetails": {
      "reference": "01234567",
      "convenio": "1234567",
      "clabe": "012345678901234567"
    }
  }
}
```

<Note>
  Save the reference from `paymentMethod.cieDetails.reference`. You'll need it to trigger the simulator.
</Note>

### Step 2: Simulate Successful Reconciliation

```bash theme={null}
curl -X POST https://api.sandbox.cheqpay.mx/ps/webhook/cie-cash-net/simulator \
  -H "Content-Type: application/json" \
  -d '{
    "reference": "01234567",
    "action": "pass"
  }'
```

**Response:**

```json theme={null}
{
  "success": true,
  "message": "CIE Cash Net webhook for reference 01234567 simulated with action pass"
}
```

### Step 3: Receive Webhook

Your webhook endpoint receives `payment.capture.success` with `data.paymentMethod.options.cieCashNet` set to the same reference, convenio, and CLABE:

```json theme={null}
{
  "id": "evt_cie_001",
  "event": "payment.capture.success",
  "data": {
    "paymentOrder": {
      "id": "ord_cie_123",
      "merchantReference": "order_cie_123",
      "externalId": "order_cie_123"
    },
    "customer": {
      "id": "cus_abc123",
      "externalId": "customer-301"
    },
    "paymentMethod": {
      "type": "cie_cash_net",
      "options": {
        "cieCashNet": {
          "reference": "01234567",
          "convenio": "1234567",
          "clabe": "012345678901234567"
        }
      }
    },
    "amount": "10000",
    "currency": "MXN",
    "createdAt": "2026-05-22T14:30:00.000Z"
  }
}
```

## Testing Failed Payments

Simulate a failed payment to test error handling:

```bash theme={null}
curl -X POST https://api.sandbox.cheqpay.mx/ps/webhook/stp/simulator \
  -H "Content-Type: application/json" \
  -d '{
    "clabe": "646180157000000001",
    "action": "fail"
  }'
```

Your webhook will receive a `payment.auth.failed` event (payments transitioning to `FAILED` emit `payment.auth.failed`; a distinct `payment.capture.failed` event is not emitted today).

<Warning>
  The simulator sends a deposit with an incorrect amount (`0.0001`), which causes the payment to fail. This matches how real bank transfers can fail due to amount mismatches.
</Warning>

## Testing Refunds

### Step 1: Request a Refund

First, create a refund for a captured payment:

```bash theme={null}
curl -X POST https://api.sandbox.cheqpay.mx/pos/v2/payment-orders/{id}/refund \
  -H "x-api-key: YOUR_API_KEY" \
  -H "x-merchant-id: YOUR_MERCHANT_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": "10000",
    "reason": "Customer requested refund"
  }'
```

The payment status changes to `PENDING_REFUND`.

### Step 2: Simulate Refund Processing

```bash theme={null}
curl -X POST https://api.sandbox.cheqpay.mx/ps/webhook/stp/simulator \
  -H "Content-Type: application/json" \
  -d '{
    "clabe": "646180157000000001",
    "action": "refund-pass"
  }'
```

### Step 3: Receive Refund Webhook

Your webhook endpoint will receive a `payment.refund.success` event with the payment status as `REFUNDED`.

## Simulator Behavior

### Multiple Pending Payments

If you have multiple payments with the same CLABE in `PENDING_CAPTURE` status:

* The simulator sums all pending amounts
* Simulates a single deposit for the total amount
* All pending payments are captured

### Already Captured Payments

If the payment is already `CAPTURED`:

* The simulator detects it's already processed
* Sends a webhook to your endpoint anyway (useful for testing webhook retry logic)
* Returns `success: true`

### Payment Not Found

If no payment matches the CLABE and status:

```json theme={null}
{
  "success": false,
  "message": "No pending payment found for CLABE 646180157000000001"
}
```

## STP vs OPM Differences

| Feature                | STP                      | OPM                      |
| ---------------------- | ------------------------ | ------------------------ |
| Simulator Availability | Development only         | Development only         |
| Endpoint               | `/webhook/stp/simulator` | `/webhook/opm/simulator` |
| Example CLABE          | `646180157000000001`     | `684180338000000186`     |

<Tip>
  STP and OPM simulators share the same actions and behavior; choose the one that matches your payment order's SPEI provider (STP vs OPM CLABE prefix).
</Tip>

## Complete Test Flow Example

Here's a complete example testing a payment failure and retry:

<Steps>
  <Step title="Create Payment">
    ```bash theme={null}
    curl -X POST https://api.sandbox.cheqpay.mx/pos/v2/payment-orders \
      -H "x-api-key: YOUR_API_KEY" \
      -H "x-merchant-id: YOUR_MERCHANT_ID" \
      -d '{"paymentMethod": {"type": "SPEI", ...}}'
    ```

    Payment status: `PENDING_CAPTURE`
  </Step>

  <Step title="Simulate Failure">
    ```bash theme={null}
    curl -X POST https://api.sandbox.cheqpay.mx/ps/webhook/stp/simulator \
      -d '{"clabe": "646180157000000001", "action": "fail"}'
    ```

    Payment status: `FAILED`

    Your webhook receives: `payment.auth.failed`
  </Step>

  <Step title="Customer Retries">
    Create a new payment with the same CLABE

    Payment status: `PENDING_CAPTURE`
  </Step>

  <Step title="Simulate Success">
    ```bash theme={null}
    curl -X POST https://api.sandbox.cheqpay.mx/ps/webhook/stp/simulator \
      -d '{"clabe": "646180157000000001", "action": "pass"}'
    ```

    Payment status: `CAPTURED`

    Your webhook receives: `payment.capture.success`
  </Step>
</Steps>

## Best Practices

<AccordionGroup>
  <Accordion title="Test Both Success and Failure" icon="check">
    Always test both `pass` and `fail` scenarios to ensure your error handling works correctly.
  </Accordion>

  <Accordion title="Use Unique CLABEs" icon="hashtag">
    Use different CLABEs for different test scenarios to avoid confusion.
  </Accordion>

  <Accordion title="Test Webhook Handling" icon="webhook">
    Verify your webhook endpoint correctly processes all payment status changes.
  </Accordion>

  <Accordion title="Test Idempotency" icon="copy">
    Trigger the simulator multiple times with the same CLABE to test duplicate webhook handling.
  </Accordion>
</AccordionGroup>

## Common Testing Scenarios

### Scenario 1: Successful Payment Flow

Test the happy path from payment creation to capture:

```bash theme={null}
# 1. Create payment
curl -X POST .../v2/payment-orders -d '{...}'

# 2. Simulate successful deposit
curl -X POST .../webhook/stp/simulator -d '{"action": "pass", ...}'

# 3. Verify webhook received
# 4. Verify order fulfilled in your system
```

### Scenario 2: Payment Failure

Test error handling when deposits fail:

```bash theme={null}
# 1. Create payment
curl -X POST .../v2/payment-orders -d '{...}'

# 2. Simulate failed deposit
curl -X POST .../webhook/stp/simulator -d '{"action": "fail", ...}'

# 3. Verify failure webhook received
# 4. Verify customer notified in your system
```

### Scenario 3: Refund Flow

Test complete refund processing:

```bash theme={null}
# 1. Create and capture payment (action: "pass")
# 2. Request refund
curl -X POST .../v2/payment-orders/{id}/refund -d '{...}'

# 3. Simulate refund success
curl -X POST .../webhook/stp/simulator -d '{"action": "refund-pass", ...}'

# 4. Verify refund webhook received
# 5. Verify customer refund processed
```

## Limitations

<Warning>
  The simulator has some limitations compared to production:

  * **No signature verification**: Simulator doesn't validate webhook secrets
  * **Development only**: STP, OPM, PayCash, and CIE Cash Net simulators only work in the development environment
  * **Instant processing**: Real bank transfers can take hours; simulator is instant
  * **No reconciliation events**: Internal reconciliation webhooks aren't triggered
</Warning>

## Next Steps

<CardGroup cols={2}>
  <Card title="Webhooks Guide" icon="webhook" href="/features/webhooks">
    Learn how to handle production webhooks
  </Card>

  <Card title="SPEI Payments" icon="building-columns" href="/features/spei-transfers">
    Understand SPEI payment flows
  </Card>

  <Card title="PayCash Payments" icon="money-bill" href="/features/paycash-payments">
    Understand PayCash payment flows
  </Card>

  <Card title="CIE Cash Net Payments" icon="building-columns" href="/features/cie-cash-net-payments">
    Understand CIE Cash Net payment flows
  </Card>

  <Card title="Testing Guide" icon="flask" href="/guides/testing">
    Complete testing best practices
  </Card>

  <Card title="Error Handling" icon="triangle-exclamation" href="/guides/error-handling">
    Handle payment failures gracefully
  </Card>
</CardGroup>
