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