> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sorsa.io/llms.txt
> Use this file to discover all available pages before exploring further.

# ID 转换

在 X（原 Twitter）用户名、数字用户 ID 和个人资料 URL 之间转换。三个轻量工具端点，每次转换消耗一次请求。新账号有 100 次免费请求，无需信用卡，可立即开始。

> **注意：** 用户名、用户 ID 和个人资料链接的完整说明见博客上的 [Twitter ID 转换器：用户名、用户 ID 与资料链接](https://api.sorsa.io/blog/twitter-id-converter)。

> **无代码方案：** 单次转换可使用免费的 [Sorsa ID 转换器](https://api.sorsa.io/playground/id-converter)。粘贴用户名、ID 或资料 URL 即可立即得到结果，无需 API 密钥。

***

## 为什么用户 ID 很重要？

用户名可随时更改，释放后还可能被他人注册。数字用户 ID 在账号创建时分配，此后不会改变。构建存储或引用 X 账号的系统时，应使用用户 ID：

* **改名不会破坏系统。** 无论用户改名多少次，ID 始终指向同一账号。
* **保留完整 ID。** 在 JSON 和 JavaScript 中将 ID 作为字符串。如果数据库使用整数列，请确认范围足够且不会丢失精度。
* **跨时间数据关联更可靠。** 将不同时期收集的数据集匹配时，ID 是唯一可靠的键。
* **部分端点基于 ID。** `/info-batch` 接受 `user_ids` 数组，也支持 `usernames`；列表和社群端点通过数字 ID 引用目标。

## 用户 ID 的格式

X 使用 Snowflake ID：把时间戳、机器 ID 和序列号打包为一个 64 位整数。推文 ID 自 2010 年起使用此格式。

用户 ID 不同。Snowflake 推出后，X 仍多年采用顺序整数账号 ID，约在 2020 年才转为 Snowflake。因此旧账号 ID 较短，例如 Jack Dorsey 的账号为 `12`，而 2020 年后创建的账号有 19 位 ID。实际影响是无法从旧用户 ID 解码创建时间。需要旧账号注册日期时，应获取资料并读取 `created_at`。

***

## 端点 1：用户名转用户 ID

```http theme={null}
GET /v3/username-to-id/{user_handle}
```

将不含 `@` 的用户名转换为永久数字用户 ID。

```bash theme={null}
curl "https://api.sorsa.io/v3/username-to-id/elonmusk" \
  -H "ApiKey: YOUR_API_KEY"
```

```json theme={null}
{"id": "44196397"}
```

```python theme={null}
import requests

API_KEY = "YOUR_API_KEY"

def username_to_id(handle: str) -> str:
    resp = requests.get(
        f"https://api.sorsa.io/v3/username-to-id/{handle}",
        headers={"ApiKey": API_KEY},
    )
    resp.raise_for_status()
    return resp.json()["id"]

print(username_to_id("elonmusk"))  # "44196397"
```

```javascript theme={null}
async function usernameToId(handle) {
  const resp = await fetch(
    `https://api.sorsa.io/v3/username-to-id/${handle}`,
    { headers: { "ApiKey": "YOUR_API_KEY" } }
  );
  return (await resp.json()).id;
}
```

## 端点 2：用户 ID 转用户名

```http theme={null}
GET /v3/id-to-username/{user_id}
```

将数字用户 ID 解析为当前用户名。适合让存储的 ID 更易读，或检查账号自上次查询后是否改名。

```bash theme={null}
curl "https://api.sorsa.io/v3/id-to-username/44196397" \
  -H "ApiKey: YOUR_API_KEY"
```

```json theme={null}
{"handle": "elonmusk"}
```

```python theme={null}
def id_to_username(user_id: str) -> str:
    resp = requests.get(
        f"https://api.sorsa.io/v3/id-to-username/{user_id}",
        headers={"ApiKey": API_KEY},
    )
    resp.raise_for_status()
    return resp.json()["handle"]
```

## 端点 3：资料链接转用户 ID

```http theme={null}
GET /v3/link-to-id?link={profile_url}
```

从完整资料 URL 提取永久用户 ID。处理电子表格、书签或抓取页面中的链接时，可将它们统一为 ID。

```bash theme={null}
curl "https://api.sorsa.io/v3/link-to-id?link=https://x.com/elonmusk" \
  -H "ApiKey: YOUR_API_KEY"
```

```json theme={null}
{"id": "44196397"}
```

```python theme={null}
def link_to_id(profile_url: str) -> str:
    resp = requests.get(
        "https://api.sorsa.io/v3/link-to-id",
        headers={"ApiKey": API_KEY},
        params={"link": profile_url},
    )
    resp.raise_for_status()
    return resp.json()["id"]
