Free Stripe-Shaped Mock API for Testing
Mock endpoints that match Stripe's response shapes — for testing integrations, prototyping checkout flows, and verifying webhook handlers without ever touching a real Stripe key.
What this is
A read-only-ish HTTP API that returns JSON in the shape of Stripe's public REST API. Same field names, same ID prefixes (cus_, ch_, pi_, sub_, in_), cursor pagination, integer cents, Unix timestamps, and a Stripe-style error envelope. Reads are deterministic — every request returns the same data, so you can pin snapshot tests. Writes return shape-correct objects but are not persisted.
Use it to: exercise the JSON shapes your code consumes, test webhook signature verification end-to-end, simulate failure modes (card_declined, rate_limited, timeouts) that are hard to trigger on real Stripe test cards, and demo a flow before you set up a real Stripe account.
Quick start
Fetch the first three charges. No auth needed.
curl
curl https://mockapihub.com/api/stripe/charges?limit=3JavaScript
const res = await fetch(
"https://mockapihub.com/api/stripe/charges?limit=3"
);
const { data, has_more } = await res.json();
console.log(data[0].id); // -> "ch_..."Python
import requests
res = requests.get(
"https://mockapihub.com/api/stripe/charges",
params={"limit": 3},
)
data = res.json()["data"]
print(data[0]["id"]) # -> "ch_..."Available endpoints
| Method | Path | Description |
|---|---|---|
| GET | /api/stripe/customers | List customers (cursor paginated). |
| GET | /api/stripe/customers/:id | Retrieve one customer. |
| POST | /api/stripe/customers | Create a customer (not persisted). |
| GET | /api/stripe/charges | List charges. |
| GET | /api/stripe/charges/:id | Retrieve one charge. |
| POST | /api/stripe/charges | Create a charge (not persisted). |
| GET | /api/stripe/payment_intents | List PaymentIntents. |
| GET | /api/stripe/payment_intents/:id | Retrieve one PaymentIntent. |
| POST | /api/stripe/payment_intents | Create a PaymentIntent. |
| POST | /api/stripe/payment_intents/:id/confirm | Confirm a PaymentIntent. ?simulate=requires_action returns a 3DS-style response. |
| GET | /api/stripe/subscriptions | List subscriptions. |
| GET | /api/stripe/subscriptions/:id | Retrieve one subscription. |
| GET | /api/stripe/invoices | List invoices. |
| GET | /api/stripe/invoices/:id | Retrieve one invoice. |
| POST | /api/stripe/webhooks/trigger | Sign and POST a Stripe-shaped event to a target_url you provide. 10/min per IP. |
All paths support the cursor params limit, starting_after, and ending_before per Stripe's convention.
Webhook simulation
Send a signed, Stripe-shaped event to any public HTTPS URL you control. Combine with webhook.site or RequestBin for an instant inbox.
# 1. Grab a free inbox URL (no signup):
# https://webhook.site/ → copy the unique URL
# 2. Tell us to send a Stripe-shaped event there:
curl -X POST https://mockapihub.com/api/stripe/webhooks/trigger \
-H 'Content-Type: application/json' \
-d '{
"event_type": "charge.succeeded",
"target_url": "https://webhook.site/<your-uuid>"
}'
# 3. Refresh webhook.site — the signed event has arrived.
# The Stripe-Signature header verifies against the secret below.Public test secret (for HMAC verification):
whsec_mockapihub_demo_DO_NOT_USE_IN_PROD_5f3aBpQrS9zX1Y2Z
Algorithm: HMAC-SHA256(secret, "${t}.${payload}"), header format t=<unix>,v1=<hex>. Stripe's own libraries verify cleanly against it.
Limits: 10 trigger calls/min per IP, up to 5 events per call. Only public HTTPS URLs are accepted — private/internal addresses are refused at request time and again after DNS resolution.
Supported event types: charge.succeeded, charge.failed, customer.created, payment_intent.succeeded, payment_intent.payment_failed, invoice.paid, customer.subscription.created, customer.subscription.deleted
Failure simulation
The chaos query params apply to every /api/stripe/* endpoint. Use them to drive your error paths without provisioning special Stripe test cards or test clocks.
| Query param | Effect |
|---|---|
| ?simulate=card_declined | 402 — card_error / generic_decline |
| ?simulate=insufficient_funds | 402 — card_error / insufficient_funds |
| ?simulate=rate_limited | 429 — rate_limit_error |
| ?simulate=timeout | 504 — api_error after a 5s delay |
| ?delay=1500 | Sleep N ms (clamped 0..10000) before responding. |
| ?fail_rate=0.3 | 30% chance of a 500 api_error per request. |
Example: curl https://mockapihub.com/api/stripe/charges?simulate=card_declined returns a real Stripe-shaped 402 with code: card_declined.
How this differs from the real Stripe API
- No persistence. Reads are deterministic; writes return a shape-correct object but the next GET won't find it.
- No real authentication. All endpoints are public. There's no sk_test_* key, no Bearer token, no idempotency key validation.
- No real money movement. Charges "succeed" because we say so. They don't hit a card processor.
- Limited resource coverage. Customers, charges, PaymentIntents, subscriptions, invoices, and webhooks only.
- Response shapes may drift. Stripe ships new fields constantly. We won't perfectly track every minor version. Last reviewed: 2026-05-13.
Common use cases
- Testing Stripe webhook signature verification without a Stripe account.
- Prototyping a checkout UI before committing to Stripe's SDK, or while waiting on an account-approval review.
- Driving the failure-handling paths in your code: card_declined, rate_limited, and timeout flows without test-card juggling.
- Deterministic CI fixtures for code that reads Stripe-shaped JSON.
- Demo environments — a sales engineer can demo a Stripe integration without keys, dashboards, or live accounts.
FAQ
Can I point Stripe's official SDK at this mock API?
Not directly — the official Stripe SDKs hardcode api.stripe.com. Use a plain HTTP client (fetch / axios / requests / curl) and call https://mockapihub.com/api/stripe/<resource> to verify the shapes your code consumes. For end-to-end SDK testing, use Stripe's own test-mode keys.
Is data persisted between requests?
No. Every GET returns the same deterministic data on every call. Every POST returns a Stripe-shaped response with a fresh ID, but nothing is stored — a follow-up GET for that ID will 404. This is the whole mock contract; tests must not depend on persistence.
How is the Stripe-Signature header on triggered webhooks generated?
HMAC-SHA256 over `${timestamp}.${json_payload}`, formatted as `t=<unix>,v1=<hex>`. Identical to Stripe's algorithm, so stripe.webhooks.constructEvent() (Node) or stripe.Webhook.construct_event() (Python) verify successfully against the public test secret published below.
Why is there no API key or signup?
It's a free, public testing service. No accounts, no keys, no rate limits on reads. The only rate limit is on the webhook trigger endpoint (10 calls/min per IP) to prevent abuse of the outbound HTTPS POST.
Can I add custom fields to created objects?
Fields you POST are echoed back in the response so your serialization paths work end-to-end. They're not stored — the next GET shows the same deterministic data as before. Good for testing request shape; not a state store.
What about endpoints you don't mock?
We ship customers, charges, payment_intents, subscriptions, invoices, and a webhook trigger. Resources like Radar, Terminal, Identity, Issuing, and Connect aren't shaped yet — if you need one, open an issue at github.com/nepalibidur14/freeapi.