Your first run
Sign up, top up and create an API key in the dashboard when access is available. Then run these five steps in one Bash session. There is no sandbox: creating runs spends real balance.
1. Configure the confirmed API host and key
Bash · curl + jq
# Sign up in the API dashboard, top up by card (minimum $5), then mint an API key.
# The dashboard/production API URL will be supplied at onboarding.
# API keys cannot create keys or read billing; those require a signed-in session.
export PINEAPI_BASE_URL='<confirmed API origin>'
read -r -s PINEAPI_KEY
export PINEAPI_KEY
# Requires curl, jq and uuidgen. Paid requests start in step 3.2. Read the accepted filters
Bash · curl + jq
curl --fail-with-body "$PINEAPI_BASE_URL/v1/catalogs/locations" \
-H "Authorization: Bearer $PINEAPI_KEY"
# Also read industries, schools, experience-bands and company-headcounts as needed.3. Create one paid search
Bash · curl + jq
# Up to 100 delivered profiles: $1.20. A completed empty search costs $0.12.
# Keep the key and body unchanged if retrying this request.
IDEMPOTENCY_KEY=$(uuidgen)
RUN_ID=$(curl --fail-with-body "$PINEAPI_BASE_URL/v1/profile-searches" \
-H "Authorization: Bearer $PINEAPI_KEY" \
-H "Idempotency-Key: $IDEMPOTENCY_KEY" \
-H 'Content-Type: application/json' \
-d '{"locations":["Spain"],"current_job_titles":["Data Engineer"],"max_items":100}' | jq -er '.run_id') || exit 1
printf '%s\n' "$RUN_ID" # Save this ID to resume polling later.4. Poll until the run ends
Bash · curl + jq
STARTED=$SECONDS
while true; do
RUN=$(curl --fail-with-body "$PINEAPI_BASE_URL/v1/runs/$RUN_ID" \
-H "Authorization: Bearer $PINEAPI_KEY") || exit 1
STATUS=$(printf '%s' "$RUN" | jq -r '.status')
case "$STATUS" in
succeeded|partial) printf '%s\n' "$RUN"; break ;;
failed|cancelled) printf '%s\n' "$RUN"; exit 1 ;;
queued|starting|running|processing) ;;
*) printf 'Unexpected status: %s\n' "$STATUS"; exit 1 ;;
esac
if (( SECONDS - STARTED >= 1800 )); then
printf 'Polling paused; resume with run_id %s\n' "$RUN_ID"; exit 1
fi
if (( SECONDS - STARTED < 60 )); then sleep 5; else sleep 20; fi
done
# HTTP errors stop this example. On 429 wait Retry-After before resuming.5. Read every page
Bash · curl + jq
CURSOR=''
while true; do
PAGE=$(curl --fail-with-body --get "$PINEAPI_BASE_URL/v1/runs/$RUN_ID/profiles" \
-H "Authorization: Bearer $PINEAPI_KEY" \
--data-urlencode 'limit=50' --data-urlencode "cursor=$CURSOR") || exit 1
printf '%s' "$PAGE" | jq '.data[]'
[ "$(printf '%s' "$PAGE" | jq -r '.has_more')" = true ] || break
CURSOR=$(printf '%s' "$PAGE" | jq -er '.next_cursor') || exit 1
done