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
Create SPEI Payment
Create a SPEI payment using the payments API. The payment will be in PENDING_CAPTURE status with a CLABE assigned.
Trigger Simulator
Call the simulator endpoint with the CLABE and desired action (pass or fail).
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
Action Description Payment Status passSimulates successful deposit CAPTUREDfailSimulates deposit with wrong amount FAILED
Refunds
Action Description Payment Status refund-passSimulates successful refund REFUNDEDrefund-failSimulates failed refund PENDING_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
Feature STP OPM Simulator Availability Development only All environments Endpoint /webhook/stp/simulator/webhook/opm/simulatorExample CLABE 646180157000000001684180338000000186
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:
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
Simulate Failure
curl -X POST https://api.cheqpay.dev/ps/webhook/stp/simulator \
-d '{"clabe": "646180157000000001", "action": "fail"}'
Payment status: FAILED Your webhook receives: payment.capture.failed
Customer Retries
Create a new payment with the same CLABE Payment status: PENDING_CAPTURE
Simulate Success
curl -X POST https://api.cheqpay.dev/ps/webhook/stp/simulator \
-d '{"clabe": "646180157000000001", "action": "pass"}'
Payment status: CAPTURED Your webhook receives: payment.capture.success
Best Practices
Test Both Success and Failure
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