← Guides

Test mode

Try it on a test key

curl -s "https://api.wellwardhealth.com/v1/prices?service=colonoscopy&near=00010&test_scenario=rate_limited" -H "Authorization: Bearer $WELLWARD_KEY"

Everything a test key returns is fictional. The practices, addresses, phone numbers and prices are made up; practice names start with [TEST]; the cities and ZIP codes do not exist. Nothing a test key returns is a real price, and nothing should be shown to a real user.

A test key (wl_test_…) calls the same endpoints, through the same code, as a live key. What differs is the data it reads and what it can cause.

How to tell, in code: every response to a test key has the header Wellward-Mode: test (errors too), and every successful one has meta.mode: "test" and meta.test_mode_notice; every fixture practice has identity_source: "fixture". Live responses say meta.mode: "live".

  • It reads a fixed fictional dataset, never live prices.
  • It never creates work: a test price request is not seen by anyone, and plays itself out.
  • It is never billed. Test calls are counted separately on your usage page.
  • It has the same rate limits as a live key, so nothing surprises you when you switch.

The dataset

Three fictional metros. Their ZIP codes are in the 000xx block the US Postal Service never issued, so they cannot collide with a real place — and a live key cannot resolve them.

| Metro | ZIPs | Coverage | |---|---|---| | Juniper Bay, OR | 00010, 00011 | full for most services | | Red Mesa, NM | 00020 | full for some, partial for others | | Cobalt Ridge, MT | 00030 | partial only; several services have no prices (left out of /v1/coverage) |

Twelve real services, with their real slugs and variant keys — so code you write against test data works unchanged on live data: comprehensive-metabolic-panel-cmp, lipid-panel, dental-cleaning-with-exam-and-x-rays, colonoscopy, mri-brain, x-ray-chest, urgent-care-visit-cold-flu-respiratory-ent, dermatology-consult, primary-care-annual-physical, vision-exam, physical-therapy, psychotherapy-consult. Several have more than one core variant and add-ons. (/v1/services on a test key lists the real catalog; only these twelve have test prices.)

About 190 prices, every one inside the freshness window. Practices are fictional — names prefixed [TEST], no NPI or Google place id, identity_source: "fixture", phone numbers in the fictional 555-01xx range.

Paging and sorting. lipid-panel near ZIP 00010 has more than 45 prices, so it pages: the first page holds 20 with a next_cursor, and summary.count gives the total. The nearest practices are not the cheapest, so sort=price and sort=distance lead with different rows:

curl -s "https://api.wellwardhealth.com/v1/prices?service=lipid-panel&near=00010&sort=price" -H "Authorization: Bearer $WELLWARD_KEY"
curl -s "https://api.wellwardhealth.com/v1/prices?service=lipid-panel&near=00010&sort=distance" -H "Authorization: Bearer $WELLWARD_KEY"

Withdrawn ids. fx_wd_001 to fx_wd_005 exist only as withdrawn prices: fetching one returns 410 with withdrawn_at (and, for fx_wd_001, a replacement_price_id), and they appear on GET /v1/prices/changes for about the first week of each month (the dataset is reloaded monthly and the feed keeps 30 days). For a withdrawal event you can rely on any day, use test_scenario=withdrawn_since.

test_scenario

Add test_scenario=<value> (query parameter on GET, body field on POST) to make a call misbehave on purpose. A live key sending it gets 400 test_scenario_not_allowed; an unknown value gets 400 invalid_test_scenario.

Any keyed REST endpoint (not /v1/mcp, and not the keyless /v1/prices/{id}/updates)

| Value | Result | |---|---| | rate_limited | 429, Retry-After: 1, rate-limit headers at zero | | server_error | 500 | | unavailable | 503 maintenance, Retry-After: 60, body maintenance: true | | slow | answers normally after 3 seconds | | timeout | 504 after 25 seconds | | auth_invalid | 401 |

POST /v1/price-requests

| Value | Result | |---|---| | complete_with_price (the default) | 30 s later: completed, outcome: price_obtained, a new fixture price in price_ids, and a request.completed webhook on the next five-minute delivery run. Only for the twelve test services sent as service; anything else completes with no price. | | complete_no_price | 30 s later: completed, outcome: no_price_obtained | | stay_queued | stays queued forever | | reject_unsupported_service | 422 unsupported_service at creation | | coverage_exists | 409 coverage_exists at creation |

A test request settles when you next read it (after 30 s) or on our five-minute tick, whichever comes first.

POST /v1/price-requests needs an Idempotency-Key in test mode too. Send a fresh one for each scenario you try: test_scenario is not part of what the key remembers, so reusing a key replays the first answer.

GET /v1/prices/changes

| Value | Result | |---|---| | withdrawn_since | exactly one fixed price.withdrawn event |

Test webhooks

An endpoint registered with a test key (or created as test in the dashboard) receives only test-mode events, signed the same way as live ones. Use Send test event in the dashboard to check your signature verification without waiting for anything to happen.

API reference · Dashboard · Questions: hello@wellwardhealth.com