Skip to content
Create account
or
Sign in
The Stripe Docs logo
/
Ask AI
Create account
Sign in
Get started
Payments
Finance automation
Platforms and marketplaces
Money management
Developer tools
Get started
Payments
Finance automation
Get started
Payments
Finance automation
Platforms and marketplaces
Money management
Overview
Versioning
Changelog
Upgrade your API version
Upgrade your SDK version
Developer tools
SDKs
API
    API v2
    API keys
    Stripe-Context header
    Daily changelog
    Rate limits
    Automated testing
    Metadata
    Expanding responses
    Pagination
    Domains and IP addresses
    Search
    Localisation
    Error handling
      Advanced error handling
    Error codes
Testing
Workbench
Event Destinations
Workflows
Stripe CLI
Stripe Shell
Developers Dashboard
Agent toolkit
Stripe health alertsBuild with LLMsStripe for Visual Studio CodeFile uploads
Security
Security
Extend Stripe
Stripe Apps
Stripe Connectors
Partners
Partner ecosystem
Partner certification
HomeDeveloper toolsAPI

Error handling

Catch and respond to declines, invalid data, network problems, and more.

Copy page

Stripe offers many kinds of errors. They can reflect external events, like declined payments and network interruptions, or code problems, like invalid API calls.

To handle errors, use some or all of the techniques in the table below. No matter what technique you use, you can follow up with our recommended responses for each error type.

TechniquePurposeWhen needed
Catch exceptionsRecover when an API call can’t continueAlways
Monitor webhooksReact to notifications from StripeSometimes
Get stored information about failuresInvestigate past problems and support other techniquesSometimes

Catch exceptions

Errors and HTTP

With this library, you don’t need to check for non-200 HTTP responses. The library translates them as exceptions.

In the rare event you need HTTP details, see Low-level exception handling and the Error object.

If an immediate problem prevents an API call from continuing, the Stripe Ruby library raises an exception. It’s a best practice to catch and handle exceptions.

To catch an exception, use Ruby’s rescue keyword. Catch Stripe::StripeError or its subclasses to handle Stripe-specific exceptions only. Each subclass represents a different kind of exception. When you catch an exception, you can use its class to choose a response.

Ruby
require 'stripe' Stripe.api_key =
'sk_test_BQokikJOvBiI2HlWgH4olfQ2'
def example_function(params) begin Stripe::PaymentIntent.create(params) rescue Stripe::CardError => e puts "A payment error occurred: #{e.error.message}" rescue Stripe::InvalidRequestError => e puts "An invalid request occurred." rescue Stripe::StripeError => e puts "Another problem occurred, maybe unrelated to Stripe." else puts "No error." end end

After setting up exception handling, test it on a variety of data, including test cards, to simulate different payment outcomes.

Ruby
example_function( # The required parameter currency is missing, amount: 2000, confirm: true, payment_method:
'pm_card_visa'
, )
console
Ruby
An invalid request occurred.

Monitor webhooks

Stripe notifies you about many kinds of problems using webhooks. This includes problems that don’t follow immediately after an API call. For example:

  • You lose a dispute.
  • A recurring payment fails after months of success.
  • Your front end confirms a payment, but goes offline before finding out the payment fails. (The back end still receives webhook notification, even though it wasn’t the one to make the API call.)

You don’t need to handle every webhook event type. In fact, some integrations don’t handle any.

In your webhook handler, start with the basic steps from the webhook builder: get an event object and use the event type to find out what happened. Then, if the event type indicates an error, follow these extra steps:

  1. Access event.data.object to retrieve the affected object.
  2. Use stored information on the affected object to gain context, including an error object.
  3. Use its type to choose a response.
Ruby
require 'stripe' require 'sinatra' post '/webhook' do payload = request.body.read data = JSON.parse(payload, symbolize_names: true) # Get the event object event = Stripe::Event.construct_from(data) # Use the event type to find out what happened case event.type when 'payment_intent.payment_failed' # Get the object affected payment_intent = event.data.object # Use stored information to get an error object e = payment_intent.last_payment_error # Use its type to choose a response case e.type when 'card_error' puts "A payment error occurred: #{e.message}" when 'invalid_request' puts "An invalid request occurred." else puts "Another problem occurred, maybe unrelated to Stripe." end end content_type 'application/json' { status: 'success' }.to_json end

To test how your integration responds to webhook events, you can trigger webhook events locally. After completing the setup steps at that link, trigger a failed payment to see the resulting error message.

Command Line
stripe trigger payment_intent.payment_failed
Output
A payment error occurred: Your card was declined.

Get stored information about failures

Many objects store information about failures. That means that if something already went wrong, you can retrieve the object and examine it to learn more. In many cases, stored information is in the form of an error object, and you can use its type to choose a response.

For instance:

  1. Retrieve a specific payment intent.
  2. Check if it experienced a payment error by determining if last_payment_error is empty.
  3. If it did, log the error, including its type and the affected object.
