Public API · v1

What I Wish API docs

What I Wish is a free gift-list app: the owner creates a list, shares the link, and guests reserve items so nobody buys the same thing twice. This page documents the parts of the API that are open to anyone: no account, no API key, no token. The machine-readable contract is the OpenAPI 3.1 spec.

Basics

Permissions and authentication

The public API has one permission level and it is unauthenticated: read published lists, reserve an item on them, and unfurl product links. There are no scopes to request and no key to generate, so there is nothing to sign up for. The OpenAPI document says the same in machine terms: top-level security is empty, and the only scheme under components.securitySchemes (firebaseSession) names the credential the app itself uses for owner-only endpoints, which are not part of this API and cannot be reached with a token obtained elsewhere. Longer version: auth.md.

Rate limits

Every response from a documented endpoint carries the IETF draft fields RateLimit-Policy (the quota: "per-ip";q=10;w=60) and RateLimit (what is left: "per-ip";r=7;t=42), plus X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset for older clients. A 429 adds Retry-After in seconds. Quotas: 60 per minute on public-wishlist, 10 per minute on unfurl and scrape-product, 10 per 10 minutes on reserve.

Errors

Every error is JSON with the same shape, including unknown /api paths (404) and wrong methods (405). There is no HTML error page on the API.

{
  "success": false,
  "error": "Missing URL",
  "code": "MISSING_URL",
  "hint": "Send a JSON body with a url field.",
  "docs": "https://whatiwish.app/docs"
}
codestatusmeaning
NOT_FOUND404No route, list or item at that path or id.
WISHLIST_NOT_FOUND, WISHLIST_NOT_PUBLISHED404The slug does not exist, or the owner has not published the list.
MISSING_SLUG, MISSING_URL, INVALID_URL, INVALID_BODY400The request is incomplete or the URL is not a public http(s) address. INVALID_BODY carries a details array.
MISSING_CAPTCHA, CAPTCHA_FAILED400Reservations need the Turnstile token the public list page issues.
ALREADY_RESERVED409Someone reserved that item first.
NO_PRODUCT_DATA422The page was fetched but nothing product-like was found on it.
METHOD_NOT_ALLOWED405Wrong HTTP method.
RATE_LIMIT429Per-IP limit hit. Wait and retry.
FETCH_FAILED, INTERNAL500The remote page could not be read, or something failed on our side.

Endpoints

GET /api/v1/public-wishlist/{slug}

Returns a published list and its items. The slug is the last segment of the public URL https://whatiwish.app/w/{slug}. Draft or private lists answer 404, the same as a slug that does not exist.

curl https://whatiwish.app/api/v1/public-wishlist/cumple-de-sofi
{
  "success": true,
  "wishlist": { "id": "...", "slug": "cumple-de-sofi", "title": "Cumple de Sofi", "occasion": "birthday", "isSurpriseMode": true, "itemCount": 3, "reservedCount": 1 },
  "items": [ { "id": "...", "title": "Taza térmica", "url": "https://...", "price": 35000, "currency": "ARS", "reservationStatus": "available" } ],
  "ownerName": "Sofi",
  "ownerUsername": "sofi"
}

POST /api/v1/reserve

Reserves an item on behalf of a guest. The owner sees that the item is taken, not who took it. The response includes a cancelToken; it is the only way to undo the reservation. When Cloudflare Turnstile is enabled on the site, the body must carry a turnstileToken issued by the widget on the public list page, so in practice this operation is called from that page rather than from a headless client.

curl -X POST https://whatiwish.app/api/v1/reserve \
  -H "Content-Type: application/json" \
  -d '{"wishItemId":"ITEM_ID","wishlistId":"LIST_ID","reservedByName":"Ana","reservedByEmail":"[email protected]","turnstileToken":"..."}'

POST /api/v1/unfurl

Fetches a page server-side and returns its Open Graph and product metadata: title, description, image, price, currency, site name. Private and internal addresses are rejected.

curl -X POST https://whatiwish.app/api/v1/unfurl \
  -H "Content-Type: application/json" \
  -d '{"url":"https://www.mercadolibre.com.ar/..."}'

POST /api/v1/scrape-product

Same input as unfurl, tuned for store product pages: it also reads JSON-LD and store-specific price markup, and answers 422 when nothing product-like was found.

curl -X POST https://whatiwish.app/api/v1/scrape-product \
  -H "Content-Type: application/json" \
  -d '{"url":"https://shop.example/products/cafetera"}'

Reading the site as an agent

Questions

Write to [email protected] or use the contact page. The app itself is at whatiwish.app.