Code Examples
End-to-end examples of the three-step async workflow: create a search via POST /v1/searches, poll GET /v1/searches/{job_id} until complete, then download each Parquet shard in the download_urls array. Pick the language that matches your stack using the tabs below. Each example paces its polling loop to the recommended 15–30 second cadence and handles both completed and failed terminal states.
#!/bin/bash
set -e
API_KEY="${KEEPER_API_KEY:?set KEEPER_API_KEY in your environment}"
BASE="https://api.keeperhealth.com"
# 1. Create the search job
JOB_ID=$(curl -s -X POST "$BASE/v1/searches" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"npis": [1144218512],
"billing_codes": ["99213", "99214"],
"fee_schedules": [{"payer":"Cigna","plan":"PPO"}]
}' | jq -r '.job_id')
echo "Job created: $JOB_ID"
# 2. Poll until terminal state (completed or failed).
# 15 attempts × 20 seconds = 5 minute cap, well inside the recommended
# 15-30s polling cadence.
for attempt in $(seq 1 15); do
STATUS=$(curl -s -H "Authorization: Bearer $API_KEY" \
"$BASE/v1/searches/$JOB_ID")
STATE=$(echo "$STATUS" | jq -r '.status')
echo "Attempt $attempt: $STATE"
if [ "$STATE" = "completed" ]; then
# `download_urls` is always an array — iterate every shard.
i=0
echo "$STATUS" | jq -r '.download_urls[]' | while read -r url; do
curl -o "results-$i.parquet" "$url"
i=$((i + 1))
done
echo "Results saved as results-*.parquet"
exit 0
elif [ "$STATE" = "failed" ]; then
REASON=$(echo "$STATUS" | jq -r '.error')
echo "Job failed: $REASON" >&2
exit 1
fi
sleep 20
done
echo "Timed out waiting for job" >&2
exit 1See also
- Create Search — field reference, hard per-request limits, and
Idempotency-Keyheader - Get Search Status — full job state machine, terminal states, and response shapes
- Reimbursement Data Schema — columns in each downloaded shard
- Rate Limits — polling cadence and
Retry-Afterhandling - Errors — error envelope and retry-safe taxonomy
- Authentication — how to set
KEEPER_API_KEYand rotate it safely