Quickstart
The API follows a three-step asynchronous pattern. Each step below is shown on its own so you can copy, run, and inspect the response before moving on. For a full end-to-end client with retries and error handling, see Code Examples.
- Create Search —
POST /v1/searches - Poll Status —
GET /v1/searches/:id - Download Parquet shards —
GETeach URL indownload_urls
Set KEEPER_API_KEY in your environment before running the snippets below.
Not sure what to pass for
payerandplan? Use List Payers and List Plans to enumerate the exact strings the API accepts. The values are matched exactly — a typo silently returns zero rows.
1. Submit a search
Returns a job_id and status: "queued". Save the job_id — you'll use it in step 2.
curl -X POST https://api.keeperhealth.com/v1/searches \
-H "Authorization: Bearer $KEEPER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"npis": [1144218512],
"billing_codes": ["99213", "99214"],
"fee_schedules": [{"payer": "Cigna", "plan": "PPO"}]
}'2. Check status
Call this every 15–30 seconds until status is "completed" or "failed" — see polling cadence. When complete, the response includes a download_urls array.
curl https://api.keeperhealth.com/v1/searches/$JOB_ID \
-H "Authorization: Bearer $KEEPER_API_KEY"3. Download each Parquet shard
download_urls is always an array — iterate it even for single-file results. The URLs are pre-signed; do not attach the Authorization header.
# Assuming you saved the step 2 response to status.json:
i=0
jq -r '.download_urls[]' status.json | while read -r url; do
curl -o "results-$i.parquet" "$url"
i=$((i + 1))
doneOnce you've downloaded the Parquet shards, load them as a single dataset with pandas (pd.read_parquet(paths)), DuckDB, pyarrow, or any reader that accepts a list of files. See the Reimbursement Data Schema for column definitions.
See also
- List Payers / List Plans — discover valid
payerandplanstrings before building your first request - Create Search — full request body, headers, and
Idempotency-Keysupport - Get Search Status — job state machine and terminal states
- Code Examples — complete polling loops with error handling in cURL, Python, JavaScript/TypeScript, and Go
- Rate Limits — recommended polling cadence (15–30 seconds)
- Errors — how to read error responses and what's retry-safe