Stripe API uses a single endpoint for both test and live traffic. As a user/developer, this is very convenient because switching from test mode to live mode only requires changing one variable – Stripe API Key.But how does Stripe use the same API endpoint and still keep the test and live traffic separate?The solution is simple, elegant and beautiful.*These are the constraints Stripe has to work with:- Use the same endpoint for both test and live traffic.
- Keep test and live deployments seperate.
What if we use a proxy server?Yes! The server at 'https://api.stripe.com' is a proxy server.This proxy server looks at the secret key(sk_test_xxxx or sk_live_xxxx) and routes the request either to the test or live Stripe API deployment.This is what the infrastructure looks like.Caveat: Using an extra layer of infrastructure adds on to your Cloud bill. But, hey, the simplicity is worth it.Here's a FastAPI implementation of the above logic.1import base64
2import httpx
3
4from fastapi import FastAPI, Request
5from fastapi.responses import JSONResponse
6
7app = FastAPI()
8
9@app.middleware("http")
10async def get_credentials(request: Request, _):
11 auth = request.headers.get("Authorization")
12 _, data = (auth or " ").split(" ", 1)
13 secret_key, _ = base64.b64decode(data).decode().split(":", 1)
14 _, mode, _ = secret_key.split("_")
15
16 ENDPOINT = None
17 if mode == "test":
18 ENDPOINT = TEST_ENDPOINT
19 elif mode == "live":
20 ENDPOINT = LIVE_ENDPOINT
21
22 async with httpx.AsyncClient() as client:
23 # Construct the new URL with the original path
24 new_url = f"{ENDPOINT.rstrip('/')}{request.url.path}"
25 # Properly encode query parameters
26 if request.url.query:
27 new_url = f"{new_url}?{request.url.query}"
28
29 response = await client.request(
30 method=request.method,
31 url=new_url,
32 headers=request.headers.raw,
33 content=await request.body(),
34 timeout=10,
35 )
36 # Return the response
37 return JSONResponse(
38 content=response.json(),
39 status_code=response.status_code,
40 headers=dict(response.headers),
41 )
42
*This is how I think it works. Stripe may be doing something else but this solution fits.