Skip to content
Create account
or
Sign in
The Stripe Docs logo
/
Ask AI
Create account
Sign in
Get started
Payments
Revenue
Platforms and marketplaces
Money management
Developer tools
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
    Localization
    Error handling
      Advanced error handling
    Error codes
Testing
Workbench
Event Destinations
Workflows
Stripe CLI
Stripe Shell
Developers Dashboard
Agent toolkit
Build with LLMsStripe for Visual Studio CodeStripe health alertsFile uploads
Security and privacy
Security
Privacy
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
Use error valuesRecover when an API call can’t continueAlways
Monitor webhooksReact to notifications from StripeSometimes
Get stored information about failuresInvestigate past problems and support other techniquesSometimes

Use error values

Errors and HTTP

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

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

API calls in the Stripe Go library return both a result value and an error value. Use multiple assignment to capture both. If the error value isn’t nil, it means an immediate problem prevented the API call from continuing.

If the error value is related to Stripe, you can cast it to a stripe.Error object, which has fields describing the problem. Use the Type field to choose a response. In some cases, you can coerce the Err property to a more specific error type with additional information.

Go
package main import ( "github.com/stripe/stripe-go/v72" "github.com/stripe/stripe-go/v72/paymentintent" "log" ) func example_function(params *stripe.PaymentIntentParams) { stripe.Key =
"sk_test_BQokikJOvBiI2HlWgH4olfQ2"
_, err := paymentintent.New(params) if err == nil { log.Println("No error.") } else { if stripeErr, ok := err.(*stripe.Error); ok { switch stripeErr.Type { case stripe.ErrorTypeCard: log.Println("A payment error occurred:", stripeErr.Msg) case stripe.ErrorTypeInvalidRequest: log.Println("An invalid request occurred.") default: log.Println("Another Stripe error occurred.") } } else { log.Println("An error occurred that was unrelated to Stripe.") } } }

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

Go
params := &stripe.PaymentIntentParams{ Amount: stripe.Int64(2000), // The required parameter currency is missing Confirm: stripe.Bool(true), PaymentMethod: stripe.String(
"pm_card_visa"
), } example_function(params)
console
Go
1749843298 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 frontend confirms a payment, but goes offline before finding out the payment fails. (The backend 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. Get the affected object by unmarshalling data from event.Data.Raw.
  2. Use stored information on the affected object to gain context, including an error object.
  3. Use its type to choose a response.
Go
package main import ( "encoding/json" "io/ioutil" "log" "net/http" "github.com/stripe/stripe-go/v72" "github.com/stripe/stripe-go/v72/webhook" ) func main() { http.HandleFunc("/webhook", handleWebhook) addr := "localhost:4242" log.Printf("Listening on %s", addr) log.Fatal(http.ListenAndServe(addr, nil)) } func handleWebhook(w http.ResponseWriter, req *http.Request) { const MaxBodyBytes = int64(65536) req.Body = http.MaxBytesReader(w, req.Body, MaxBodyBytes) payload, err := ioutil.ReadAll(req.Body) if err != nil { log.Printf("Error reading request body: %v\n", err) w.WriteHeader(http.StatusServiceUnavailable) return } // Replace this endpoint secret with your endpoint's unique secret // If you are testing with the CLI, find the secret by running 'stripe listen' // If you are using an endpoint defined with the API or dashboard, look in your webhook settings // at https://dashboard.stripe.com/webhooks endpointSecret := "whsec_..." signatureHeader := req.Header.Get("Stripe-Signature") // Get an event object event, err := webhook.ConstructEvent(payload, signatureHeader, endpointSecret) if err != nil { log.Printf("⚠️ Webhook signature verification failed. %v\n", err) w.WriteHeader(http.StatusBadRequest) // Return a 400 error on a bad signature return } // Use its type to find out what happened switch event.Type { case "payment_intent.payment_failed": // Get the object affected by unmarshalling event data into // the appropriate struct for the event type var paymentIntent stripe.PaymentIntent err := json.Unmarshal(event.Data.Raw, &paymentIntent) if err != nil { log.Printf("Error parsing webhook JSON: %v\n", err) w.WriteHeader(http.StatusBadRequest) return } // Use stored data to get an error object e := paymentIntent.LastPaymentError // Use its type to choose a response switch e.Type { case "card_error": log.Println("A payment error occurred: ", e.Msg) case "invalid_request": log.Println("An invalid request occurred.") default: log.Println("Another problem occurred, maybe unrelated to Stripe.") } default: log.Println("Unhandled event type: ", event.Type) } w.WriteHeader(http.StatusOK) }

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.
Go
stripe.Key =
"sk_test_BQokikJOvBiI2HlWgH4olfQ2"
pi, _ := paymentintent.Get(
"{{PAYMENT_INTENT_ID}}"
, nil, ) paymentErr := pi.LastPaymentError if paymentErr != nil { log.Printf("PaymentIntent %s experienced a %s error.", pi.ID, paymentErr.Type) }

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 Go library, each error object has a Type attribute. Use the documentation for each type for advice about how to respond.

Name

Type

Description
Payment error

stripe.ErrorTypeCard

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.ErrorTypeInvalidRequest

You made an API call in a way that isn’t currently valid. This can include:

  • Rate limiting error
  • Authentication error
  • Invalid parameters or state
API error

stripe.ErrorTypeAPI

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

stripe.ErrorTypeIdempotency

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

Card errors

Non-card payment errors

Everything in this section also applies to non-card payments. For historical reasons, payment errors have the type stripe.ErrorTypeCard. 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.)

Go
func example_function(params *stripe.PaymentIntentParams) { stripe.Key =
"sk_test_BQokikJOvBiI2HlWgH4olfQ2"
_, err := paymentintent.New(params) if err == nil { log.Println("No error.") } else { if stripeErr, ok := err.(*stripe.Error); ok { if stripeErr.Type == stripe.ErrorTypeCard { charge = Charge.retrieve(stripeErr.PaymentIntent.LatestCharge) if charge.Outcome.Type == "blocked" { log.Println("Payment blocked for suspected fraud.") } else if stripeErr.Code == stripe.ErrorCodeCardDeclined { log.Println("Declined by the issuer.") } else if stripeErr.Code == stripe.ErrorCodeExpiredCard { log.Println("Card expired.") } else { log.Println("Other card error.") } } } } }

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.)

