Stripe exception handling
| |

Recovering from Failures when Handling Payments with Stripe

In our previous post we explored webhooks as a reliable means to promptly respond to customer activities, such as checkouts, successful payments or failed transactions. Yet, in practice, we often deal with a variety of unforeseen errors that can present a threat to daily operations of an e-commerce platform. To mitigate service disruptions, it’s crucial to understand how Stripe communicates issues. In this post, we explore common Stripe exceptions and learn about managing network and connection issues.

This article is part of a comprehensive series. Be sure to check out the previous post, where you learn how to use and benefit from Stripe webhooks.

Disclaimer: I am not affiliated with Stripe. All insights shared in this article are based on my personal experience and opinions.

Table of Contents

Stripe Error Anatomy

Stripe’s API uses standard HTTP status codes to indicate the success or failure of requests. In addition to these codes, it returns a JSON payload that contains more detailed information about the problem. Key elements included in the error response are:

  • type: Represents the error type (e.g. api_error, card_error etc) – see all error types here.
  • code: Helps understand the error (e.g invalid_number)
  • message: A descriptive message providing more details

When using Stripe’s Java library, errors are handled through exceptions. Each type of error thrown by the API can correspond to different exceptions in the Java library.

Stripe’s API groups errors into several types. Source: Stripe

The Java SDK maps API errors to specific exceptions. Understanding this classification will help you make your payment system more robust and reliable.

Common Exceptions in Stripe’s Java Library

ApiException

Unexpected errors that occur server-side. These are rare but can happen during Stripe’s API downtime or unexpected issues on their end.

import com.stripe.exception.ApiException;

try {
  // Stripe SDK call
} catch (ApiException e) {
  logger.warn("Operation failed", e);
  throw e;
}

ApiConnectionException

Represents issues related to network connectivity between your server and Stripe.

import com.stripe.exception.ApiConnectionException;

try {
  // Stripe SDK call
} catch (ApiConnectionException e) {
  logger.warn("Network error", e);
  throw e;
}

AuthenticationException

Occur when your API key is incorrect or lacks the necessary permissions for the requested operation.

import com.stripe.exception.AuthenticationException;

try {
  // Stripe SDK call
} catch (AuthenticationException e) {
  logger.warn("Authentication with Stripe failed", e);
  throw e;
}

CardException

This exception relates specifically to issues with card processing, such as declined payments or fraudulent flags.

import com.stripe.exception.CardException;

try {
  // Stripe SDK call
} catch (CardException e) {
  logger.warn("There was an issue with the card", e);
  throw e;
}

InvalidRequestException

Happens due to invalid parameters or resource IDs in your request.

import com.stripe.exception.InvalidRequestException;

try {
  // Stripe SDK call
} catch (InvalidRequestException e) {
  logger.warn("Invalid request", e);
  throw e;
}

RateLimitException

Occurs when too many requests are made to the API in a short amount of time.

import com.stripe.exception.RateLimitException;

try {
  // Stripe SDK call
} catch (RateLimitException e) {
  logger.warn("Too Many Requests", e);
  throw e;
}

Additional Exceptions to Be Aware of

  • ApiKeyMissingException: This exception is thrown when you forget to initialize the SDK with your API key. Typically, you want to set the key globally through Stripe.apiKey = "YOUR_SECRET_API_KEY";.
  • SignatureVerificationException: You will likely encounter this one when working with webhooks. Essentially, each webhook request is signed and the signature is subject to verification.
  • IdempotencyException: Indicates that the request did not adhere to idempotent rules. For instance, if the parameters changed between requests with the same idempotent key. In general, idempotency is an important feature that let’s you retry operations that would otherwise result in data inconsistencies. Curious to learn more? Check this post.

Managing Network and Connection Issues

Network and connection issues can occur for various reasons, such as timeouts or intermittent server availability. Merely catching ApiConnectionException might not be enough. You want to implement a retry mechanism for handling transient errors that are likely to resolve on their own after a short period.

Stripe supports idempotent requests for safely retrying transactions without accidentally performing the same operation twice. This is done by adding an Idempotency-Key header to your requests.

import com.stripe.model.Charge;
import com.stripe.param.ChargeCreateParams;
import com.stripe.net.RequestOptions;

RequestOptions options = RequestOptions.builder()
  .setIdempotencyKey("unique-key")
  .build();
Charge charge = Charge.create(
  ChargeCreateParams.builder()
    .setAmount(1000L)
    .setCurrency("usd")
    .setSource("tok_visa")
    .build(), 
  options
);

Next, make sure to change timeout setting for your HTTP client whenever the default settings are insufficient. Stripe’s Java library exposes the relevant keys:

// Set the connection timeout to 2 seconds
Stripe.setConnectTimeout(2000);

// Set the API read timeout to 5 seconds
Stripe.setReadTimeout(5000);

Summary

Effectively managing network and connection issues and implementing resilient coding practices are essential for a reliable integration with Stripe’s APIs. Utilizing idempotency for safe retries with a robust mechanism such as exponential backoff and customizing timeout settings can significantly enhance your application’s robustness. Always refer to Stripe’s latest documentation and best practices to keep your integration up to date.

Thanks for reading and stay tuned for the next article where we expand on dealing with edge cases. In particular, we will implement handling of declined payments and provide a customer-friendly way of retrying a payment.

Similar Posts