Lightweight Stripe API Library
1 Why not just stripe?
2 Idempotency keys?
3 Client API Reference
stripe-host
stripe-endpoint
stripe-secret-key
stripe-bearer?
stripe-request-procedure/  c
exn:  fail:  stripe
stripe-get
stripe-delete
stripe-post
4 Simple example
7.7

Lightweight Stripe API Library

Sage Lennon Gerard

 (require stripe-integration)
  package: stripe-integration

An unofficial client of the Stripe API for use in Racket.

Tested against API version 2019-09-09.

Includes exponential backoff when Stripe’s servers request it, and idempotency key handling for sensitive calls.

1 Why not just stripe?

Because that’s not my trademark and I wanted a name that hit a sweet spot between:

I found an example of other unofficial libraries taking a similar approach, and Stripe keeps links to them. For that reason I’ll use this name unless I am asked to change it.

2 Idempotency keys?

An idempotency key is Stripe’s answer for how to handle when you, say, lose network connectivity right before the API tells you that a credit card transaction was complete. Instead of tangental validation or trying to incur a new charge, you can instead provide an idempotency key to a new request and Stripe will provide the same response it has available for you on the old call.

3 Client API Reference

value

stripe-host : "api.stripe.com"

The Stripe API host.

value

stripe-endpoint : (parameter/c string?) = stripe-host

The endpoint used for requests against the Stripe API. Change this to use a mock host.

value

stripe-secret-key : (parameter/c string?) = ""

The secret key to use when authenticating requests with the Stripe API. Use parameterize to limit the time this spends visible to other client modules.

value

stripe-bearer? : (parameter/c boolean?) = #f

If #t, requests will use bearer authentication. Otherwise, it will use basic authentication.

value

stripe-request-procedure/c

 : 
(unconstrained-domain-> exact-positive-integer?
                        dict?
                        jsexpr?
                        (or/c boolean? string?))
This contract applies to the below HTTP helper procedures. They each return the following 4 values, in order:

  1. The HTTP status code, as an exact positive integer.

  2. A dict of headers such that the keys are header names as all lower-case interned symbols. This is to eliminate ambiguity on casing rules and allow eq? tests.

  3. A jsexpr representing the JSON response to a Stripe API request.

  4. A generated idempotency key used to resume sensitive operations on Stripe using non-idempotent requests. For GET and DELETE requests, this is always #f. See the Stripe API reference for more information.

struct

(struct exn:fail:stripe exn:fail (idempotency-key wrapped-exn)
    #:extra-constructor-name make-exn:fail:stripe)
  idempotency-key : (or/c string? boolean?)
  wrapped-exn : exn?
An exception that wraps another in response to interrupted network connections.

This is thrown by the HTTP request procedures below when a connection to Stripe is interrupted. It will contain an idempotency key that you should persist if this exception came up when attempting a POST that did something sensitive like charge a customer. The key will help you repeat the request without repeating something that should only happen once.

wrapped-exn is the original exception caught before the exn:fail:stripe instance was raised in the original exception’s stead. An instance of exn:fail:stripe has the same continuation marks as wrapped-exn.

procedure

(stripe-get uri    
  #:retry? retry?    
  #:max-tries max-tries)  
exact-positive-integer?
dict?
jsexpr?
(or/c boolean? string?)
  uri : string?
  retry? : #t
  max-tries : 5

procedure

(stripe-delete uri    
  #:retry? retry?    
  #:max-tries max-tries)  
exact-positive-integer?
dict?
jsexpr?
(or/c boolean? string?)
  uri : string?
  retry? : #t
  max-tries : 5

procedure

(stripe-post uri    
  data    
  #:retry? retry?    
  #:max-tries max-tries)  
exact-positive-integer?
dict?
jsexpr?
(or/c boolean? string?)
  uri : string?
  data : (or/c dict? string?)
  retry? : #t
  max-tries : 5
HTTP helper methods for speaking to the Stripe API.

If retry? is #t, each request will retry with an exponential backoff if Stripe API responds with "HTTP 429 - Too Many Requests". retry? does not cover network connectivity failure, because blocking might not be the best approach. The client will make max-tries attempts before throwing exn:fail, and will wait as many seconds as defined by this procedure:

(define (backoff-time n)
  (min (+ (expt 2 n)
          (/ (random 0 1000) 1000))
       32))

The data provided to post will be encoded for use with "Content-Type: application/x-www-form-urlencoded". If the value cannot be encoded, post will raise exn:fail:contract.

All POST requests will include a generated idempotency key to protect against unusual network conditions at bad times (such as when processing a payment). In the event of a exn:fail:network, the exact exception will be transformed into an instance of exn:fail:stripe with the same continuation marks and the idempotency key attached for you to persist.

None of the request procedures will throw an exception in response to 4xx or 5xx HTTP status codes. If the response reports an error, it is still a response and will simply be returned as such.

4 Simple example

This follows the authentication example in the Stripe API reference.

(require stripe-integration json)
(stripe-secret-key "test_blahblahblah")
 
(define-values (status headers json ik) (stripe-get "/v1/charges"))

From this you can follow along in the reference using the other request procedures.