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.
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: Development environment only
Request Body:
{
"clabe" : "684180338000000186" ,
"action" : "pass"
}
PayCash Simulator
POST /ps/webhook/paycash/simulator
Content-Type : application/json
Availability: Development environment only
Request Body:
{
"reference" : "7041621293386809" ,
"action" : "pass"
}
Field Description referencepaymentMethod.paycashDetails.reference from the payment order responseactionpass (capture) or fail (simulated capture failure)
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.
CIE Cash Net Simulator
POST /ps/webhook/cie-cash-net/simulator
Content-Type : application/json
Availability: Development environment only
Request Body:
{
"reference" : "01234567" ,
"action" : "pass"
}
Field Description referencepaymentMethod.cieDetails.reference from the payment order responseactionpass (capture) or fail (simulated capture failure)
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.
Available Actions
Payment Capture
Action Description Payment Status passSimulates successful deposit CAPTUREDfailSimulates deposit with wrong amount FAILED
Refunds (SPEI only)
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 PayCash Capture
Step 1: Create a PayCash Payment Order
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_paycash_123",
"customer": {
"firstName": "Laura",
"lastName": "Ramirez",
"email": "laura@example.com"
},
"amount": 10000,
"currency": "MXN",
"description": "PayCash test payment",
"paymentMethod": {
"type": "paycash"
}
}'
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.
Response:
{
"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"
}
}
}
Save the reference from paymentMethod.paycashDetails.reference. You’ll need it to trigger the simulator.
Step 2: Simulate Successful Deposit
curl -X POST https://api.cheqpay.dev/ps/webhook/paycash/simulator \
-H "Content-Type: application/json" \
-d '{
"reference": "7041621293386809",
"action": "pass"
}'
Response:
{
"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:
{
"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"
}
}
You may receive payment.auth.pending earlier while the payment is still PENDING_CAPTURE. Fulfill the order only after payment.capture.success.
Testing CIE Cash Net Capture
Step 1: Create a CIE Cash Net Payment Order
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_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:
{
"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"
}
}
}
Save the reference from paymentMethod.cieDetails.reference. You’ll need it to trigger the simulator.
Step 2: Simulate Successful Reconciliation
curl -X POST https://api.cheqpay.dev/ps/webhook/cie-cash-net/simulator \
-H "Content-Type: application/json" \
-d '{
"reference": "01234567",
"action": "pass"
}'
Response:
{
"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:
{
"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:
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 Development only Endpoint /webhook/stp/simulator/webhook/opm/simulatorExample CLABE 646180157000000001684180338000000186
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).
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, 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
Next Steps
Webhooks Guide Learn how to handle production webhooks
SPEI Payments Understand SPEI payment flows
PayCash Payments Understand PayCash payment flows
CIE Cash Net Payments Understand CIE Cash Net payment flows
Testing Guide Complete testing best practices
Error Handling Handle payment failures gracefully