Make scenarios fail in production for reasons that never show up while you're building them: the third-party API starts 503ing, rate-limits you, times out, or your error route turns out to be wired to a directive that doesn't do what you thought. You can't make a real API fail on cue โ so error routes, the Break directive's retries, and timeout handling usually ship untested. And on the free plan every rehearsal run costs credits from a 1,000/month budget, so "just rerun it until it breaks" is an expensive test strategy.
This guide points Make's HTTP module at a live, stateful mock API that fails exactly when you tell it to โ with a URL parameter. Every curl below was verified against production before publishing.
The public demo project is a seeded e-commerce API. Add an HTTP โ Make a request module and set the URL to:
https://mockbird.mockbird.workers.dev/m/demo/products?limit=2
Click Run once โ you get two product records (enable Parse response to map fields in later modules). Writes work too: POST /m/demo/products creates a record a later module can GET back. Same query conventions as json-server (_page/_limit/sortBy/filters), so pagination loops are testable. Want your own schema instead of ours? One curl or one click, below.
Make's HTTP module has a setting called "Evaluate all states as errors (except for 2xx and 3xx)" โ and it's off by default. Off means a 503 from the API is a successful module run: the status code and error body come back as ordinary output, and your scenario carries on, happily piping error HTML into whatever comes next. Prove it to yourself:
https://mockbird.mockbird.workers.dev/m/demo/products?mock_status=503
Run once with the toggle off: module goes green, output shows status code 503. Flip the toggle on, run again: now the module errors and your error route (if any) actually fires. One URL parameter lets you rehearse both behaviors deliberately instead of discovering the difference in production. mock_status takes any code โ run your scenario through 400, 401, 404, 429, 500 and watch what each branch does.
Make's retry story is the Break error handler: right-click the module โ Add error handler โ Break, set a retry limit (1โ10) and an interval in minutes, and enable incomplete-execution storage in scenario settings. The failing bundle is parked as an incomplete execution and retried automatically. The hard part is proving that chain works: real APIs don't fail twice and then recover on cue. ?mock_seq does exactly that:
# 1st request โ 500, 2nd โ 500, 3rd and later โ real 200 response
curl -s -o /dev/null -w '%{http_code}\n' \
'https://mockbird.mockbird.workers.dev/m/demo/products?mock_seq=500,500,200&mock_seq_key=myscenario'
# run it four times: 500 500 200 200
Point the HTTP module at that URL (with "Evaluate all states as errors" on, per ยง2), attach a Break handler with 2 retries at 1-minute intervals, run once: the first attempt draws a 500 and parks an incomplete execution, retry one draws the second 500, retry two succeeds and the incomplete execution clears. Every response carries x-mockbird-seq: pos/len so you can see which step each attempt hit. Use a distinct mock_seq_key per scenario so parallel tests don't share a counter, and &mock_seq_reset=1 to restart. Failed writes are not applied โ a POST that draws a 500 inserts nothing, so a retried POST can't double-create. (On the shared demo, counters are also scoped per client IP, so this link starts fresh for you.)
The other directives โ Ignore, Resume, Rollback, Commit โ are just as testable: wire each to an error route, trigger the error with mock_status=500, and check what actually reaches the modules downstream.
curl -s -o /dev/null -w '%{time_total}\n' \
'https://mockbird.mockbird.workers.dev/m/demo/products/1?mock_delay=3000'
# 3.14s
The HTTP module's Timeout field accepts 1โ300 seconds (default 40). Set it to 2 against a mock_delay=3000 URL and the timeout path fires on demand โ then decide whether that should Break-and-retry (ยง3) or fail into an error route (ยง2). mock_delay goes up to 5,000 ms; mock_jitter adds a random component if you want latency that isn't suspiciously constant.
# allow 3 requests per 60s per client, then 429 with Retry-After
'https://mockbird.mockbird.workers.dev/m/demo/products?mock_ratelimit=3&limit=1'
# 4 rapid requests โ 200 200 200 429
Run an iterator over that URL and watch the fourth call 429. Responses carry x-ratelimit-limit / x-ratelimit-remaining / x-ratelimit-reset, and the 429 includes Retry-After โ so you can verify your Break interval outlasts the window, or that a Sleep module reads the header, before the real provider starts rationing you. More recipes: simulating rate limits.
When a scenario POSTs to a partner API and the partner says "malformed payload", you want the request, verbatim. Point the module at a bin instead:
curl -s -X POST https://mockbird.mockbird.workers.dev/m/demo/hooks/order-created \
-H 'content-type: application/json' -d '{"orderId":123,"total":49.9}'
# โ {"ok":true,"caught":"POST /hooks/order-created","body":{...},"receivedAt":"โฆ"}
The demo's catch-all route echoes what it caught, and every hit โ method, path, headers, body โ lands in the public demo request inspector. On your own project, an empty project plus one ANY /* custom route is a private bin with a per-project inspector โ webhook.site without the 7-day expiry.
Make's Custom webhook trigger learns its data structure from a sample request โ you click Redetermine data structure (costs no operations) and send it something. Most people send a hand-typed toy payload. Send it a realistic, signed one instead: Mockbird projects deliver HMAC-signed POSTs with x-mockbird-event, x-mockbird-delivery, and x-mockbird-signature: sha256=โฆ headers on every record change.
# point your project's webhook at the Make webhook URL (returns the signing secret)
curl -s -X PUT https://mockbird.mockbird.workers.dev/api/projects/YOUR_ID/webhook \
-H "x-admin-key: YOUR_ADMIN_KEY" -H "content-type: application/json" \
-d '{"url":"https://hook.eu2.make.com/YOUR_WEBHOOK_ID"}'
# instant test delivery, no record edit needed:
curl -s -X POST https://mockbird.mockbird.workers.dev/api/projects/YOUR_ID/webhook/test \
-H "x-admin-key: YOUR_ADMIN_KEY"
Click Redetermine data structure, fire the webhook/test curl, and the webhook learns a payload with the same shape (and signature headers) your scenario will see from any signed-webhook provider โ then verify the signature with the returned secret and you've tested the part of webhook handling everyone skips. Delivery attempts (status, error, duration) are listed at GET โฆ/webhook/deliveries. Deliveries travel the public internet โ we refuse to POST to private addresses, which is fine here since Make webhook URLs are public. More recipes: sending test webhooks.
One curl (or one click), no signup:
curl -s -X POST https://mockbird.mockbird.workers.dev/api/projects \
-H "content-type: application/json" \
-d '{"preset":"ecommerce"}'
# โ {"id":"abc123xyz9", "adminKey":"โฆ", ...}
Presets: blog / ecommerce / saas โ or define resources by hand, or import an OpenAPI spec, db.json, CSV, or HAR recording of the real API. Every simulation param above works on your project's URLs. Projects have a 10,000 requests/day cap โ scenario testing barely dents it, and none of it burns your Make credits on a real provider's errors.
Fair's fair: for shaping mappings against a known payload, Run once against the real API and building from its live output is Make's native flow and often fastest. The Resume directive's substitute output is a fine way to keep a scenario alive past a known-flaky module. Reach for a hosted mock when the thing under test is the HTTP layer itself: the errors-toggle behavior, Break retries, timeouts, 429s, error routes, signature handling โ the paths a healthy real API will never let you exercise. They compose: build the happy path against the real API, rehearse the failure paths against the mock.
Related: mock APIs for n8n, mock APIs for Zapier, testing loading and error states, send test webhooks with real signatures, and mocking third-party APIs generally.
Verification: all demo curls on this page (seq 500โ500โ200โ200, mock_status 503 body, 3.14s delay, 200 200 200 429 rate-limit run with x-ratelimit-* headers, bin echo + inspector log) were run against production on 5 Sep 2026 before publishing. Make behavior โ the "Evaluate all states as errors (except for 2xx and 3xx)" default, Break handler retry limit 1โ10 with minute intervals and incomplete-execution storage, the Ignore/Resume/Break/Rollback/Commit directives, HTTP module timeout range 1โ300s (default 40), Redetermine data structure costing no operations, and the free plan's 1,000 credits/month โ is from Make's official help center, apps documentation, and pricing pages as of Sep 2026; plans change, so check make.com/en/pricing. We don't run your Make account; if a step here doesn't work, that's a bug: tell us.