Back to Documentation

TLS API Examples: Twitter Guest Token Flow

Step-by-step guide to using the TLS API for Twitter guest and flow tokens

This guide provides a multi-step example of how to use the TLS API to perform a common flow: obtaining a guest token and flow token from api.x.com (Twitter).

This flow demonstrates how to:

  • Make initial POST requests to get tokens
  • Pass required authorization and client headers
  • Use the output from one request (like the guest_token) as an input for the next request

Step 1: Get Guest Token

This first request activates a guest session and returns a guest_token.

Request (POST /tls)

{
  "url": "https://api.x.com/1.1/guest/activate.json",
  "method": "POST",
  "headers": {
    "sec-ch-ua-platform": "\"Windows\"",
    "authorization": "Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA",
    "sec-ch-ua": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
    "x-twitter-client-language": "en",
    "sec-ch-ua-mobile": "?0",
    "x-twitter-active-user": "yes",
    "x-client-transaction-id": "",
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
    "accept": "*/*",
    "origin": "https://x.com",
    "sec-fetch-site": "same-site",
    "sec-fetch-mode": "cors",
    "sec-fetch-dest": "empty",
    "referer": "https://x.com/",
    "accept-encoding": "gzip, deflate, br, zstd",
    "accept-language": "en-US,en;q=0.9"
  },
  "timeout": 80,
  "json": {}
}

Expected Output: The response text will be a JSON string. Parse this string to extract the guest_token value.


Step 2: Get Flow Token

Using the guest_token from Step 1 in the headers, this request initiates a signup flow to get a flow_token.

Request (POST /tls)

{
  "url": "https://api.x.com/1.1/onboarding/task.json?flow_name=signup",
  "method": "POST",
  "headers": {
    "sec-ch-ua-platform": "\"Windows\"",
    "authorization": "Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA",
    "sec-ch-ua": "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
    "x-twitter-client-language": "en",
    "sec-ch-ua-mobile": "?0",
    "x-twitter-active-user": "yes",
    "x-client-transaction-id": "",
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
    "accept": "*/*",
    "origin": "https://x.com",
    "sec-fetch-site": "same-site",
    "x-guest-token": "<guest_token_from_step_1>",
    "sec-fetch-mode": "cors",
    "sec-fetch-dest": "empty",
    "referer": "https://x.com/",
    "accept-encoding": "gzip, deflate, br, zstd",
    "accept-language": "en-US,en;q=0.9"
  },
  "timeout": 60,
  "json": {
    "input_flow_data": {
      "flow_context": {
        "debug_overrides": {},
        "start_location": {
          "location": "manual_link"
        }
      }
    },
    "subtask_versions": {
      "action_list": 2,
      "alert_dialog": 1,
      "app_download_cta": 1,
      "check_logged_in_account": 1,
      "choice_selection": 3,
      "contacts_live_sync_permission_prompt": 0,
      "cta": 7,
      "email_verification": 2,
      "end_flow": 1,
      "enter_date": 1,
      "enter_email": 2,
      "enter_password": 5,
      "enter_phone": 2,
      "enter_recaptcha": 1,
      "enter_text": 5,
      "enter_username": 2,
      "generic_urt": 3,
      "in_app_notification": 1,
      "interest_picker": 3,
      "js_instrumentation": 1,
      "menu_dialog": 1,
      "notifications_permission_prompt": 2,
      "open_account": 2,
      "open_home_timeline": 1,
      "open_link": 1,
      "phone_verification": 4,
      "privacy_options": 1,
      "security_key": 3,
      "select_avatar": 4,
      "select_banner": 2,
      "settings_list": 7,
      "show_code": 1,
      "sign_up": 2,
      "sign_up_review": 4,
      "tweet_selection_urt": 1,
      "update_users": 1,
      "upload_media": 1,
      "user_recommendations_list": 4,
      "user_recommendations_urt": 1,
      "wait_spinner": 3,
      "web_modal": 1
    }
  }
}

