← All guides

Mock APIs for Apple Shortcuts β€” an API that doesn't fake its writes

Apple's official Shortcuts User Guide has a whole chapter on web APIs, and its "Request your first API" tutorial teaches the Get Contents of URL action against jsonplaceholder.typicode.com/users. The same page explains that switching the action to POST, PUT, or PATCH reveals a Request Body parameter "for creating, replacing, or modifying an entry." Here's what the tutorial can't tell you: JSONPlaceholder doesn't do any of those things. We verified it the day this guide was published β€” POST /users answers 201 with {"id":11}, and GET /users/11 immediately 404s. The record was never created. Every learner who finishes Apple's GET chapter and tries the very next thing the docs describe gets a success response that lies, and no way to fetch back what they "created."

This guide continues where Apple's leaves off, against an API with the same conventions where writes persist β€” so your shortcut can create a record in one action and read it back in the next. Better for phones: nothing here needs a terminal. The shared demo API works with zero setup, and your own API is one tap in Safari (this link). The curl commands below are just the exact request each Shortcuts action makes, so Mac users can sanity-check any step; iPhone users can ignore them entirely.

1. Your first request, picking up where Apple's guide stops

The public demo project is a seeded e-commerce API β€” no signup, no key, no API-of-the-day account. In Shortcuts, add two actions:

ActionSetup
URLhttps://mockbird.mockbird.workers.dev/m/demo/products?limit=5
Get Contents of URLleave Method on GET (the default)

Run it. What comes back is a JSON list, exactly the "mess of text" Apple's tutorial promises:

curl 'https://mockbird.mockbird.workers.dev/m/demo/products?limit=3'
# β†’ [ {"id":1, "name":"World End", "price":873.65, "category":"home",
#      "inStock":true, "rating":…, "image":…, "description":…}, … ]

Apple's example narrows results with ?username=Bret; the same key=value filtering works here β€” ?category=toys, ?inStock=true β€” plus a larger query toolkit we'll use below. Every field of every record holds a type-correct value, so the parsing actions in the next step never hit a missing key.

2. Parsing it β€” Dictionary actions, exactly as Apple teaches

Apple's Work with JSON chapter is the reference here, and it applies unchanged. The canonical chain:

Get Contents of URL
β†’ Get Dictionary from Input        # parses the JSON
β†’ Get Item from List (First Item)  # lists: grab one record
β†’ Get Dictionary Value (key: name) # β†’ "World End"

For a list, wrap the last step in Repeat with Each and collect Get Dictionary Value: name of each Repeat Item into a list for Choose from List or a notification. Because the demo reseeds daily but keeps the same shape, a shortcut that parsed yesterday parses today. Want fewer keys to wade through in the editor? Ask the server to slim the record: ?select=name,price returns just those fields (plus id).

3. Let the server do the list gymnastics

Sorting and filtering inside Shortcuts means Repeat loops and If towers. Mockbird understands the work in the URL, which is where a phone-sized editor wants it:

# page 2, five per page
…/m/demo/products?page=2&limit=5          # β†’ records 6–10
# most expensive first
…/m/demo/products?sortBy=price&order=desc&limit=3
# free-text search across all fields
…/m/demo/products?q=area

Each of these is just a different text in the URL action β€” build it with variables (Ask for Input β†’ insert into the URL as a Magic Variable) and one shortcut becomes a tiny search app.

4. A POST that your next action can prove happened

Set Get Contents of URL's Method to POST and the Request Body parameter appears, exactly as Apple's guide describes. Choose JSON and add fields β€” name, price, category, inStock. The request your shortcut makes, and what returns:

curl -X POST 'https://mockbird.mockbird.workers.dev/m/demo/products' \
  -H 'content-type: application/json' \
  -d '{"name":"Shortcuts test product","price":9.99,"category":"toys","inStock":true}'
# β†’ 201 {"id":31, "name":"Shortcuts test product", …}

