Shape API Reference
Get Shape Security headers for one protected request.
The Captcha.fun Shape API accepts kind, url, challengeHtml, protectedUrl and returns Shape request headers. Send the API_KEY header, create a solve with POST /v1/request, then poll GET /v2/response/{id} until ready is true.
What you’ll need
- Your API key
- The URL of the page where the challenge appears
challengeHtml— Captured HTML of the page that loads Shape’s sensorprotectedUrl— Endpoint the headers are for. Replay them on a request to exactly this URL- A proxy, if the result must come from your own IP (
shape_proxy)
Good to Know
The Shape product replays the page that loads Shape's sensor (ssx.mod.js or an inline equivalent), lets the sensor arm, then fires a request against your protected endpoint from the browser and harvests the Shape headers off the wire.
Shape headers are URL-bound — they encode the request URL into their telemetry — so one solve produces one replayable header set for exactly the endpoint you pass in protectedUrl. Mint a fresh header set per protected endpoint.
A few gateways reject synthetic captures at the app layer; the solver detects those protected URLs and drives the site's real sign-in UI to mint the set instead.
Send the Challenge
Send the page details with your API key. You get a solve id back right away.
https://api.captcha.fun/v1/requestcurl -X POST https://api.captcha.fun/v1/request \
-H "API_KEY: CAPFUN-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"kind": "shape",
"url": "https://your-domain.example/login",
"challengeHtml": "<CAPTURED_LOGIN_PAGE_HTML>",
"protectedUrl": "https://your-domain.example/api/login"
}'import requests
response = requests.post(
"https://api.captcha.fun/v1/request",
headers={
"API_KEY": "CAPFUN-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"Content-Type": "application/json",
"Accept": "application/json",
},
json={"kind": "shape", "url": "https://your-domain.example/login", "challengeHtml": "<CAPTURED_LOGIN_PAGE_HTML>", "protectedUrl": "https://your-domain.example/api/login"},
)
print(response.status_code, response.json())const response = await fetch("https://api.captcha.fun/v1/request", {
method: "POST",
headers: {
"API_KEY": "CAPFUN-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"Content-Type": "application/json",
"Accept": "application/json"
},
body: JSON.stringify({
"kind": "shape",
"url": "https://your-domain.example/login",
"challengeHtml": "<CAPTURED_LOGIN_PAGE_HTML>",
"protectedUrl": "https://your-domain.example/api/login"
})
});
console.log(response.status, await response.json());Response
Returns the solve id. Use it to get the result.
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"message": "Started Solving"
}{
"message": "invalid kind"
}Request fields6 body fields · 4 required
Wait for the Result
Use the solve id to fetch the result.
https://api.captcha.fun/v2/response/{id}Poll every second until ready is true.
https://api.captcha.fun/v1/response/{id}Long polling: the request stays open until the solve finishes or times out. Send it once and wait.
Example
curl -X GET https://api.captcha.fun/v2/response/550e8400-e29b-41d4-a716-446655440000 \
-H "API_KEY: CAPFUN-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
-H "Accept: application/json"import requests
response = requests.get(
"https://api.captcha.fun/v2/response/550e8400-e29b-41d4-a716-446655440000",
headers={
"API_KEY": "CAPFUN-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"Accept": "application/json"
}
)
print(response.status_code, response.json())const response = await fetch(
"https://api.captcha.fun/v2/response/550e8400-e29b-41d4-a716-446655440000",
{
method: "GET",
headers: {
"API_KEY": "CAPFUN-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"Accept": "application/json"
}
}
);
const data = await response.json();
console.log(response.status, data);package main
import (
"encoding/json"
"fmt"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.captcha.fun/v2/response/550e8400-e29b-41d4-a716-446655440000", nil)
req.Header.Set("API_KEY", "CAPFUN-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
req.Header.Set("Accept", "application/json")
client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()
var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
fmt.Println(resp.StatusCode, result)
}import java.net.http.*;
import java.net.URI;
public class Main {
public static void main(String[] args) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.captcha.fun/v2/response/550e8400-e29b-41d4-a716-446655440000"))
.header("API_KEY", "CAPFUN-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
.header("Accept", "application/json")
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode() + " " + response.body());
}
}using System.Net.Http;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("API_KEY", "CAPFUN-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
client.DefaultRequestHeaders.Add("Accept", "application/json");
var response = await client.GetAsync("https://api.captcha.fun/v2/response/550e8400-e29b-41d4-a716-446655440000");
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine($"{(int)response.StatusCode} {result}");Response
{
"ready": true,
"status": "SUCCESS",
"success": true,
"userAgent": "RETURNED_USER_AGENT",
"secUa": "RETURNED_SEC_CH_UA",
"token": "",
"headers": {
"x-6a7b8c-a": "0:0:0:0:1:2:3:...",
"x-6a7b8c-b": "1:1:1:...",
"x-6a7b8c-f": "abc123..."
}
}{
"message": "API_KEY Header Missing"
}Example
curl -X GET https://api.captcha.fun/v1/response/550e8400-e29b-41d4-a716-446655440000 \
-H "API_KEY: CAPFUN-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
-H "Accept: application/json"import requests
response = requests.get(
"https://api.captcha.fun/v1/response/550e8400-e29b-41d4-a716-446655440000",
headers={
"API_KEY": "CAPFUN-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"Accept": "application/json"
}
)
print(response.status_code, response.json())const response = await fetch(
"https://api.captcha.fun/v1/response/550e8400-e29b-41d4-a716-446655440000",
{
method: "GET",
headers: {
"API_KEY": "CAPFUN-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"Accept": "application/json"
}
}
);
const data = await response.json();
console.log(response.status, data);package main
import (
"encoding/json"
"fmt"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.captcha.fun/v1/response/550e8400-e29b-41d4-a716-446655440000", nil)
req.Header.Set("API_KEY", "CAPFUN-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
req.Header.Set("Accept", "application/json")
client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()
var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
fmt.Println(resp.StatusCode, result)
}import java.net.http.*;
import java.net.URI;
public class Main {
public static void main(String[] args) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.captcha.fun/v1/response/550e8400-e29b-41d4-a716-446655440000"))
.header("API_KEY", "CAPFUN-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
.header("Accept", "application/json")
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode() + " " + response.body());
}
}using System.Net.Http;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("API_KEY", "CAPFUN-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
client.DefaultRequestHeaders.Add("Accept", "application/json");
var response = await client.GetAsync("https://api.captcha.fun/v1/response/550e8400-e29b-41d4-a716-446655440000");
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine($"{(int)response.StatusCode} {result}");Response
{
"status": "SUCCESS",
"success": true,
"userAgent": "RETURNED_USER_AGENT",
"secUa": "RETURNED_SEC_CH_UA",
"token": "",
"headers": {
"x-6a7b8c-a": "0:0:0:0:1:2:3:...",
"x-6a7b8c-b": "1:1:1:...",
"x-6a7b8c-f": "abc123..."
}
}{
"message": "API_KEY Header Missing"
}Request and response fields7 response fields
Replay the Request
- Send one outbound request to exactly protectedUrl with every returned header set verbatim, and the returned userAgent as your User-Agent header.
- Replay the set from the same egress IP as the solve, with the returned userAgent as your User-Agent header — the headers are bound to the solving browser's identity.
When using a successful result, preserve the returned userAgent as User-Agent and secUa as Sec-CH-UA.
Wrong or rejected result? Report the failed solve.