Skip to content

API Errors Fresh

Stripe uses conventional HTTP status codes and structured error objects. Handle errors by checking the error type, then the code or decline_code for specifics.

HTTP status codes

CodeStatusMeaning
200OKRequest succeeded
400Bad RequestMissing or invalid parameter
401UnauthorizedNo valid API key provided
402Request FailedParameters valid, but request failed (e.g., card declined)
403ForbiddenAPI key lacks permission for this operation
404Not FoundRequested resource doesn't exist
409ConflictRequest conflicts with another (e.g., duplicate idempotency key)
424External Dependency FailedExternal dependency (issuer, bank) failed
429Too Many RequestsRate limit exceeded — use exponential backoff
500, 502, 503, 504Server ErrorsSomething wrong on Stripe's end (rare)

Error types

TypeDescription
api_errorTemporary problem with Stripe's servers — extremely uncommon
card_errorCard was declined or had an issue — most common type to handle
idempotency_errorIdempotency key reused with different request parameters
invalid_request_errorRequest had invalid parameters (missing required field, wrong type, etc.)

Error object attributes

json
{
  "error": {
    "type": "card_error",
    "code": "card_declined",
    "decline_code": "insufficient_funds",
    "message": "Your card has insufficient funds.",
    "param": null,
    "charge": "ch_3Nxxx",
    "payment_intent": { ... },
    "doc_url": "https://stripe.com/docs/error-codes/card-declined"
  }
}
AttributeTypeDescription
typestringOne of: api_error, card_error, idempotency_error, invalid_request_error
codestringShort code identifying the error (e.g., card_declined, missing)
decline_codestringCard issuer's reason for decline (card errors only)
messagestringHuman-readable description — safe to show customers for card_error type
paramstringThe parameter that caused the error (for invalid_request_error)
chargestringID of the failed charge (card errors only)
payment_intentobjectThe PaymentIntent that caused the error (if applicable)
payment_methodobjectThe PaymentMethod that caused the error (if applicable)
setup_intentobjectThe SetupIntent that caused the error (if applicable)
advice_codestringSuggested next steps from the card issuer
network_advice_codestringTwo-digit code from the card network
network_decline_codestringAlphanumeric code from the network for declined payments
request_log_urlstringURL to the request log in Dashboard
doc_urlstringURL to error code documentation

Common error codes

Card errors (type: "card_error")

CodeMeaning
card_declinedCard was declined — check decline_code for the specific reason
expired_cardCard has expired
incorrect_cvcCVC number is incorrect
incorrect_numberCard number is incorrect
insufficient_fundsInsufficient funds
invalid_expiry_monthInvalid expiry month
invalid_expiry_yearInvalid expiry year

Invalid request errors (type: "invalid_request_error")

CodeMeaning
missingRequired parameter is missing
parameter_invalid_emptyParameter is empty but required
parameter_invalid_integerExpected an integer
parameter_invalid_string_blankValue must not be blank
resource_missingResource (customer, card, etc.) not found
idempotency_key_in_useIdempotency key currently in use
amount_too_smallAmount is below minimum charge amount
amount_too_largeAmount exceeds maximum charge amount
currency_not_supportedCurrency not supported for this account
invalid_charge_amountAmount is invalid

Error handling pattern

javascript
const stripe = require('stripe')('sk_test_YOUR_KEY');

async function createCharge(amount, currency, paymentMethodId) {
  try {
    const paymentIntent = await stripe.paymentIntents.create({
      amount,
      currency,
      payment_method: paymentMethodId,
      confirm: true,
    });
    return { success: true, paymentIntent };
  } catch (err) {
    switch (err.type) {
      case 'StripeCardError':
        // Safe to show card error messages to the customer
        return {
          success: false,
          message: err.message,
          decline_code: err.decline_code,
        };

      case 'StripeInvalidRequestError':
        // Bad API call — log internally, don't expose to user
        console.error('Invalid request:', err.message, 'param:', err.param);
        return { success: false, message: 'An error occurred. Please try again.' };

      case 'StripeAPIError':
        // Stripe server error — retry with backoff
        console.error('Stripe API error:', err.message);
        return { success: false, message: 'Temporarily unavailable. Please try again.' };

      case 'StripeConnectionError':
        // Network error — retry
        return { success: false, message: 'Network error. Please try again.' };

      case 'StripeAuthenticationError':
        // Bad API key — alert your team
        console.error('Authentication error — check API key');
        return { success: false, message: 'Configuration error.' };

      default:
        console.error('Unexpected error:', err);
        return { success: false, message: 'An unexpected error occurred.' };
    }
  }
}

Idempotency

Use idempotency keys to safely retry requests without creating duplicate charges:

bash
curl https://api.stripe.com/v1/payment_intents \
  -u "sk_test_YOUR_KEY:" \
  -H "Idempotency-Key: your-unique-key-per-request" \
  -d amount=1000 \
  -d currency=usd
  • Generate a unique key per logical operation (e.g., UUID)
  • Reuse the same key to safely retry the same request
  • Stripe returns the cached result for up to 24 hours
  • Keys are scoped per API key

Rate limit handling

javascript
async function retryWithBackoff(fn, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await fn();
    } catch (err) {
      if (err.statusCode === 429 && attempt < maxRetries - 1) {
        const delay = Math.pow(2, attempt) * 1000; // 1s, 2s, 4s
        await new Promise(resolve => setTimeout(resolve, delay));
      } else {
        throw err;
      }
    }
  }
}

Stripe API Reference - Self-contained docs reference, refreshed 2026-05-18