The Stripe Payments API implements a consistent error handling system that provides meaningful error messages and appropriate HTTP status codes.
All error responses follow a consistent structure:
{
"status" : false ,
"message" : "Error description" ,
"code" : "ERROR_CODE"
}
Response Fields:
status: Always false for errors
message: Human-readable error description
code: Optional error code (e.g., Stripe error codes)
In development mode (NODE_ENV !== 'production'), error responses include a stack field with the full stack trace.
Error Handling Implementation
The API uses a centralized error handling system built on three components:
1. ApiError Class
Custom error class for operational errors:
class ApiError extends Error {
constructor ( statusCode , message , isOperational = true , stack = '' ) {
super ( message );
this . statusCode = statusCode ;
this . isOperational = isOperational ;
if ( stack ) {
this . stack = stack ;
} else {
Error . captureStackTrace ( this , this . constructor );
}
}
}
Usage in Controllers:
if ( ! email || ! name || ! phone ) {
throw new ApiError ( 400 , 'email, name y phone son requeridos' );
}
2. catchAsync Middleware
Wrapper function that catches async errors and passes them to error handlers:
export const catchAsync = ( fn ) => ( req , res , next ) => {
fn ( req , res , next ). catch ( next );
};
Usage:
router . post ( '/customers' , catchAsync ( createCustomer ));
This eliminates the need for try-catch blocks in every controller.
3. Global Error Middleware
Centralized error handler that formats all errors:
export const apiError = ( err , req , res , next ) => {
const statusCode = err . statusCode || err . raw ?. statusCode || 500 ;
const message = err . message || 'Internal Server Error' ;
const payload = {
status: false ,
message ,
};
if ( err . code ) {
payload . code = err . code ;
}
if ( process . env . NODE_ENV !== 'production' ) {
payload . stack = err . stack ;
}
res . status ( statusCode ). json ( payload );
};
HTTP Status Codes
The API uses standard HTTP status codes:
Status Code Meaning When Used 200 OK Successful GET, PUT, PATCH requests 201 Created Successful POST requests (resource created) 400 Bad Request Missing required fields, invalid input 404 Not Found Resource or route not found 500 Internal Server Error Unexpected server errors
Common Error Scenarios
Missing Required Fields
Request:
curl -X POST http://localhost:3000/api/customers \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected] "
}'
Response (400):
{
"status" : false ,
"message" : "email, name y phone son requeridos"
}
Invalid Payment Intent ID
Request:
curl -X POST http://localhost:3000/api/payments/confirm \
-H "Content-Type: application/json" \
-d '{}'
Response (400):
{
"status" : false ,
"message" : "paymentId es requerido"
}
Invalid Card Token
Request:
curl -X POST http://localhost:3000/api/cards/assign \
-H "Content-Type: application/json" \
-d '{
"userId": "cus_invalid",
"source": "tok_invalid"
}'
Response (400-500):
{
"status" : false ,
"message" : "No such token: tok_invalid" ,
"code" : "resource_missing"
}
Route Not Found
Request:
curl http://localhost:3000/api/invalid-route
Response (404):
{
"status" : false ,
"message" : "Route not found: /api/invalid-route"
}
Invalid Refund Amount
Request:
curl -X POST http://localhost:3000/api/payments/refund \
-H "Content-Type: application/json" \
-d '{
"chargeId": "ch_xxxxx",
"amount": -10
}'
Response (400):
{
"status" : false ,
"message" : "amount debe ser un número mayor a 0"
}
Stripe Error Codes
When Stripe API calls fail, the error includes a Stripe error code:
Card Declined
Insufficient Funds
Expired Card
Invalid CVC
{
"status" : false ,
"message" : "Your card was declined" ,
"code" : "card_declined"
}
Common Stripe Error Codes
Code Description Action card_declinedCard was declined Ask customer to use different card insufficient_fundsInsufficient funds Request payment with different method expired_cardCard expired Request updated card details incorrect_cvcInvalid CVC Request correct CVC code processing_errorPayment processing error Retry the payment resource_missingResource not found Verify the ID is correct invalid_request_errorInvalid API request Check request parameters
Error Handling in Client Code
Here’s how to handle errors in your client application:
JavaScript/Node.js
Python
PHP
try {
const response = await fetch ( 'http://localhost:3000/api/payments' , {
method: 'POST' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON . stringify ({
customer_id: customerId ,
amount: 50.00 ,
payment_method: paymentMethod
})
});
const data = await response . json ();
if ( ! data . status ) {
// Handle error
console . error ( 'Payment failed:' , data . message );
// Check for specific error codes
if ( data . code === 'card_declined' ) {
alert ( 'Your card was declined. Please use a different card.' );
}
return ;
}
// Handle success
console . log ( 'Payment created:' , data . data );
} catch ( error ) {
// Handle network errors
console . error ( 'Network error:' , error );
}
Best Practices
Check Response Status Always check the status field in the response before processing data: if ( ! response . status ) {
// Handle error
}
Handle Specific Error Codes Use the code field to provide specific error messages to users: if ( data . code === 'card_declined' ) {
// Show user-friendly message
}
Log Errors for Debugging In development, use the stack trace for debugging: if ( process . env . NODE_ENV !== 'production' && data . stack ) {
console . error ( data . stack );
}
Retry Logic Implement retry logic for transient errors: if ( statusCode === 500 || statusCode === 503 ) {
// Retry with exponential backoff
}
Webhook Error Handling
Webhook endpoints have specific error handling:
Missing Signature
{
"status" : false ,
"message" : "Missing stripe-signature header"
}
Missing Webhook Secret
{
"status" : false ,
"message" : "Missing STRIPE_WEBHOOK_SECRET in environment variables"
}
Signature Verification Failed
{
"status" : false ,
"message" : "Webhook signature verification failed: No signatures found matching the expected signature for payload"
}
Always return a 200 status code for successfully received webhooks, even if your business logic fails. This prevents Stripe from retrying valid events.
Development vs Production
Development Mode
Includes full stack traces in error responses
More verbose error messages
Logs all errors to console
Example Response:
{
"status" : false ,
"message" : "email, name y phone son requeridos" ,
"stack" : "Error: email, name y phone son requeridos \n at createCustomer (...) \n at ..."
}
Production Mode
No stack traces in responses
Sanitized error messages
Errors logged to monitoring systems
Example Response:
{
"status" : false ,
"message" : "email, name y phone son requeridos"
}
Next Steps