> For the complete documentation index, see [llms.txt](https://docs.apexsolutions.lol/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.apexsolutions.lol/captchafox/workflow.md).

# Integration Workflow

The end-to-end CaptchaFox integration: identify the site key, solve, and validate the token.

The step-by-step implementation of the CaptchaFox flow. Each step describes what to do and why, with the actual requests against Apex. The full request and response reference lives in the **API reference**.

## Step 1: Identify the site key

Find the CaptchaFox site key on the protected page. It appears in the widget configuration or the page source as a public key starting with `sk_`:

```
sk_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d
```

The site key is tied to the site it was issued for, so use the one from the page you are solving — a key from another site will not work.

## Step 2: Build the solve

Call Apex with the page URL, the site key, and your sticky proxy. The proxy is required on every solve — the solver always routes through your proxy:

{% tabs %}
{% tab title="Go" %}

```go
package main

import (
	"bytes"
	"encoding/json"
	"net/http"
)

func main() {
	body, _ := json.Marshal(map[string]any{
		"params": map[string]any{
			"url":      "https://{target}",
			"site_key": "sk_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
		},
		"proxy": "http://user:pass@host:port",
	})

	req, _ := http.NewRequest("POST", "https://captchafox.apexsolutions.lol/payload", bytes.NewReader(body))
	req.Header.Set("Authorization", "Bearer your-api-key")
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
}
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

resp = requests.post(
    "https://captchafox.apexsolutions.lol/payload",
    headers={"Authorization": "Bearer your-api-key"},
    json={
        "params": {
            "url": "https://{target}",
            "site_key": "sk_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
        },
        "proxy": "http://user:pass@host:port",
    },
)

print(resp.status_code, resp.json())
```

{% endtab %}

{% tab title="JS/TS" %}

```jsts
const resp = await fetch("https://captchafox.apexsolutions.lol/payload", {
  method: "POST",
  headers: {
    "Authorization": "Bearer your-api-key",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    params: {
      url: "https://{target}",
      site_key: "sk_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
    },
    proxy: "http://user:pass@host:port",
  }),
});

const data = await resp.json();
console.log(data);
```

{% endtab %}
{% endtabs %}

The response gives you the `token` under `result`.

## Step 3: Validate the token on the backend

Your client submits the token to the site's own API that guards the action (signup, login, etc.). The site backend validates it with CaptchaFox via siteverify:

```python
import requests

# Send the token to the site's API, not to CaptchaFox directly.
resp = requests.post(
    "https://{target}/api/signup",
    json={"captchafoxToken": token},
)
print(resp.status_code, resp.json())
```

The site's backend performs the siteverify call — you do not need the organization secret (`ok_...`); the site keeps it server-side.

## Important Notes

{% hint style="info" %}
**Tokens are single-use and short-lived.** If a solve is rejected, the token was probably already consumed or expired — solve again. The `site_key` must belong to the page you are solving, and the token must be submitted to the site that owns that key.
{% endhint %}
