tmpt
Mint a valid tmpt anti-bot token for a target site, ready to replay.
We drive the whole token flow behind your proxy and hand back the cookie value plus the
browser identity it was minted for. Replay both together.
Mint a token
POST
/api/captcha/tmpt
tmpt
→ request
{
"proxy": "http://user:pass@host:port",
"target": "https://www.eticketing.co.uk",
"action": "Event"
}
← response
{
"success": true,
"token": "Oeqx…",
"session_id": "a1b2c3…",
"fingerprint": { /* see below */ }
}
Request body
| Field | Type | | Description |
proxy | string | required |
Proxy used to mint the token, as http://user:pass@host:port or http://host:port. Replay the token through this same proxy. |
target | string | required |
The site the token is for, e.g. https://www.eticketing.co.uk. Origin and host are derived from it. url is accepted as an alias. |
action | string | optional |
Flow action. Defaults to LoginPage; Event is the other common one. |
user_agent | string | optional |
Mint the token for this exact User-Agent. The sec_ch_ua* hints are derived from it unless you send them explicitly. Omit it and a random desktop profile is used. |
sec_ch_ua | string | optional |
Pin Sec-CH-UA instead of deriving it. |
sec_ch_ua_platform | string | optional |
Pin Sec-CH-UA-Platform, e.g. "Windows", "macOS". |
sec_ch_ua_mobile | string | optional |
Pin Sec-CH-UA-Mobile, e.g. ?0. |
accept_language | string | optional |
Pin Accept-Language, e.g. en-US,en;q=0.9. |
site_key | string | optional |
reCAPTCHA site key. Defaults to the standard eps site key. sitekey is accepted as an alias. |
Success response
{
"success": true,
"token": "Oeqx…the-tmpt-cookie-value…",
"session_id": "a1b2c3…",
"fingerprint": {
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) … Chrome/148.0.0.0 Safari/537.36",
"accept_language": "en-US,en;q=0.9",
"sec_ch_ua": "\"Chromium\";v=\"148\", \"Google Chrome\";v=\"148\", \"Not/A)Brand\";v=\"99\"",
"sec_ch_ua_mobile": "?0",
"sec_ch_ua_platform": "\"Windows\""
}
}
| Field | Description |
token | The value to set as the tmpt cookie on your request to the target. |
session_id | The eps session id bound to the token (informational). |
fingerprint | The browser identity the token was minted for. Replay these exact headers with it. |
Replay the token
On your request to target, send the cookie tmpt=<token> together
with the user_agent, accept_language and sec_ch_ua*
values exactly as returned in fingerprint — and through the same proxy.
A token replayed under a different identity is a token wasted.
# mint
curl -X POST https://api.antibot.primeseats.dev/api/captcha/tmpt \
-H "X-License-Key: tmpt_live_xxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"proxy": "http://user:pass@host:port",
"target": "https://www.eticketing.co.uk",
"action": "Event"
}'
Pin an identity
Currently not honoured. Tokens are minted by a real browser, and the
token only stays valid under that browser's User-Agent and client hints: a
token replayed under a different identity yields a cookie the target rejects. The
identity fields below are still accepted for compatibility, but the response
fingerprint is authoritative — switch your session to it after every
mint (User-Agent, sec-ch-ua*, accept-language).
{
"proxy": "http://user:pass@host:port",
"target": "https://www.eticketing.co.uk",
"action": "Event",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36",
"sec_ch_ua": "\"Chromium\";v=\"148\", \"Google Chrome\";v=\"148\", \"Not/A)Brand\";v=\"99\"",
"sec_ch_ua_platform": "\"macOS\"",
"sec_ch_ua_mobile": "?0",
"accept_language": "en-US,en;q=0.9"
}
reCAPTCHA v3 token
Ask for just the reCAPTCHA v3 token and run the rest yourself. No proxy is needed; the
token is valid for about two minutes and is not bound to an IP. Costs one solve, like
/api/captcha/tmpt. Two kinds of site key are supported, picked with the
enterprise field.
| Field | Type | | Description |
target | string | required |
Page URL the key is used on. The token is minted for its hostname. |
action | string | optional |
The action string the site passes to reCAPTCHA. Defaults to LoginPage. |
enterprise | boolean | optional |
true (default) for reCAPTCHA Enterprise keys such as Ticketmaster's; false for a plain v3 key loaded from api.js?render=<key>. |
site_key | string | optional |
The site key. Defaults to the eps key for Enterprise; required when enterprise is false. |
POST
/api/captcha/recaptcha
tmpt
→ request · plain v3 key
{
"target": "https://example.com/login",
"site_key": "6Lc…",
"action": "login",
"enterprise": false
}
← response
{
"success": true,
"token": "0cAFcWeA…",
"fingerprint": { /* identity the token was minted under */ }
}
Send the token to the site's own verify endpoint, with the same fingerprint
if it cares about the browser identity. The same optional identity fields as above
(user_agent and the client hints) are accepted; fingerprint
echoes either your pinned identity or the browser identity the token was minted under.
For a Ticketmaster-family site, leave enterprise out: GET /eps-mgr
on the target, then POST /epsf/gec/v3/<action> with
{"hostname","key","token"} on the same session, and the tmpt
cookie comes back on the response.
BotDeflect
Solve queue-it BotDeflector challenges. You keep the session, we do the compute.
BotDeflector is queue-it's newer challenge system, separate from the older
/challengeapi/… challenges. A softblock page hands you a flow JWT pointing at
dual.challenge.queue-it.net, which serves a chain of sub-challenges declared
inside that token. Each solved sub-challenge returns a token; the tokens are exchanged for
a ChallengeFlowResult, which the site's own verify endpoint accepts.
These endpoints are compute-only. They make no outbound requests — you
fetch the challenge and post the verify yourself, so your proxy, TLS fingerprint and header
order stay exactly as you built them. We only run the part that costs CPU: the cuckoo-cycle
search and the icon matching.
The flow
Decode botDeflectorJwtToken from the softblock page and walk its
challengeFlow array in order. Flow type inv maps to the
pow endpoint, icon to icon.
-
1
you
GET dual.challenge.queue-it.net/{endpoint}/get
Send x-tt-flow-token: <flow JWT>. Returns a
challengeToken — itself a JWT carrying the challenge parameters.
-
2
this api
POST /api/botdeflect/pow · POST /api/botdeflect/icon
Hand us the challengeToken (and, for icon, the two images).
You get the solution back in milliseconds.
-
3
you
POST dual.challenge.queue-it.net/{endpoint}/verify
Post the solution together with the challengeToken and the
flow token. Returns a solution token. Repeat 1–3 for every step in the flow.
-
4
you
GET dual.challenge.queue-it.net/verify-flow
Send every solution token in x-tt-solution-tokens, comma-joined,
in the order the flow declared them. Returns the ChallengeFlowResult.
-
5
you
POST {queue-domain}/…/challenge/botdeflector/verify
Hand the flow result to the site's own verify endpoint. Returns the
sessionInfo you carry into the queue re-entry as scv.
Proof of work
Flow type inv. A cuckoo-cycle search over a graph seeded by the
challenge session.
POST
/api/botdeflect/pow
botdeflect
→ request
{
"challenge_token": "eyJhbGciOi…"
}
← response
{
"success": true,
"solution": [
{ "challenge": "9f3c…",
"edgeIndices": [812,1907,44,3311,77,2560] }
],
"params": {
"NODES_BITS": 12, "EDGES_BITS": 13,
"CYCLE_LENGTH": 6, "GRAPH_SEED": "c8f4…"
},
"time": "0.002",
"solve_ms": 2
}
Request body
| Field | Type | | Description |
challenge_token | string | required* |
The challengeToken from /pow/get. We read the challenge hashes, the params and the session id (which seeds the graph) straight off it. Only the payload is decoded — the signature is never touched. |
challenges | string[] | optional |
Solve these challenge hashes instead of the token's. Hex. |
params | object | optional |
Override individual graph parameters: NODES_BITS, EDGES_BITS, CYCLE_LENGTH, GRAPH_SEED. Anything you omit falls back to the token, then to the defaults 12 / 13 / 6. |
* challenge_token or challenges — one of the two.
Explicit fields always win over the token.
Response
| Field | Description |
solution | The solution array /pow/verify expects, verbatim — one closed cycle per challenge hash, in the order given. |
params | The merged parameters the solution was computed against, GRAPH_SEED included. Send this back in the verify body — the verifier rebuilds the graph from it, and a mismatch fails the check. |
time | Solve duration in seconds, pre-formatted for the verify body's time field. |
solve_ms | The same duration in milliseconds (informational). |
Building the verify body
{
"solution": // from our response
"params": // from our response, verbatim
"time": // from our response
"solution_fingerprint": "<your FingerprintJS visitorId>",
"challengeToken": "<from /pow/get>",
"challengeFlowToken": "<the flow JWT>"
}
Icon challenge
Flow type icon. Find each of the icons from the strip inside the
background image, in strip order.
Fetch both images yourself using lib, img and ico from
the icon challengeToken payload:
/icons/{lib}/bgnd/{img} and /icons/{lib}/ico/{ico}. Send us the
bytes, base64-encoded.
POST
/api/botdeflect/icon
botdeflect
→ request
{
"background": "iVBORw0KGgoAAAANS…",
"icons": "iVBORw0KGgoAAAANS…"
}
← response
{
"success": true,
"solution": [
{ "x": 66, "y": 60 },
{ "x": 167, "y": 127 },
{ "x": 245, "y": 53 }
],
"solve_ms": 1
}
Request body
| Field | Type | | Description |
background | string | required |
The background image bytes, base64. A data:image/png;base64,… prefix is accepted. |
icons | string | required |
The icon strip bytes, base64. Its transparency defines the icons and their order. |
The body cap on this route is 4 MiB, which fits both images comfortably.
Response
solution holds one point per strip icon, in strip order — that is
the order the answer must be given in. Coordinates are pixels in the background image.
When the background cannot be segmented into one region per strip icon you get
success: false with a 200. Re-request the challenge rather than
guessing: a wrong click is a stronger bot signal than a slow one.
Do not send solve_ms as the verify body's time.
We solve an icon challenge in about a millisecond; a human needs seconds to find and click
three icons. Report a plausible duration instead — the reference implementation uses a
random 4500–9500 ms — or it becomes the most obvious tell in the payload.
Building the verify body
{
"solution": // from our response
"time": 6420, // milliseconds, human-plausible — NOT solve_ms
"solution_fingerprint": "<your FingerprintJS visitorId>",
"challengeToken": "<from /icon/get>",
"challengeFlowToken": "<the flow JWT>"
}
Worked example
One proof-of-work step, end to end.
# 1. ask the challenge host for a challenge
curl 'https://dual.challenge.queue-it.net/pow/get' \
-H "x-tt-flow-token: $FLOW_TOKEN"
# -> {"challengeToken":"eyJhbGciOi…"}
# 2. solve it here
curl -X POST https://api.antibot.primeseats.dev/api/botdeflect/pow \
-H "X-License-Key: tmpt_live_xxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"challenge_token":"eyJhbGciOi…"}'
# -> {"success":true,"solution":[…],"params":{…},"time":"0.002"}
# 3. verify it, from your own session
curl -X POST 'https://dual.challenge.queue-it.net/pow/verify' \
-H "Content-Type: application/json" \
-d '{
"solution": […],
"params": {…},
"time": "0.002",
"solution_fingerprint": "'"$FINGERPRINT"'",
"challengeToken": "eyJhbGciOi…",
"challengeFlowToken": "'"$FLOW_TOKEN"'"
}'
# -> {"token":"…"} — collect it, then move to the next flow step