```

> **提示：** 如果同时需要 ID 和完整资料，可以跳过转换，直接通过 `username` 参数调用 [`/info`](https://docs.sorsa.io/zh-Hans/api-reference/users-data/user-profile)。一次请求即可返回包括 `id` 的完整资料。更多方式见[优化 API 使用](https://docs.sorsa.io/zh-Hans/optimizing-api-usage)。

***

## 常见用法

### 批量转换

如果有一组用户名，例如 CRM 导出、竞争对手列表或电子表格，需要全部转换为 ID：

```python theme={null}
import requests
import time

API_KEY = "YOUR_API_KEY"
BASE = "https://api.sorsa.io/v3"
HEADERS = {"ApiKey": API_KEY}


def batch_username_to_id(handles, pause=0.05):
    """
    Resolve a list of handles to user IDs.
    Returns: dict mapping handle -> id (or None if lookup failed).
    """
    results = {}
    for handle in handles:
        handle = handle.strip().lstrip("@")
        try:
            resp = requests.get(f"{BASE}/username-to-id/{handle}", headers=HEADERS, timeout=10)
            if resp.status_code == 200:
                results[handle] = resp.json()["id"]
            elif resp.status_code == 404:
                results[handle] = None  # Account does not exist or is suspended
            elif resp.status_code == 429:
                time.sleep(1)
                retry = requests.get(f"{BASE}/username-to-id/{handle}", headers=HEADERS, timeout=10)
                results[handle] = retry.json()["id"] if retry.status_code == 200 else None
            else:
                results[handle] = None
        except requests.RequestException:
            results[handle] = None
        time.sleep(pause)
    return results


handles = ["NASA", "SpaceX", "Tesla", "OpenAI", "stripe"]
id_map = batch_username_to_id(handles)

for handle, uid in id_map.items():
    print(f"@{handle} -> {uid or '(not found)'}")
```

反向转换方式相同：将 URL 替换为 `/id-to-username/{user_id}`，并读取响应的 `handle` 字段。可用于刷新显示名称可能过时的数据库。

### 统一混合输入

用户以用户名、URL 或 ID 等不同形式提交账号时，应统一转换为用户 ID。以下检查在输入已是 ID 时完全跳过 API 调用：

```python theme={null}
def normalize_to_id(value: str) -> str:
    """
    Accepts a handle, an @handle, a profile URL, or a numeric ID.
    Returns the numeric user ID.
    """
    value = value.strip().lstrip("@")

    if value.isdigit():
        return value

    if "x.com/" in value or "twitter.com/" in value:
        return link_to_id(value)

    return username_to_id(value)


# All four return the same ID
for source in ["elonmusk", "@elonmusk", "https://x.com/elonmusk", "44196397"]:
    print(normalize_to_id(source))
```

将其作为数据采集管道的第一步，使下游始终使用稳定标识符。

### 检测用户名变更

如果采集时同时保存 ID 和用户名，可定期重新解析 ID，发现改名账号：

```python theme={null}
def detect_renames(records):
    """
    records: list of {"user_id": str, "stored_handle": str}
    Returns: list of accounts that have renamed.
    """
    changes = []
    for record in records:
        try:
            current = id_to_username(record["user_id"])
        except requests.HTTPError:
            continue  # Deleted, suspended, or transient error

        if current and current.lower() != record["stored_handle"].lower():
            changes.append({
                "user_id": record["user_id"],
                "old_handle": record["stored_handle"],
                "new_handle": current,
            })
        time.sleep(0.05)
    return changes
```

需要更完整的审计时，[`/about`](https://docs.sorsa.io/zh-Hans/api-reference/users-data/account-about-info) 返回 `username_change_count` 和 `last_username_change_at`，不仅能了解当前用户名，还能知道累计改名次数和最近一次变更时间。

***

## 后续步骤

* [粉丝与关注](https://docs.sorsa.io/zh-Hans/followers-and-following)：多数粉丝提取工作流从 ID 转换开始
* [受众地理分布](https://docs.sorsa.io/zh-Hans/Audience-Geography)：`/about` 接受 `user_id`，返回国家数据和用户名变更历史
* [优化 API 使用](https://docs.sorsa.io/zh-Hans/optimizing-api-usage)：需要完整资料时直接使用 `/info`，避免多余转换
* [API 参考](https://docs.sorsa.io/zh-Hans/api-reference-guide)：`/username-to-id`、`/id-to-username`、`/link-to-id` 及全部端点的完整规范
