Sometimes network connections fail! If you are only streaming a movie, then you can simply refresh the web page and start where you left off. But if your network goes out while waiting on a payment-related response from Forage's API, error resolution becomes more ambiguous. If you do not receive a response from Forage due to a network outage, there is no way to know whether,

  • Forage did not receive the request at all, or,
  • Forage already processed your request and the response did not reach your application

This is exactly where idempotency comes to the rescue.

The Forage Payments API supports an Idempotency-Key header for most operations. This header allows you to safely retry requests while still guaranteeing that the side effects only happen once. Simply use the same Idempotency-Key header across all of the retries and the financial effects will only occur once. If the Forage API sees a duplicate request with the same Idempotency-Key, it will serve a cached response.

Here are some additional pieces of guidance for idempotency keys,

  • If you change the request body, then you must use a different Idempotency-Key.
  • Idempotency keys only last for 10 minutes on Forage's backend, meaning that you should not retry requests for more than 10 minutes.
  • Forage recommends using a deterministic Idempotency-Key, such as the UUID of the related object on your backend. For example, if the UUID of your Order model is 75c34048-f166-4bf7-8447-2bbd39ff9ebe, you could use that as the idempotency key for a Create Checkout Session request as you should only need to call this endpoint once per Order,
curl -X POST \
-H 'Idempotency-Key:75c34048-f166-4bf7-8447-2bbd39ff9ebe' \
-H 'Content-Type:application/json' \
-H 'Authorization: Bearer <your_token>' \ \
-d '
     "delivery_address": {
          "country": "US",
          "city": "Los Angeles",
          "line1": "4121 Santa Monica Blvd",
          "line2": "Unit 513",
          "zipcode": "90029",
          "state": "CA"
     "snap_total": 100,
     "ebt_cash_total": 20,
     "remaining_total": 0,
     "product_list": [],
     "is_delivery": true,
     "success_redirect_url": "",
     "cancel_redirect_url": ""