Expected Output: The response text will contain the new flow data. Parse this JSON to extract the flow_token.


Step 3: Begin Verification (Send Castle Token)

This request submits user details and a castle_token (which you must obtain separately) to proceed with verification, using both the guest_token and the flow_token.

Request (POST /tls)

{
  "url": "https://api.x.com/1.1/onboarding/begin_verification.json",
  "method": "POST",
  "headers": {
    "sec-ch-ua-platform": "\"Windows\"",
    "authorization": "Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA",
    "sec-ch-ua": "\"Google Chrome\";v=\"142\", \"Not?A_Brand\";v=\"99\", \"Chromium\";v=\"142\"",
    "x-twitter-client-language": "en",
    "sec-ch-ua-mobile": "?0",
    "x-twitter-active-user": "yes",
    "x-client-transaction-id": "",
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36",
    "accept": "*/*",
    "origin": "https://x.com",
    "sec-fetch-site": "same-site",
    "x-guest-token": "<guest_token_from_step_1>",
    "sec-fetch-mode": "cors",
    "sec-fetch-dest": "empty",
    "referer": "https://x.com/",
    "accept-encoding": "gzip, deflate, br, zstd",
    "accept-language": "<your_accept_lang>"
  },
  "timeout": 60,
  "json": {
    "email": "<YOUR_EMAIL>",
    "display_name": "<YOUR_NAME>",
    "castle_token": "<your_castle_token>",
    "flow_token": "<flow_token_from_step_2>"
  }
}

Expected Output: The response will contain verification results and next steps for onboarding.


Ready to use python script

import requests
import json
import random
import string

# Fake info generator
def generate_fake_email():
    username = ''.join(random.choices(string.ascii_lowercase + string.digits, k=10))
    domains = ['gmail.com', 'yahoo.com', 'outlook.com']
    return f"{username}@{random.choice(domains)}"

def generate_fake_name():
    first_names = ['John', 'Jane', 'Bob', 'Alice', 'Charlie', 'Diana', 'Eve', 'Frank', 'Grace', 'Henry']
    last_names = ['Doe', 'Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Garcia', 'Miller', 'Davis', 'Wilson']
    return random.choice(first_names) + ' ' + random.choice(last_names)

# Function to make TLS bypassed request via castlebreaker
def make_tls_request(target_url, method='POST', headers=None, json_data=None, proxy=None, timeout=60):
    if headers is None:
        headers = {}
    tls_url = "https://castlebreaker.cc/tls"
    tls_payload = {
        "url": target_url,
        "method": method,
        "headers": headers,
        "json": json_data or {}
    }
    if proxy:
        tls_payload["proxy"] = proxy  # Optional proxy support
    response = requests.post(tls_url, json=tls_payload, timeout=timeout)
    if response.status_code == 200:
        return response.json()
    else:
        raise Exception(f"TLS request failed: {response.status_code} - {response.text}")