Now the part JSONPlaceholder can't do. Feed the response through Get Dictionary Value (key: id), insert that Magic Variable into a second URL β€” …/m/demo/products/id β€” and Get Contents of URL again:

curl 'https://mockbird.mockbird.workers.dev/m/demo/products/31'
# β†’ your record, still there

Create β†’ read-back β†’ (optionally DELETE) in one shortcut, every response real. We verified the full POST β†’ GET-back β†’ DELETE β†’ 404 cycle before publishing. The demo resets every 24 h, so test junk cleans itself up.

5. Errors you can branch on β€” because Shortcuts won't show you a status code

Get Contents of URL hands your shortcut the response's contents. Apple's docs list no status-code or response-header outputs for it, and the community has documented for years that error handling in Shortcuts means looking at the body. So make your failures arrive in the body, on purpose:

curl 'https://mockbird.mockbird.workers.dev/m/demo/products?mock_status=500'
# β†’ 500 with body {"error":"simulated 500 error (mock_status)"}

The branch is two actions: Get Dictionary from Input β†’ If (Dictionary β†’ Has Any Value for error) β†’ Show Alert, Otherwise β†’ parse as normal. Once that skeleton works, your real shortcut inherits it. For retry logic, ?mock_seq serves a deterministic script β€” fail, fail, recover:

…/products?mock_seq=503,503,200&mock_seq_key=my-test-1&limit=1
# call 1 β†’ {"error":"simulated 503 error (mock_seq)","seq":"1/3"}
# call 2 β†’ {"error":…,"seq":"2/3"}
# call 3 β†’ the products list, and 200s from then on

A Repeat (3 times) containing the request plus an If-has-error check exercises the retry path identically on every run β€” something no real API will do for you.

6. Totals in the body, where Get Dictionary Value can reach

Mockbird sends the collection total in an X-Total-Count header β€” which your shortcut will never see. ?mock_envelope reshapes the response so the metadata lives in the body instead:

…/m/demo/products?limit=3&mock_envelope=%7B%22total%22%3A%22%24total%22%2C%22page%22%3A%22%24page%22%2C%22hasMore%22%3A%22%24hasMore%22%2C%22items%22%3A%22%24data%22%7D
# β†’ {"total":30, "page":1, "hasMore":true, "items":[ …3 products… ]}

