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=3

JavaScript

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

MethodPathDescription
GET/api/stripe/customersList customers (cursor paginated).
GET/api/stripe/customers/:idRetrieve one customer.
POST/api/stripe/customersCreate a customer (not persisted).
GET/api/stripe/chargesList charges.
GET/api/stripe/charges/:idRetrieve one charge.
POST/api/stripe/chargesCreate a charge (not persisted).
GET/api/stripe/payment_intentsList PaymentIntents.
GET/api/stripe/payment_intents/:idRetrieve one PaymentIntent.
POST/api/stripe/payment_intentsCreate a PaymentIntent.
POST/api/stripe/payment_intents/:id/confirmConfirm a PaymentIntent. ?simulate=requires_action returns a 3DS-style response.
GET/api/stripe/subscriptionsList subscriptions.
GET/api/stripe/subscriptions/:idRetrieve one subscription.
GET/api/stripe/invoicesList invoices.
GET/api/stripe/invoices/:idRetrieve one invoice.
POST/api/stripe/webhooks/triggerSign 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 paramEffect
?simulate=card_declined402 — card_error / generic_decline
?simulate=insufficient_funds402 — card_error / insufficient_funds
?simulate=rate_limited429 — rate_limit_error
?simulate=timeout504 — api_error after a 5s delay
?delay=1500Sleep N ms (clamped 0..10000) before responding.
?fail_rate=0.330% 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.

Free Mock API Shaped Like Stripe — For Testing & Prototyping | MockApiHub