Skip to main content

Overview

Webhook simulators let you test SPEI payment flows in your development and staging environments without making actual bank transfers. This accelerates development and lets you test both success and failure scenarios.

No Real Transfers

Test without moving real money

Instant Feedback

No waiting for actual bank processing

Test Failures

Simulate failed payments and refunds

Full Webhooks

Receive the same webhooks as production

How It Works

1

Create SPEI Payment

Create a SPEI payment using the payments API. The payment will be in PENDING_CAPTURE status with a CLABE assigned.
2

Trigger Simulator

Call the simulator endpoint with the CLABE and desired action (pass or fail).
3

Receive Webhook

Your webhook endpoint receives the same payment status change webhook as production.

Available Simulators

STP Simulator

POST /ps/webhook/stp/simulator
Content-Type: application/json
Availability: Development environment only Request Body:
{
  "clabe": "646180157000000001",
  "action": "pass"
}

OPM Simulator

POST /ps/webhook/opm/simulator
Content-Type: application/json
Availability: All environments Request Body:
{
  "clabe": "684180338000000186",
  "action": "pass"
}

Available Actions

Payment Capture

ActionDescriptionPayment Status
passSimulates successful depositCAPTURED
failSimulates deposit with wrong amountFAILED

Refunds

ActionDescriptionPayment Status
refund-passSimulates successful refundREFUNDED
refund-failSimulates failed refundPENDING_REFUND (unchanged)

Testing Payment Capture

Step 1: Create a SPEI Payment

curl -X POST https://api.cheqpay.dev/pos/v2/payment-orders \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -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:
{
  "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"
    }
  }
}
Save the CLABE from paymentMethod.speiDetails.clabe. You’ll need it to trigger the simulator.

Step 2: Simulate Successful Deposit

curl -X POST https://api.cheqpay.dev/ps/webhook/stp/simulator \
  -H "Content-Type: application/json" \
  -d '{
    "clabe": "646180157000000001",
    "action": "pass"
  }'
Response:
{
  "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:
{
  "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 Failed Payments

Simulate a failed payment to test error handling:
curl -X POST https://api.cheqpay.dev/ps/webhook/stp/simulator \
  -H "Content-Type: application/json" \
  -d '{
    "clabe": "646180157000000001",
    "action": "fail"
  }'
Your webhook will receive a payment.capture.failed event with the payment status as FAILED.
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.

Testing Refunds

Step 1: Request a Refund

First, create a refund for a captured payment:
curl -X POST https://api.cheqpay.dev/pos/v2/payment-orders/{id}/refund \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": "10000",
    "reason": "Customer requested refund"
  }'
The payment status changes to PENDING_REFUND.

Step 2: Simulate Refund Processing

curl -X POST https://api.cheqpay.dev/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:
{
  "success": false,
  "message": "No pending payment found for CLABE 646180157000000001"
}

STP vs OPM Differences

FeatureSTPOPM
Simulator AvailabilityDevelopment onlyAll environments
Endpoint/webhook/stp/simulator/webhook/opm/simulator
Example CLABE646180157000000001684180338000000186
Use OPM simulator if you need to test in staging or production-like environments, as it’s available in all environments.

Complete Test Flow Example

Here’s a complete example testing a payment failure and retry:
1

Create Payment

curl -X POST https://api.cheqpay.dev/pos/v2/payment-orders \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{"paymentMethod": {"type": "SPEI", ...}}'
Payment status: PENDING_CAPTURE
2

Simulate Failure

curl -X POST https://api.cheqpay.dev/ps/webhook/stp/simulator \
  -d '{"clabe": "646180157000000001", "action": "fail"}'
Payment status: FAILEDYour webhook receives: payment.capture.failed
3

Customer Retries

Create a new payment with the same CLABEPayment status: PENDING_CAPTURE
4

Simulate Success

curl -X POST https://api.cheqpay.dev/ps/webhook/stp/simulator \
  -d '{"clabe": "646180157000000001", "action": "pass"}'
Payment status: CAPTUREDYour webhook receives: payment.capture.success

Best Practices

Always test both pass and fail scenarios to ensure your error handling works correctly.
Use different CLABEs for different test scenarios to avoid confusion.
Verify your webhook endpoint correctly processes all payment status changes.
Trigger the simulator multiple times with the same CLABE to test duplicate webhook handling.

Common Testing Scenarios

Scenario 1: Successful Payment Flow

Test the happy path from payment creation to capture:
# 1. Create payment
curl -X POST .../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:
# 1. Create payment
curl -X POST .../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:
# 1. Create and capture payment (action: "pass")
# 2. Request refund
curl -X POST .../payments/{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

The simulator has some limitations compared to production:
  • No signature verification: Simulator doesn’t validate webhook secrets
  • Development only (STP): STP simulator only works in development environment
  • Instant processing: Real bank transfers can take hours; simulator is instant
  • No reconciliation events: Internal reconciliation webhooks aren’t triggered

Next Steps