Overview
The HTTP Endpoints provide essential web services including Stripe webhook processing for automatic order creation, health monitoring, and configuration retrieval for client applications.
Location: convex/http.ts
Stripe Webhook
Handles Stripe webhook events for automatic payment processing and order creation.
Stripe webhook signature header for verification
Supported Events
Payment Succeeded Event : payment_intent.succeeded
Action : Creates order from cart items
Payment Failed Event : payment_intent.payment_failed
Action : Logs failure and notifies customer
Payment Canceled Event : payment_intent.canceled
Action : Cleans up resources and preserves cart
Webhook Processing Flow
Signature Verification
Validates Stripe webhook signature for security
Event Parsing
Extracts payment data and metadata from webhook payload
Order Processing
Creates orders for successful payments or handles failures
Cart Cleanup
Removes items from customer cart after successful order creation
Notifications
Sends confirmation notifications to customers and stores
Webhook Handler
Webhook Setup
Test Webhook
// This runs automatically when Stripe sends webhook events
// Location: convex/http.ts
export default httpRouter ;
httpRouter . route ({
path: "/stripe/webhook" ,
method: "POST" ,
handler : async ( request : Request ) => {
const signature = request . headers . get ( "stripe-signature" );
const body = await request . text ();
try {
// Verify webhook signature
const event = stripe . webhooks . constructEvent (
body ,
signature ! ,
process . env . STRIPE_WEBHOOK_SECRET !
);
switch ( event . type ) {
case 'payment_intent.succeeded' :
// Automatic order creation
const paymentIntent = event . data . object ;
const metadata = paymentIntent . metadata ;
// Create order from cart
await convex . mutation ( "customers.cartToOrder.createOrderFromCart" , {
customerId: metadata . customerId ,
storeId: metadata . storeId ,
deliveryAddress: JSON . parse ( metadata . deliveryAddress ),
deliveryType: metadata . deliveryType ,
deliveryFee: parseFloat ( metadata . deliveryFee ),
paymentMethod: "card" ,
paymentIntentId: paymentIntent . id ,
paymentStatus: "paid"
});
break ;
case 'payment_intent.payment_failed' :
// Handle payment failure
console . error ( 'Payment failed:' , event . data . object );
break ;
case 'payment_intent.canceled' :
// Handle payment cancellation
console . log ( 'Payment canceled:' , event . data . object );
break ;
}
return new Response ( "Webhook processed" , { status: 200 });
} catch ( error ) {
console . error ( 'Webhook error:' , error );
return new Response ( "Webhook failed" , { status: 400 });
}
}
});
Health Check
Simple health check endpoint for monitoring and uptime verification.
cURL
TypeScript
JavaScript
Python
curl https://your-deployment.convex.cloud/health
Twigz Backend is healthy!
Stripe Configuration
Retrieve Stripe publishable key for client-side integration.
TypeScript
JavaScript
Python
cURL
const config = await fetch ( 'https://your-deployment.convex.cloud/stripe/config' );
const { publishableKey } = await config . json ();
// Use with Stripe.js
import { loadStripe } from '@stripe/stripe-js' ;
const stripe = await loadStripe ( publishableKey );
{
"publishableKey" : "pk_test_51234567890abcdef..."
}
Webhook Security
All webhooks are verified using Stripe’s signature verification: const signature = request . headers . get ( "stripe-signature" );
const event = stripe . webhooks . constructEvent (
body ,
signature ! ,
process . env . STRIPE_WEBHOOK_SECRET !
);
Webhook events are processed idempotently to handle retries: // Check if order already exists for this payment
const existingOrder = await convex . query ( "customers.orders.getOrderByPaymentIntent" , {
paymentIntentId: paymentIntent . id
});
if ( existingOrder ) {
return new Response ( "Order already processed" , { status: 200 });
}
Robust error handling for webhook processing: try {
await processWebhookEvent ( event );
return new Response ( "Success" , { status: 200 });
} catch ( error ) {
console . error ( 'Webhook processing failed:' , error );
// Return 500 to trigger Stripe retry
return new Response ( "Processing failed" , { status: 500 });
}
Webhook Testing
Stripe CLI Setup
Local Testing
# Install Stripe CLI
# macOS
brew install stripe/stripe-cli/stripe
# Login to Stripe
stripe login
# Forward webhooks to local development
stripe listen --forward-to localhost:3000/stripe/webhook
# In another terminal, trigger test events
stripe trigger payment_intent.succeeded
stripe trigger payment_intent.payment_failed
Monitoring & Observability
Health Monitoring Use the /health endpoint for uptime monitoring and load balancer health checks
Webhook Logs Monitor webhook processing in Convex logs for debugging payment issues
Error Tracking Failed webhooks are logged with full context for troubleshooting
Performance Metrics Track webhook processing times and success rates
CORS Configuration
The endpoints include proper CORS headers for web applications:
// CORS headers included in responses
const headers = {
'Content-Type' : 'application/json' ,
'Access-Control-Allow-Origin' : '*' ,
'Access-Control-Allow-Methods' : 'GET, POST, OPTIONS' ,
'Access-Control-Allow-Headers' : 'Content-Type, Authorization, stripe-signature'
};
Error Responses
Invalid webhook signature
Status Code : 400{
"error" : "Invalid webhook signature"
}
Unsupported webhook event
Status Code : 200 (Success, but ignored){
"message" : "Event type not supported" ,
"eventType" : "customer.created"
}
Webhook processing failed
Status Code : 500{
"error" : "Webhook processing failed" ,
"eventId" : "evt_123456789"
}
Status Code : 503{
"error" : "Service temporarily unavailable" ,
"retryAfter" : 30
}
Webhook endpoints are automatically secured and include signature verification. Failed webhook processing triggers Stripe’s automatic retry mechanism.
Use the Stripe CLI during development to test webhook integration locally. Always verify webhook signatures in production for security.