> 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/forter/workflow.md).

# Integration Workflow

The end-to-end Forter integration: solve, submit the flushes, and replay the session.

The step-by-step implementation of the Forter 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: Extract the site ID and seed

GET the protected page with your Chrome TLS client and locate the Forter snippet. The values you need are in the script tag — its `id` is the site ID and `window.ftr__config.s` is the seed:

```
<script type="text/javascript" id="{site_id}">
  ...
  var siteId = '{site_id}';
  window.ftr__config = { m: { csp: false }, s: "{seed}", si: siteId };
  ...
script>
```

Two regexes over the HTML are enough to pull them:

```
import re

html = open("page.html").read()

site_id = re.search(r'<script[^>]+id="([0-9a-f]+)"', html).group(1)
seed = re.search(r'ftr__config = \{.*?s: "([^"]+)"', html, re.S).group(1)

print(site_id, seed)
```

Replace the `{site_id}` and `{seed}` placeholders with the values of YOUR target — each merchant has its own, and using another site’s values will not work.

## Step 2: Build the session

Call Apex to build the session. Send the page details, your sticky proxy, and your real Chrome-on-Windows User-Agent. The `user_agent` is required — Apex builds the fingerprint for exactly that UA:

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

```go
package main

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

func main() {
	body, _ := json.Marshal(map[string]string{
		"site_id":    "{site_id}",
		"seed":       "{seed}",
		"page_url":   "{page_url}",
		"referrer":   "{referrer}",
		"proxy":      "http://user:pass@host:port",
		"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.6778.86 Safari/537.36",
	})

	req, _ := http.NewRequest("POST", "https://forter.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://forter.apexsolutions.lol/payload",
    headers={"Authorization": "Bearer your-api-key"},
    json={
        "site_id": "{site_id}",
        "seed": "{seed}",
        "page_url": "{page_url}",
        "referrer": "{referrer}",
        "proxy": "http://user:pass@host:port",
        "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.6778.86 Safari/537.36",
    },
)

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

{% endtab %}

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

```jsts
const resp = await fetch("https://forter.apexsolutions.lol/payload", {
  method: "POST",
  headers: {
    "Authorization": "Bearer your-api-key",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    site_id: "{site_id}",
    seed: "{seed}",
    page_url: "{page_url}",
    referrer: "{referrer}",
    proxy: "http://user:pass@host:port",
    user_agent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.6778.86 Safari/537.36",
  }),
});

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

{% endtab %}
{% endtabs %}

The response gives you the encrypted payloads, the ping targets, and the token material (the full response is documented in the API reference). Keep the `session_id` — you need it to get the second payload.

## Step 3: Submit the first payload and the pings

Using your own HTTP client bound to the same proxy and TLS profile, decode the hex payload and POST it as raw binary, then send the ping targets:

```python
import requests, binascii

# bind your client to the same sticky proxy / TLS profile as the solve
s = requests.Session()

flush = response["flush"]
s.post(flush["url"], data=binascii.unhexlify(flush["payload_hex"]),
       headers={"Content-Type": flush["content_type"]})

s.post(response["wpt"]["url"], json=response["wpt"]["body"])

for url in response["prop_urls"]:
    s.get(url)
```

Everything goes to Forter’s CDN. Missing any piece, or sending it from a different IP, is the most common reason a session never validates.

## Step 4: Generate and submit the second payload

Wait a short delay — a real user does not interact instantly — then call Apex for the second payload:

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

```go
req, _ := http.NewRequest("POST", "https://forter.apexsolutions.lol/flush", bytes.NewBufferString(`{"session_id": "{session_id}"}`))
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://forter.apexsolutions.lol/flush",
    headers={"Authorization": "Bearer your-api-key"},
    json={"session_id": "{session_id}"},
)

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

{% endtab %}

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

```jsts
const resp = await fetch("https://forter.apexsolutions.lol/flush", {
  method: "POST",
  headers: {
    "Authorization": "Bearer your-api-key",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    session_id: "{session_id}",
  }),
});

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

{% endtab %}
{% endtabs %}

Submit the returned payload exactly as you did the first one.

## Step 5: Attach the tokens and access

On your final requests, attach the `cookie` value as the `forterToken` cookie and the `f_sdk_c` value as the `f-sdk-c` header, all through the same proxy:

```python
import requests

s = requests.Session()
s.cookies.set("forterToken", response["cookie"])
headers = {"f-sdk-c": response["f_sdk_c"]}

s.get("https://{target}/protected", headers=headers)
```

## Important Notes

{% hint style="info" %}
**Order and consistency.** The steps must run in order and on the same proxy and TLS client. A session is valid about **3 minutes** and for **5 flushes**; it can only be flushed by the API key that created it. If a flush is rejected, check that the hex was decoded to raw binary, the exact content type was used, and the same proxy/TLS was used throughout.
{% endhint %}