Ruby
require 'stripe' Stripe.api_key =
'sk_test_BQokikJOvBiI2HlWgH4olfQ2'
payment_intent = Stripe::PaymentIntent.retrieve(
'{{PAYMENT_INTENT_ID}}'
) e = payment_intent.last_payment_error if !e.nil? puts "PaymentIntent #{payment_intent.id} experienced a #{e.type}." end

Here are common objects that store information about failures.

ObjectAttributeValues
Payment Intentlast_payment_errorAn error object
Setup Intentlast_setup_errorAn error object
Invoicelast_finalization_errorAn error object
Setup Attemptsetup_errorAn error object
Payoutfailure_codeA payout failure code
Refundfailure_reasonA refund failure code

To test code that uses stored information about failures, you often need to simulate failed transactions. You can often do this using test cards or test bank numbers. For example:

  • Simulate a declined payment, for creating failed Charges, PaymentIntents, SetupIntents, and so on.
  • Simulate a failed payout.
  • Simulate a failed refund.

Types of error and responses

In the Stripe Ruby library, error objects belong to stripe.error.StripeError and its subclasses. Use the documentation for each class for advice on responding.

Name

Class

Description
Payment error

Stripe::CardError

An error occurred during a payment, involving one of these situations:
  • Payment blocked for suspected fraud
  • Payment declined by the issuer.
  • Other payment errors.
Invalid request error

Stripe::InvalidRequestError

You made an API call with the wrong parameters, in the wrong state, or in an invalid way.

Connection error

Stripe::APIConnectionError

There was a network problem between your server and Stripe.
API error

Stripe::APIError

Something went wrong on Stripe’s end. (These are rare.)
Authentication error

Stripe::AuthenticationError

Stripe can’t authenticate you with the information provided.
Idempotency error

Stripe::IdempotencyError

You used an idempotency key for something unexpected, like replaying a request but passing different parameters.
Permission error

Stripe::PermissionError

The API key used for this request does not have the necessary permissions.
Rate limit error

Stripe::RateLimitError

You made too many API calls in too short a time.
Signature verification error

Stripe::SignatureVerificationError

You’re using webhook signature verification and couldn’t verify that a webhook event is authentic.

Payment errors

Non-card payment errors

Everything in this section also applies to non-card payments. For historical reasons, payment errors have the type Stripe::CardError. But in fact, they can represent a problem with any payment, regardless of the payment method.

Payment errors—sometimes called “card errors” for historical reasons—cover a wide range of common problems. They come in three categories:

  • Payment blocked for suspected fraud
  • Payment declined by the issuer
  • Other payment errors

To distinguish these categories or get more information about how to respond, consult the error code, decline code, and charge outcome.

(To find the charge outcome from an error object, first get the Payment Intent that’s involved and the latest Charge it created. See the example below for a demonstration.)

Ruby
require 'stripe' Stripe.api_key =
'sk_test_BQokikJOvBiI2HlWgH4olfQ2'
def example_function(params) begin Stripe::PaymentIntent.create(params) rescue Stripe::CardError => e charge = Stripe::Charge.retrieve(e.error.payment_intent.latest_charge) if charge.outcome.type == 'blocked' puts 'Payment blocked for suspected fraud.' elsif e.code == 'card_declined' puts 'Payment declined by the issuer.' elsif e.code == 'expired_card' puts 'Card expired.' else puts 'Other card error.' end end end

Users on API version 2022-08-01 or older:

(To find the charge outcome from an error object, first get the Payment Intent that’s involved and the latest Charge it created. See the example below for a demonstration.)

Ruby
require 'stripe' Stripe.api_key =
'sk_test_BQokikJOvBiI2HlWgH4olfQ2'
def example_function(params) begin Stripe::PaymentIntent.create(params) rescue Stripe::CardError => e if e.error.payment_intent.charges.data[0].outcome.type == 'blocked' puts 'Payment blocked for suspected fraud.' elsif e.code == 'card_declined' puts 'Payment declined by the issuer.' elsif e.code == 'expired_card' puts 'Card expired.' else puts 'Other card error.' end end end

You can trigger some common kinds of payment error with test cards. Consult these lists for options:

  • Simulating payments blocked for fraud risk
  • Simulating declined payments and other card errors

The test code below demonstrates a few possibilities.

Ruby
example_function( currency: 'usd', amount: 2000, confirm: true, payment_method:
'pm_card_radarBlock'
, )
console
Ruby
Payment blocked for suspected fraud.

Payment blocked for suspected fraud

Type

Stripe::CardError

Codes
charge = Stripe::Charge.retrieve(e.error.payment_intent.latest_charge) charge.outcome.type == 'blocked'
Codes

e.error.payment_intent.charges.data[0].outcome.type == 'blocked'

ProblemStripe’s fraud prevention system, Radar, blocked the payment

Solutions

This error can occur when your integration is working correctly. Catch it and prompt the customer for a different payment method.

To block fewer legitimate payments, try these:

  • Optimise your Radar integration to collect more detailed information.
  • Use Payment Links, Checkout, or Stripe Elements for pre-built optimised form elements.