(That's the URL-encoded template {"total":"$total","page":"$page","hasMore":"$hasMore","items":"$data"}; on your own project you can set it once as a project default and keep the URL clean.) Get Dictionary Value: hasMore now decides whether your shortcut fetches another page, and items is the list to Repeat over. If the real API you'll eventually call wraps its lists β€” most do β€” matching its envelope now means your Dictionary actions survive the swap untouched.

7. Slow on purpose

A shortcut that's instant on Wi-Fi behaves differently as an automation on cellular. Hold the response open and watch what yours actually does while waiting:

curl -s -o /dev/null -w '%{time_total}s\n' \
  'https://mockbird.mockbird.workers.dev/m/demo/products?mock_delay=3000&limit=1'
# β†’ 3.78s

Three real seconds to notice that your "runs when I arrive at the gym" automation shows nothing until the request lands β€” and to decide whether a Show Notification up front would make it feel less broken.

8. A login flow that's safe to leave inside a shared shortcut

Shortcuts are made to be shared β€” via iCloud link, to anyone. Whatever API keys you typed into the actions travel with them. Mock credentials make that a non-event. Every Mockbird project exposes mock auth: any email/password logs in and returns a real signed JWT:

curl -X POST 'https://mockbird.mockbird.workers.dev/m/demo/auth/login' \
  -H 'content-type: application/json' \
  -d '{"email":"tester@example.com","password":"anything"}'
# β†’ {"user":{"id":…,"email":…,"name":…}, "token":"eyJhbGciOi…"}

In Shortcuts: POST with a JSON body from two Ask for Input prompts β†’ Get Dictionary Value: token β†’ later requests add a Header in Get Contents of URL: Authorization = Bearer token. Tokens expire on a schedule you control, so even the token-expired branch is testable. Nothing in the flow is a real credential; share the shortcut freely.

9. What did my shortcut actually send?

The eternal debugging question β€” did Request Body transmit JSON or a form? which headers went out? β€” has a ten-second answer. Point the action at a catch-all bin path:

curl -X POST 'https://mockbird.mockbird.workers.dev/m/demo/hooks/from-shortcuts' \
  -H 'content-type: application/json' -d '{"hello":"shortcuts"}'
# β†’ {"ok":true, "caught":"POST /hooks/from-shortcuts", "body":{"hello":"shortcuts"}, …}

The response echoes what arrived, and the request inspector (public for the demo project) logs method, path, headers, and body β€” from your phone's browser, no Mac required.

10. Your own API β€” one tap in Safari, still no terminal

The shared demo is fine for learning; for your own schema, open this link on the same iPhone β€” it creates a project (no signup) and opens its dashboard. Presets: blog, ecommerce, saas; or define resources by hand, or paste a CSV β€” a Numbers/Sheets export becomes a typed API, which is a very Shortcuts-shaped trick: your spreadsheet, queryable from an automation. For the curl-inclined, the same thing from a Mac:

curl -X POST 'https://mockbird.mockbird.workers.dev/api/projects' \
  -H 'content-type: application/json' -d '{"preset":"ecommerce"}'
# β†’ {"id":"abc123xyz9", "adminKey":"…"}  β†’ your API: /m/abc123xyz9/products

The adminKey manages the mock (schema, seeding) and never belongs inside a shortcut; the public /m/… URL is all your actions need β€” and it's safe to share by design.

11. When you don't need any of this

Honesty section. If your shortcut's data lives on the device β€” lists you maintain, values passed between shortcuts β€” plain Shortcuts features (files, Notes, the share sheet) or a storage app like Data Jar are simpler than any HTTP call. And for read-only practice, JSONPlaceholder remains perfectly good at the thing Apple's tutorial uses it for: GETs. A stateful mock earns its place the moment your shortcut needs to write something and see it again, needs failure and slowness on cue, or needs an auth header that's safe to share. One more honest note: we can't run iOS in our test rig, so the Shortcuts action chains above follow Apple's user guide patterns verbatim rather than screenshots of our own phone β€” but every HTTP request and response shown was executed against production, byte for byte, before publishing.

Related: the full JSONPlaceholder comparison, Home Assistant and ESP32 from the same personal-automation series, testing loading and error states, and mock JWT auth.

Verification: all HTTP calls on this page (demo limit=3 typed list, category/inStock filters, page=2&limit=5 returning ids 6–10, sortBy=price desc, q=area, ?select projection, POSTβ†’GET-backβ†’DELETEβ†’404 cycle with id 31, mock_status=500 body with error key, mock_seq bodies carrying error + seq "1/3"/"2/3" then recovery, mock_envelope returning {"total":30,"page":1,"hasMore":true,"items":[…]}, 3.78s measured mock_delay, auth login returning user + 231-char JWT, bin echo at /hooks/from-shortcuts) were run against production on 21 Sep 2026 before publishing, as was the JSONPlaceholder claim (POST /users β†’ 201 {"id":11}; GET /users/11 β†’ 404; their ?username=Bret query works fine). Apple facts β€” the "Request your first API" tutorial's use of jsonplaceholder.typicode.com, Get Contents of URL's GET/POST/PUT/PATCH/DELETE methods and the Request Body (JSON/Form/File) parameter appearing for POST/PUT/PATCH β€” are from Apple's Shortcuts User Guide for iOS and Mac as of September 2026. Seeded names/prices vary with the demo's daily reseed. If a step here doesn't work, that's a bug: tell us.