Go
func example_function(params *stripe.PaymentIntentParams) { stripe.Key =
"sk_test_BQokikJOvBiI2HlWgH4olfQ2"
_, err := paymentintent.New(params) if err == nil { log.Println("No error.") } else { if stripeErr, ok := err.(*stripe.Error); ok { if stripeErr.Type == stripe.ErrorTypeCard { if stripeErr.PaymentIntent.Charges.Data[0].Outcome.Type == "blocked" { log.Println("Payment blocked for suspected fraud.") } else if stripeErr.Code == stripe.ErrorCodeCardDeclined { log.Println("Declined by the issuer.") } else if stripeErr.Code == stripe.ErrorCodeExpiredCard { log.Println("Card expired.") } else { log.Println("Other card error.") } } } } }

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.

Go
params := &stripe.PaymentIntentParams{ Amount: stripe.Int64(2000), Currency: stripe.String(string(stripe.CurrencyUSD)), Confirm: stripe.Bool(true), PaymentMethod: stripe.String(
"pm_card_radarBlock"
), } example_function(params)
console
Go
1749843298 Payment blocked for suspected fraud.

Blocked for suspected fraud

Type

stripe.ErrorTypeCard

Codes
charge = Charge.retrieve(stripeErr.PaymentIntent.LatestCharge) charge.Outcome.Type == "blocked"
Codes

stripeErr.PaymentIntent.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:

  • Optimize your Radar integration to collect more detailed information.
  • Use Payment Links, Checkout, or Stripe Elements for prebuilt optimized 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.

Declined by the issuer

Type

stripe.ErrorTypeCard

Codes

cardErr.Error.Code == stripe.ErrorCodeCardDeclined

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 prebuilt 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.ErrorTypeCard

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

Invalid request errors cover a range of situations. The most common one is when the API request has invalid parameters or isn’t allowed in your integration’s current state. Use the error code (stripeErr.Code) and consult the error code documentation to find a solution. A few error codes require a special response:

  • rate_limit and lock_timeout reflect rate limit errors
  • secret_key_required reflects an authentication error
  • Other error codes reflect invalid parameters or state

Rate limit errors

Type

stripe.ErrorTypeInvalidRequest

CodesstripeErr.Code == stripe.ErrorCodeRateLimit or stripeErr.Code == stripe.ErrorCodeLockTimeout
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.

Authentication errors

Type

stripe.ErrorTypeInvalidRequest

CodesstripeErr.Code == stripe.ErrorCodeSecretKeyRequired
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.

Invalid parameters or state

Type

stripe.ErrorTypeInvalidRequest

Codes stripeErr.Code != stripe.ErrorCodeRateLimit and stripeErr.Code != stripe.ErrorCodeLockTimeout and stripeErr.Code != stripe.ErrorCodeSecretKeyRequired
Problem You made an API call with the wrong parameters, in the wrong state, or in an invalid way.
Solutions In 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 stripeErr.DocURL for documentation about the error code.
  • If the error involves a specific parameter, use stripeErr.Param to determine which one.

API errors

Type

stripe.ErrorTypeAPI

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.

Idempotency errors

Type

stripe.ErrorTypeIdempotency

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.
Was this page helpful?
YesNo
Need help? Contact Support.
Join our early access program.
Check out our changelog.
Questions? Contact Sales.
LLM? Read llms.txt.
Powered by Markdoc