Radar for Fraud Teams customers have these additional options:

  • To exempt a specific payment, add it to your allowlist. Radar for Fraud Teams
  • To change your risk tolerance, adjust your risk settings. Radar for Fraud Teams
  • To change the criteria for blocking a payment, use custom rules. Radar for Fraud Teams

You can test your integration’s settings with test cards that simulate fraud. If you have custom Radar rules, follow the testing advice in the Radar documentation.

Payment declined by the issuer

Type

Stripe::CardError

Codes

e.error.code == "card_declined"

ProblemThe card issuer declined the payment.

Solutions

This error can occur when your integration is working correctly. It reflects an action by the issuer, and that action might be legitimate. Use the decline code to determine what next steps are appropriate. See the documentation on decline codes for appropriate responses to each code.

You can also:

  • Follow recommendations to reduce issuer declines.
  • Use Payment Links, Checkout, or Stripe Elements for pre-built form elements that implement those recommendations.

Test how your integration handles declines with test cards that simulate successful and declined payments.

Other payment errors

Type

Stripe::CardError

ProblemAnother payment error occurred.
SolutionsThis error can occur when your integration is working correctly. Use the error code to determine what next steps are appropriate. See the documentation on error codes for appropriate responses to each code.

Invalid request errors

Type

Stripe::InvalidRequestError

ProblemYou made an API call with the wrong parameters, in the wrong state, or in an invalid way.
SolutionsIn most cases, the problem is with the request itself. Either its parameters are invalid or it can’t be carried out in your integration’s current state.
  • Consult the error code documentation for details on the problem.
  • For convenience, you can follow the link at for documentation about the error code.
  • If the error involves a specific parameter, use to determine which one.

Connection errors

Type

Stripe::APIConnectionError

ProblemThere was a network problem between your server and Stripe.

Solutions

Treat the result of the API call as indeterminate. That is, don’t assume that it succeeded or that it failed.

To find out if it succeeded, you can:

  • Retrieve the relevant object from Stripe and check its status.
  • Listen for webhook notification that the operation succeeded or failed.

To help recover from connection errors, you can:

  • When creating or updating an object, use an idempotency key. Then, if a connection error occurs, you can safely repeat the request without risk of creating a second object or performing the update twice. Repeat the request with the same idempotency key until you receive a clear success or failure. For advanced advice on this strategy, see Low-level error handling.
  • Turn on automatic retries. Then, Stripe generates idempotency keys for you, and repeats requests for you when it is safe to do so.

This error can mask others. It’s possible that when the connection error resolves, some other error becomes apparent. Check for errors in all of these solutions just as you would in the original request.

API errors

Type

Stripe::APIError

ProblemSomething went wrong on Stripe’s end. (These are rare.)

Solutions

Treat the result of the API call as indeterminate. That is, don’t assume that it succeeded or that it failed.

Rely on webhooks for information about the outcome. Whenever possible, Stripe fires webhooks for any new objects we create as we solve a problem.

To set your integration up for maximum robustness in unusual situations, see this advanced discussion of server errors.

Authentication errors

Type

Stripe::AuthenticationError

ProblemStripe can’t authenticate you with the information provided.
Solutions
  • Use the correct API key.
  • Make sure you aren’t using a key that you “rotated” or revoked.

Idempotency errors

Type

Stripe::IdempotencyError

ProblemYou used an idempotency key for something unexpected, like replaying a request but passing different parameters.
Solutions
  • After you use an idempotency key, only reuse it for identical API calls.
  • Use idempotency keys under the limit of 255 characters.

Permission errors

Type

Stripe::PermissionError

ProblemThe API key used for this request doesn’t have the necessary permissions.
Solutions
  • Make sure you aren’t using a restricted API key for a service it doesn’t have access to.
  • Don’t perform actions in the Dashboard while logged in as a user role that lacks permission.

Rate limit errors

Type

Stripe::RateLimitError

ProblemYou made too many API calls in too short a time.
Solutions
  • If a single API call triggers this error, wait and try it again.
  • To handle rate-limiting automatically, retry the API call after a delay, and increase the delay exponentially if the error continues. See the documentation on rate limits for further advice.
  • If you anticipate a large increase in traffic and want to request an increased rate limit, contact support in advance.

Signature verification errors

Type

Stripe::SignatureVerificationError

ProblemYou’re using webhook signature verification and couldn’t verify that a webhook event is authentic.

Solutions

This error can occur when your integration is working correctly. If you use webhook signature verification and a third party attempts to send you a fake or malicious webhook, then verification fails and this error is the result. Catch it and respond with a 400 Bad Request status code.

If you receive this error when you shouldn’t – for instance, with webhooks that you know originate with Stripe –then see the documentation on checking webhook signatures for further advice. In particular, make sure you’re using the correct endpoint secret. This is different from your API key.

Was this page helpful?
YesNo
Need help? Contact Support.
Join our early access programme.
Check out our changelog.
Questions? Contact Sales.
LLM? Read llms.txt.
Powered by Markdoc