Generate Kasada headers with cURL
Create a KasadaTask, wait for ready, then send the entire solution.headers object with the returned browser identity through the same proxy. Standalone Kasada currently supports HTTPS targets on www.ticketmaster.com.
On this page
Create, poll and submit with cURL
The script requires Bash, cURL 7.76 or later, jq and openssl. Set SOLVETHREE_API_KEY to your workspace API key and SOLVETHREE_PROXY to your HTTP or HTTPS proxy URL. Keep the API key server-side and shell tracing off.
This example uses one proxy throughout. A Kasada request requires type, url and exactly one of proxy or proxyCandidates; it must not include reCAPTCHA fields such as site or action, a session, or custom browser identity fields. See the Kasada request contract.
#!/usr/bin/env bash
set -euo pipefail
: "${SOLVETHREE_API_KEY:?Set the API key}" "${SOLVETHREE_PROXY:?Set the proxy}"
# Requires bash, curl, jq and openssl. Do not enable shell tracing.
work=$(mktemp -d)
chmod 700 "$work"
trap 'rm -rf "$work"' EXIT
request_id=$(openssl rand -hex 16)
printf 'Recovery requestId=%s\n' "$request_id"
printf 'Authorization: Bearer %s\n' "$SOLVETHREE_API_KEY" > "$work/auth"
jq -n --arg proxy "$SOLVETHREE_PROXY" --arg id "$request_id" '{"type":"KasadaTask","url":"https://www.ticketmaster.com/","proxy":$proxy,"requestId":$id}' > "$work/input.json"
api='https://api.solvethree.com/v1'
curl --fail-with-body --silent --show-error --max-time 30 \
--header @"$work/auth" --header 'Content-Type: application/json' \
--data-binary @"$work/input.json" --output "$work/result.json" "$api/tasks?waitMs=0"
task_id=$(jq -er '.id' "$work/result.json")
encoded_id=$(jq -nr --arg id "$task_id" '$id|@uri')
printf 'Recovery taskId=%s\n' "$task_id"
deadline=$((SECONDS + 180))
while [[ $(jq -r '.status' "$work/result.json") =~ ^(pending|solving)$ ]]; do
remaining=$((deadline - SECONDS))
(( remaining > 0 )) || { echo 'Local deadline reached; resume the saved task ID' >&2; exit 1; }
timeout=$((remaining < 25 ? remaining : 25))
curl --fail-with-body --silent --show-error --max-time "$timeout" \
--header @"$work/auth" --output "$work/result.json" "$api/tasks/$encoded_id?waitMs=15000"
[[ $(jq -r '.status' "$work/result.json") =~ ^(pending|solving)$ ]] && sleep 1 || true
done
[[ $(jq -r '.status' "$work/result.json") == ready ]] || { echo 'Solver task failed' >&2; exit 1; }
user_agent=$(jq -er '.solution.userAgent' "$work/result.json")
client_hints=$(jq -er '.solution.secChUa' "$work/result.json")
jq -r '.solution.headers | to_entries[] | "\(.key): \(.value)"' "$work/result.json" > "$work/target-headers"
curl --silent --show-error --max-time 30 --proxy "$SOLVETHREE_PROXY" \
--header @"$work/target-headers" --user-agent "$user_agent" \
--header "sec-ch-ua: $client_hints" --output "$work/target-response" \
--write-out 'Target HTTP %{http_code}\n' 'https://www.ticketmaster.com/'
# Inspect the application's response before treating the operation as successful.
# Replace the example target path with the actual supported workflow URL.Replace the example target URL in both the task body and the final cURL call with the intended supported workflow URL. Don't solve for one URL and submit the result to an unrelated target.
The script authenticates with a Bearer header, creates one task and polls only its returned ID. Creation has a 30-second request timeout; polling uses a 180-second local deadline and bounded GET requests. These are script limits, not solve-time guarantees. No automatic retries or redirect following are enabled.
Apply the whole header object
pending and solving mean keep polling. Only ready contains a usable solution. The script reads the raw solution.headers object with jq and converts every entry into a header-file line; it doesn't select a single header or treat the task ID as the solution.
The final request loads that header file, sets solution.userAgent and solution.secChUa, and uses the original proxy. Keep these values together rather than substituting your usual browser headers.
API responses, generated headers and the target response stay in a private temporary directory rather than being printed. Keep them out of routine logs, and don't enable shell tracing.
Recover the task instead of creating another
Save the printed recovery IDs. Rerunning the script generates a new requestId; it isn't a recovery attempt. To recover creation, reuse the saved request ID with exactly the original task inputs. The script deletes its input file on exit, so retain those inputs securely if you need to reconstruct the request.
- The POST times out before a task ID is returned.
A connection timeout doesn't prove task creation failed.
Try this: Submit the same task request with the saved requestId. Identical inputs recover the existing task; changing the inputs while reusing that ID conflicts.
- The local polling deadline expires.
Use the printed task ID to check whether the existing task is still pending or solving.
Try this: Resume GET polling for that ID with another finite deadline. Don't create a replacement merely because the local wait ended.
- An API request returns a non-success HTTP response.
The API calls use --fail-with-body, so cURL exits before the script reads a success payload.
Try this: For diagnostics, add an HTTP-error handler that examines the saved response body privately before cleanup. Correct the reported request problem rather than blindly retrying unchanged inputs.
- The task reaches failed.
The example prints a generic failure message; the response also contains errorCode and error.
Try this: Inspect those fields in the failure branch before cleanup, then stop polling that task. Use the reported cause to decide what to change. Failed solves are refunded.
Sources and API reference
Run your first task.
Start with $5 in workspace credit.