Payment API Monitoring
A broken payment endpoint costs you money from the first failed request. Assert checks your gateway and your own payment endpoints on the same schedule, and reads the response body instead of the status line.
The Problem
The gateway returns 200 and the transaction fails anyway. One card type stops working while every other method goes through. Your provider has an incident and your checkout inherits it. Or your own validation starts rejecting requests that were fine yesterday.
How Assert Helps
Monitor Payment Gateway Health
Check that your payment provider is operational:
Monitor: Stripe Health Check
URL: POST https://api.stripe.com/v1/payment_methods
Assertions:
✓ Status code == 200
✓ $.object == "payment_method"
✓ Response time < 2000ms
Validate Your Payment Integration
Then the endpoints you wrote yourself:
Monitor: Checkout Payment Validation
URL: POST /api/payments/validate
Body: {"amount": 100, "currency": "USD", "method": "card"}
Assertions:
✓ $.valid == true
✓ $.available_methods contains "card"
✓ $.min_amount <= 100
Check Webhook Endpoints
Verify your webhook handlers are responding:
Monitor: Payment Webhook Health
URL: POST /webhooks/stripe
Assertions:
✓ Status code == 200
✓ Response time < 500ms
Critical Assertions for Payment APIs
Transaction Creation
// Expected response from payment creation:
{
"id": "txn_abc123",
"status": "pending",
"amount": 9999,
"currency": "usd"
}
Assertions:
$.idmust exist$.statusmust be one of["pending", "succeeded", "processing"]$.amountmust equal expected amount$.currencymust equal expected currency
Payment Status
// Expected response from status check:
{
"status": "succeeded",
"paid": true,
"receipt_url": "https://..."
}
Assertions:
$.statusmust exist$.paidmust be boolean$.receipt_urlmust match URL pattern
Refund Processing
// Expected refund response:
{
"id": "re_xyz789",
"status": "succeeded",
"amount": 5000
}
Assertions:
$.statusmust equal "succeeded"$.amountmust be positive integer$.idmust start with "re_"
Real-World Example
The Scenario
A SaaS company bills subscriptions through Stripe. Some webhook deliveries never arrive, so the renewal never gets recorded, and the customer wakes up downgraded.
The Assert Solution
Monitor 1: Stripe Webhook Endpoint
URL: POST /webhooks/stripe
Headers:
Stripe-Signature: test_signature
Body: {"type": "test"}
Assertions:
✓ Status code == 200 or 400
✓ Response time < 1000ms
Monitor 2: Subscription Status API
URL: GET /api/subscriptions/health
Assertions:
✓ $.queue_size < 100
✓ $.last_processed within 5 minutes
✓ $.error_rate < 0.01
The Outcome
The endpoint monitor ran every minute while the health monitor watched the queue. Queue size crossed the threshold and Assert alerted once, with the failing response attached. The team traced it to a Redis connection issue and fixed it before a single renewal was missed. Both monitors are still running.
Payment Providers to Monitor
Stripe
| Endpoint | What to Monitor |
|---|---|
| Payment Intents | Transaction creation works |
| Payment Methods | Card tokenization succeeds |
| Webhooks | Events are delivered |
| Customers | Customer creation works |
PayPal
| Endpoint | What to Monitor |
|---|---|
| Orders | Order creation succeeds |
| Captures | Payment capture works |
| Refunds | Refund processing |
| Webhooks | Event delivery |
Your Payment Endpoints
| Endpoint | What to Monitor |
|---|---|
| POST /checkout | Cart to payment works |
| POST /payments | Payment processing |
| GET /payments/:id | Status retrieval |
| POST /refunds | Refund processing |
Best Practices
Use Test/Sandbox Endpoints
Most payment providers offer test endpoints:
Production: api.stripe.com
Sandbox: api.stripe.com (with test keys)
Monitor both. Sandbox tells you your integration still works; production tells you about the failures that only happen with live keys.
Monitor from Multiple Regions
Payment latency matters globally:
US East: Monitor latency to Stripe US
Europe: Monitor latency to Stripe EU
Asia: Monitor latency to Stripe APAC
Assert runs each check from six regions and needs them to agree before it alerts, so one slow route to Frankfurt doesn't wake anybody up.
Set Aggressive Alert Thresholds
For payment APIs, detect issues fast:
- Check interval: 30 seconds, which every plan allows
- Alert threshold: one or two failures, not three to five
- Response time: alert above 3 seconds
Create Payment-Specific Alerts
Route payment alerts to specialized channels:
Payment API Down → PagerDuty (immediate page)
Payment Slow → Slack #payments (warning)
Webhook Queue Growing → Email (monitor)
Test Edge Cases
Monitor for specific scenarios:
- Zero amount: free trials and $0 checkouts
- Large amounts: high-value transactions
- Currency handling: multi-currency support
- Declined cards: the error your customer actually sees
Alert Response Runbook
When payment alerts fire:
- Check the provider's status page. Is this Stripe's problem or yours?
- Check your logs for a deploy or an error spike in the last hour.
- Run a test payment by hand. Does it go through?
- Check the dependencies: database, Redis, webhook handlers.
- Open a ticket with the provider if it's on their side.
Getting Started
Start with the flows that move money: checkout, subscription renewal, refunds. Map the endpoints on both sides, yours and your provider's. Build the first monitor around transaction creation, assert on the fields in the response rather than the status code, and send it to PagerDuty. Everything else can go to Slack.
Related Use Cases
- E-commerce API Monitoring: the rest of the storefront
- Webhook Reliability: the endpoints your provider posts to