# Main script
if __name__ == "__main__":
    # Step 1: Fetch castle data
    print("Fetching castle token...")
    castle_url = "https://castlebreaker.cc/getCastleTokenProxyless"
    castle_response = requests.get(castle_url)
    castle_data = castle_response.json()
    
    if castle_data.get('status') != 'success':
        raise Exception("Failed to fetch castle token")
    
    data = castle_data['data']
    castle_token = data['castle_token']
    accept_lang = data['accept_lang']
    sec_ch_ua = data['sec_ch_ua']
    user_agent = data['user_agent']
    cid = data['cid']  # Not sure if needed, but captured
    
    print(f"Castle token fetched: {castle_token[:20]}...")

    # Base headers updated with castle data
    base_headers = {
        "sec-ch-ua-platform": "\"Windows\"",
        "authorization": "Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA",
        "sec-ch-ua": sec_ch_ua,
        "x-twitter-client-language": "en",
        "sec-ch-ua-mobile": "?0",
        "x-twitter-active-user": "yes",
        "x-client-transaction-id": "",
        "user-agent": user_agent,
        "accept": "*/*",
        "origin": "https://x.com",
        "sec-fetch-site": "same-site",
        "sec-fetch-mode": "cors",
        "sec-fetch-dest": "empty",
        "referer": "https://x.com/",
        "accept-encoding": "gzip, deflate, br, zstd",
        "accept-language": accept_lang
    }

    # Step 2: Get guest token
    print("Getting guest token...")
    guest_url = "https://api.x.com/1.1/guest/activate.json"
    guest_data = make_tls_request(guest_url, headers=base_headers, json_data={}, timeout=80)
    guest_token = guest_data.get('guest_token')
    if not guest_token:
        raise Exception("Failed to get guest token")
    print(f"Guest token: {guest_token}")

    # Step 3: Get flow token
    print("Getting flow token...")
    flow_url = "https://api.x.com/1.1/onboarding/task.json?flow_name=signup"
    flow_headers = base_headers.copy()
    flow_headers["x-guest-token"] = guest_token
    
    flow_json = {
        "input_flow_data": {
            "flow_context": {
                "debug_overrides": {},
                "start_location": {
                    "location": "manual_link"
                }
            }
        },
        "subtask_versions": {
            "action_list": 2,
            "alert_dialog": 1,
            "app_download_cta": 1,
            "check_logged_in_account": 1,
            "choice_selection": 3,
            "contacts_live_sync_permission_prompt": 0,
            "cta": 7,
            "email_verification": 2,
            "end_flow": 1,
            "enter_date": 1,
            "enter_email": 2,
            "enter_password": 5,
            "enter_phone": 2,
            "enter_recaptcha": 1,
            "enter_text": 5,
            "enter_username": 2,
            "generic_urt": 3,
            "in_app_notification": 1,
            "interest_picker": 3,
            "js_instrumentation": 1,
            "menu_dialog": 1,
            "notifications_permission_prompt": 2,
            "open_account": 2,
            "open_home_timeline": 1,
            "open_link": 1,
            "phone_verification": 4,
            "privacy_options": 1,
            "security_key": 3,
            "select_avatar": 4,
            "select_banner": 2,
            "settings_list": 7,
            "show_code": 1,
            "sign_up": 2,
            "sign_up_review": 4,
            "tweet_selection_urt": 1,
            "update_users": 1,
            "upload_media": 1,
            "user_recommendations_list": 4,
            "user_recommendations_urt": 1,
            "wait_spinner": 3,
            "web_modal": 1
        }
    }
    
    flow_data = make_tls_request(flow_url, headers=flow_headers, json_data=flow_json, timeout=60)
    flow_token = flow_data.get('flow_token')
    if not flow_token:
        raise Exception("Failed to get flow token")
    print(f"Flow token: {flow_token[:20]}...")

    # Step 4: Generate fake info and send to begin verification
    print("Generating fake info...")
    fake_email = generate_fake_email()
    fake_name = generate_fake_name()
    print(f"Fake email: {fake_email}")
    print(f"Fake name: {fake_name}")

    verify_url = "https://api.x.com/1.1/onboarding/begin_verification.json"
    verify_headers = base_headers.copy()
    verify_headers["x-guest-token"] = guest_token

    verify_json = {
        "email": fake_email,
        "display_name": fake_name,
        "castle_token": castle_token,
        "flow_token": flow_token
    }

    # Optional proxy - set proxy_var = "http://your-proxy:port" if needed, else None
    proxy_var = None  # Change this if you have a proxy

    print("Sending verification request...")
    verify_response = make_tls_request(verify_url, headers=verify_headers, json_data=verify_json, proxy=proxy_var, timeout=60)
    print("Verification response:")
    print(json.dumps(verify_response, indent=2))