Các điểm cuối trên trang này
GET /v1/residential/subscriptions: Liệt kê gói lưu lượng (proxy dân cư và proxy di động xoay vòng tính theo GB)GET /v1/residential/subscriptions/{subscriptionId}: Lấy gói proxy dân cưPATCH /v1/residential/subscriptions/{subscriptionId}: Đổi tên hoặc bật/tắt tự động gia hạnPOST /v1/residential/subscriptions/{subscriptionId}/reset-password: Tạo mật khẩu proxy mới cho người dùng chínhGET /v1/residential/subscriptions/{subscriptionId}/usage: Mức sử dụng lưu lượng hằng ngàyGET /v1/residential/subscriptions/{subscriptionId}/sub-users: Liệt kê người dùng phụ (thông tin đăng nhập proxy riêng với giới hạn lưu lượng riêng)POST /v1/residential/subscriptions/{subscriptionId}/sub-users: Tạo người dùng phụPATCH /v1/residential/subscriptions/{subscriptionId}/sub-users/{subUserId}: Cập nhật người dùng phụ (nhãn, giới hạn, bật/tắt, mật khẩu mới)DELETE /v1/residential/subscriptions/{subscriptionId}/sub-users/{subUserId}: Xóa người dùng phụGET /v1/catalog/countries: Các quốc gia có sản phẩmGET /v1/catalog/countries/{countryCode}/states: Các bang / tỉnh có thể nhắm mục tiêu trong một quốc gia (US, CA, AU…)GET /v1/catalog/countries/{countryCode}/cities: Các thành phố có thể nhắm mục tiêu trong một quốc giaGET /v1/catalog/countries/{countryCode}/asns: Các ISP có thể nhắm mục tiêu (ASN) trong một quốc gia — chỉ proxy dân cư
URL cơ sở https://localserpproxy.com/api/v1. Xem phần Tổng quan API] để biết về xác thực, lỗi và giới hạn.
Phiên cố định
Thêm -session-{id}-ttl-{minutes} vào tên người dùng proxy để giữ nguyên IP: {id} là 1–32 chữ cái hoặc chữ số tùy chọn, ttl là 1–30 phút. IP có thể thay đổi sớm hơn, chẳng hạn khi thiết bị phía sau ngắt kết nối.
Liệt kê gói lưu lượng (proxy dân cư và proxy di động xoay vòng tính theo GB)
GET/v1/residential/subscriptions
Xác thực: khóa API trong tiêu đề Authorization: Bearer API_KEY.
Tham số
| Tên | Trong | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|---|
productId | query | residential · mobile-gb | Không | Chỉ sản phẩm này (không có: cả hai). |
Phản hồi 200 OK
{
"data": [
{
"id": "res_9x2m4k",
"productId": "residential",
"label": "Residential #1",
"planId": "res-10",
"status": "active",
"trafficTotalBytes": 10000000000,
"trafficUsedBytes": 2350000000,
"trafficRemainingBytes": 7650000000,
"expiresAt": null,
"autoRenew": false,
"username": "u7k2m9",
"password": "PASSWORD",
"endpoint": {
"host": "gw.localserpproxy.com",
"httpPort": 7777,
"socksPort": 7778
},
"subUserCount": 1,
"createdAt": "2026-10-05T14:03:11Z"
}
]
}Ví dụ mã
curl -s "https://localserpproxy.com/api/v1/residential/subscriptions" \
-H "Authorization: Bearer $API_KEY"import os
import requests
API = "https://localserpproxy.com/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['API_KEY']}"}
r = requests.get(f"{API}/residential/subscriptions", headers=HEADERS, timeout=30)
r.raise_for_status()
print(r.json())// Node.js 18+ (built-in fetch), ES module
const API = 'https://localserpproxy.com/api/v1';
const res = await fetch(`${API}/residential/subscriptions`, {
headers: { Authorization: `Bearer ${process.env.API_KEY}` },
});
if (!res.ok) throw new Error((await res.json()).error?.message ?? `HTTP ${res.status}`);
console.log(await res.json());Lấy gói proxy dân cư
GET/v1/residential/subscriptions/{subscriptionId}
Xác thực: khóa API trong tiêu đề Authorization: Bearer API_KEY.
Tham số
| Tên | Trong | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|---|
subscriptionId | path | string | Có | — |
Phản hồi 200 OK
{
"id": "res_9x2m4k",
"productId": "residential",
"label": "Residential #1",
"planId": "res-10",
"status": "active",
"trafficTotalBytes": 10000000000,
"trafficUsedBytes": 2350000000,
"trafficRemainingBytes": 7650000000,
"expiresAt": null,
"autoRenew": false,
"username": "u7k2m9",
"password": "PASSWORD",
"endpoint": {
"host": "gw.localserpproxy.com",
"httpPort": 7777,
"socksPort": 7778
},
"subUserCount": 1,
"createdAt": "2026-10-05T14:03:11Z"
}Ví dụ mã
curl -s "https://localserpproxy.com/api/v1/residential/subscriptions/res_9x2m4k" \
-H "Authorization: Bearer $API_KEY"import os
import requests
API = "https://localserpproxy.com/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['API_KEY']}"}
r = requests.get(f"{API}/residential/subscriptions/res_9x2m4k", headers=HEADERS, timeout=30)
r.raise_for_status()
print(r.json())// Node.js 18+ (built-in fetch), ES module
const API = 'https://localserpproxy.com/api/v1';
const res = await fetch(`${API}/residential/subscriptions/res_9x2m4k`, {
headers: { Authorization: `Bearer ${process.env.API_KEY}` },
});
if (!res.ok) throw new Error((await res.json()).error?.message ?? `HTTP ${res.status}`);
console.log(await res.json());Đổi tên hoặc bật/tắt tự động gia hạn
PATCH/v1/residential/subscriptions/{subscriptionId}
Xác thực: khóa API trong tiêu đề Authorization: Bearer API_KEY.
Tham số
| Tên | Trong | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|---|
subscriptionId | path | string | Có | — |
Nội dung yêu cầu
| Trường | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|
label | string | Không | tối đa 60 ký tự |
autoRenew | boolean | Không | — |
{
"label": "Price monitoring",
"autoRenew": true
}Phản hồi 200 OK
{
"id": "res_9x2m4k",
"productId": "residential",
"label": "Residential #1",
"planId": "res-10",
"status": "active",
"trafficTotalBytes": 10000000000,
"trafficUsedBytes": 2350000000,
"trafficRemainingBytes": 7650000000,
"expiresAt": null,
"autoRenew": false,
"username": "u7k2m9",
"password": "PASSWORD",
"endpoint": {
"host": "gw.localserpproxy.com",
"httpPort": 7777,
"socksPort": 7778
},
"subUserCount": 1,
"createdAt": "2026-10-05T14:03:11Z"
}Ví dụ mã
curl -s -X PATCH "https://localserpproxy.com/api/v1/residential/subscriptions/res_9x2m4k" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"label":"Price monitoring","autoRenew":true}'import os
import requests
API = "https://localserpproxy.com/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['API_KEY']}"}
r = requests.patch(f"{API}/residential/subscriptions/res_9x2m4k", headers=HEADERS, json={"label": "Price monitoring", "autoRenew": True}, timeout=30)
r.raise_for_status()
print(r.json())// Node.js 18+ (built-in fetch), ES module
const API = 'https://localserpproxy.com/api/v1';
const res = await fetch(`${API}/residential/subscriptions/res_9x2m4k`, {
method: 'PATCH',
headers: { Authorization: `Bearer ${process.env.API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ label: 'Price monitoring', autoRenew: true }),
});
if (!res.ok) throw new Error((await res.json()).error?.message ?? `HTTP ${res.status}`);
console.log(await res.json());Tạo mật khẩu proxy mới cho người dùng chính
POST/v1/residential/subscriptions/{subscriptionId}/reset-password
Mật khẩu cũ sẽ ngừng hoạt động tại cổng trong vòng 60 giây.
Xác thực: khóa API trong tiêu đề Authorization: Bearer API_KEY.
Tham số
| Tên | Trong | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|---|
subscriptionId | path | string | Có | — |
Phản hồi 200 OK
{
"id": "res_9x2m4k",
"productId": "residential",
"label": "Residential #1",
"planId": "res-10",
"status": "active",
"trafficTotalBytes": 10000000000,
"trafficUsedBytes": 2350000000,
"trafficRemainingBytes": 7650000000,
"expiresAt": null,
"autoRenew": false,
"username": "u7k2m9",
"password": "PASSWORD",
"endpoint": {
"host": "gw.localserpproxy.com",
"httpPort": 7777,
"socksPort": 7778
},
"subUserCount": 1,
"createdAt": "2026-10-05T14:03:11Z"
}Ví dụ mã
curl -s -X POST "https://localserpproxy.com/api/v1/residential/subscriptions/res_9x2m4k/reset-password" \
-H "Authorization: Bearer $API_KEY"import os
import requests
API = "https://localserpproxy.com/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['API_KEY']}"}
r = requests.post(f"{API}/residential/subscriptions/res_9x2m4k/reset-password", headers=HEADERS, timeout=30)
r.raise_for_status()
print(r.json())// Node.js 18+ (built-in fetch), ES module
const API = 'https://localserpproxy.com/api/v1';
const res = await fetch(`${API}/residential/subscriptions/res_9x2m4k/reset-password`, {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.API_KEY}` },
});
if (!res.ok) throw new Error((await res.json()).error?.message ?? `HTTP ${res.status}`);
console.log(await res.json());Mức sử dụng lưu lượng hằng ngày
GET/v1/residential/subscriptions/{subscriptionId}/usage
Xác thực: khóa API trong tiêu đề Authorization: Bearer API_KEY.
Tham số
| Tên | Trong | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|---|
subscriptionId | path | string | Có | — |
from | query | string (date) | Không | Ngày đầu tiên (UTC), tính cả ngày đó. Mặc định = 29 ngày trước to. |
to | query | string (date) | Không | Ngày cuối cùng (UTC), tính cả ngày đó. Mặc định = hôm nay. Khoảng thời gian tối đa là 366 ngày. |
subUserId | query | string | Không | Giới hạn ở một người dùng phụ. |
Phản hồi 200 OK
{
"from": "2026-10-04",
"to": "2026-10-05",
"totalBytes": 2350000000,
"totalRequests": 48210,
"points": [
{
"date": "2026-10-04",
"bytes": 1200000000,
"requests": 24800
},
{
"date": "2026-10-05",
"bytes": 1150000000,
"requests": 23410
}
],
"byCountry": [
{
"country": "US",
"bytes": 2350000000
}
]
}Ví dụ mã
curl -s "https://localserpproxy.com/api/v1/residential/subscriptions/res_9x2m4k/usage" \
-H "Authorization: Bearer $API_KEY"import os
import requests
API = "https://localserpproxy.com/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['API_KEY']}"}
r = requests.get(f"{API}/residential/subscriptions/res_9x2m4k/usage", headers=HEADERS, timeout=30)
r.raise_for_status()
print(r.json())// Node.js 18+ (built-in fetch), ES module
const API = 'https://localserpproxy.com/api/v1';
const res = await fetch(`${API}/residential/subscriptions/res_9x2m4k/usage`, {
headers: { Authorization: `Bearer ${process.env.API_KEY}` },
});
if (!res.ok) throw new Error((await res.json()).error?.message ?? `HTTP ${res.status}`);
console.log(await res.json());Danh sách người dùng phụ (thông tin đăng nhập proxy riêng với giới hạn lưu lượng riêng)
GET/v1/residential/subscriptions/{subscriptionId}/sub-users
Xác thực: khóa API trong tiêu đề Authorization: Bearer API_KEY.
Tham số
| Tên | Trong | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|---|
subscriptionId | path | string | Có | — |
Phản hồi 200 OK
{
"data": [
{
"id": "sub_3m9qk2",
"label": "Client A",
"username": "u7k2m9_scraper",
"password": "PASSWORD",
"trafficLimitBytes": 5000000000,
"trafficUsedBytes": 1200000000,
"enabled": true,
"createdAt": "2026-10-05T14:03:11Z"
}
],
"limit": 50
}Ví dụ mã
curl -s "https://localserpproxy.com/api/v1/residential/subscriptions/res_9x2m4k/sub-users" \
-H "Authorization: Bearer $API_KEY"import os
import requests
API = "https://localserpproxy.com/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['API_KEY']}"}
r = requests.get(f"{API}/residential/subscriptions/res_9x2m4k/sub-users", headers=HEADERS, timeout=30)
r.raise_for_status()
print(r.json())// Node.js 18+ (built-in fetch), ES module
const API = 'https://localserpproxy.com/api/v1';
const res = await fetch(`${API}/residential/subscriptions/res_9x2m4k/sub-users`, {
headers: { Authorization: `Bearer ${process.env.API_KEY}` },
});
if (!res.ok) throw new Error((await res.json()).error?.message ?? `HTTP ${res.status}`);
console.log(await res.json());Tạo người dùng phụ
POST/v1/residential/subscriptions/{subscriptionId}/sub-users
Xác thực: khóa API trong tiêu đề Authorization: Bearer API_KEY.
Tham số
| Tên | Trong | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|---|
subscriptionId | path | string | Có | — |
Nội dung yêu cầu
| Trường | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|
label | string | Có | tối đa 60 ký tự |
password | string | Không | Tự tạo nếu để trống. — tối đa 64 ký tự |
trafficLimitBytes | integer (int64), nullable | Không | ≥ 0 |
{
"label": "Scraper EU",
"trafficLimitBytes": 5000000000
}Phản hồi 201 Created
{
"id": "sub_3m9qk2",
"label": "Client A",
"username": "u7k2m9_scraper",
"password": "PASSWORD",
"trafficLimitBytes": 5000000000,
"trafficUsedBytes": 1200000000,
"enabled": true,
"createdAt": "2026-10-05T14:03:11Z"
}Ví dụ mã
curl -s -X POST "https://localserpproxy.com/api/v1/residential/subscriptions/res_9x2m4k/sub-users" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"label":"Scraper EU","trafficLimitBytes":5000000000}'import os
import requests
API = "https://localserpproxy.com/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['API_KEY']}"}
r = requests.post(f"{API}/residential/subscriptions/res_9x2m4k/sub-users", headers=HEADERS, json={"label": "Scraper EU", "trafficLimitBytes": 5000000000}, timeout=30)
r.raise_for_status()
print(r.json())// Node.js 18+ (built-in fetch), ES module
const API = 'https://localserpproxy.com/api/v1';
const res = await fetch(`${API}/residential/subscriptions/res_9x2m4k/sub-users`, {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ label: 'Scraper EU', trafficLimitBytes: 5000000000 }),
});
if (!res.ok) throw new Error((await res.json()).error?.message ?? `HTTP ${res.status}`);
console.log(await res.json());Cập nhật người dùng phụ (nhãn, giới hạn, bật/tắt, mật khẩu mới)
PATCH/v1/residential/subscriptions/{subscriptionId}/sub-users/{subUserId}
Xác thực: khóa API trong tiêu đề Authorization: Bearer API_KEY.
Tham số
| Tên | Trong | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|---|
subscriptionId | path | string | Có | — |
subUserId | path | string | Có | — |
Nội dung yêu cầu
| Trường | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|
label | string | Không | tối đa 60 ký tự |
trafficLimitBytes | integer (int64), nullable | Không | ≥ 0 |
enabled | boolean | Không | — |
regeneratePassword | boolean | Không | — |
{
"enabled": false
}Phản hồi 200 OK
{
"id": "sub_3m9qk2",
"label": "Client A",
"username": "u7k2m9_scraper",
"password": "PASSWORD",
"trafficLimitBytes": 5000000000,
"trafficUsedBytes": 1200000000,
"enabled": true,
"createdAt": "2026-10-05T14:03:11Z"
}Ví dụ mã
curl -s -X PATCH "https://localserpproxy.com/api/v1/residential/subscriptions/res_9x2m4k/sub-users/sub_3m9qk2" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"enabled":false}'import os
import requests
API = "https://localserpproxy.com/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['API_KEY']}"}
r = requests.patch(f"{API}/residential/subscriptions/res_9x2m4k/sub-users/sub_3m9qk2", headers=HEADERS, json={"enabled": False}, timeout=30)
r.raise_for_status()
print(r.json())// Node.js 18+ (built-in fetch), ES module
const API = 'https://localserpproxy.com/api/v1';
const res = await fetch(`${API}/residential/subscriptions/res_9x2m4k/sub-users/sub_3m9qk2`, {
method: 'PATCH',
headers: { Authorization: `Bearer ${process.env.API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ enabled: false }),
});
if (!res.ok) throw new Error((await res.json()).error?.message ?? `HTTP ${res.status}`);
console.log(await res.json());Xóa người dùng phụ
DELETE/v1/residential/subscriptions/{subscriptionId}/sub-users/{subUserId}
Xác thực: khóa API trong tiêu đề Authorization: Bearer API_KEY.
Tham số
| Tên | Trong | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|---|
subscriptionId | path | string | Có | — |
subUserId | path | string | Có | — |
Phản hồi 204 No Content
Không có nội dung yêu cầu: mã trạng thái là câu trả lời.
Ví dụ mã
curl -s -X DELETE "https://localserpproxy.com/api/v1/residential/subscriptions/res_9x2m4k/sub-users/sub_3m9qk2" \
-H "Authorization: Bearer $API_KEY"import os
import requests
API = "https://localserpproxy.com/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['API_KEY']}"}
r = requests.delete(f"{API}/residential/subscriptions/res_9x2m4k/sub-users/sub_3m9qk2", headers=HEADERS, timeout=30)
r.raise_for_status()
print(r.status_code) # 204: done// Node.js 18+ (built-in fetch), ES module
const API = 'https://localserpproxy.com/api/v1';
const res = await fetch(`${API}/residential/subscriptions/res_9x2m4k/sub-users/sub_3m9qk2`, {
method: 'DELETE',
headers: { Authorization: `Bearer ${process.env.API_KEY}` },
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
console.log(res.status); // 204: doneCác quốc gia có sản phẩm
GET/v1/catalog/countries
Công khai: không cần khóa API.
Tham số
| Tên | Trong | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|---|
product | query | string | Không | Chỉ áp dụng cho các địa điểm có sản phẩm này (residential, mobile, mobile-gb). |
Phản hồi 200 OK
{
"data": [
{
"code": "US",
"name": "United States",
"region": "Americas",
"products": [
"residential",
"mobile",
"mobile-gb"
],
"cities": 6,
"asns": 4,
"carriers": 3
}
]
}Ví dụ mã
curl -s "https://localserpproxy.com/api/v1/catalog/countries"import os
import requests
API = "https://localserpproxy.com/api/v1"
r = requests.get(f"{API}/catalog/countries", timeout=30)
r.raise_for_status()
print(r.json())// Node.js 18+ (built-in fetch), ES module
const API = 'https://localserpproxy.com/api/v1';
const res = await fetch(`${API}/catalog/countries`);
if (!res.ok) throw new Error((await res.json()).error?.message ?? `HTTP ${res.status}`);
console.log(await res.json());Các tiểu bang / tỉnh có thể nhắm mục tiêu trong một quốc gia (US, CA, AU…)
GET/v1/catalog/countries/{countryCode}/states
Giá trị của phần tên người dùng -state-{state}. Danh sách trống với các quốc gia không hỗ trợ nhắm mục tiêu theo tiểu bang. Không liệt kê mã ZIP: phần -zip-{zip} chấp nhận mọi mã ZIP 5 chữ số của US; gateway sẽ trả về trang lỗi nếu không có IP thoát phù hợp.
Công khai: không cần khóa API.
Tham số
| Tên | Trong | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|---|
countryCode | path | string | Có | ISO 3166-1 alpha-2, viết hoa. |
Phản hồi 200 OK
{
"data": [
{
"id": "ny",
"code": "NY",
"name": "New York",
"cities": 0
}
]
}Ví dụ mã
curl -s "https://localserpproxy.com/api/v1/catalog/countries/US/states"import os
import requests
API = "https://localserpproxy.com/api/v1"
r = requests.get(f"{API}/catalog/countries/US/states", timeout=30)
r.raise_for_status()
print(r.json())// Node.js 18+ (built-in fetch), ES module
const API = 'https://localserpproxy.com/api/v1';
const res = await fetch(`${API}/catalog/countries/US/states`);
if (!res.ok) throw new Error((await res.json()).error?.message ?? `HTTP ${res.status}`);
console.log(await res.json());Các thành phố có thể nhắm mục tiêu trong một quốc gia
GET/v1/catalog/countries/{countryCode}/cities
Với product=mobile hoặc product=mobile-gb, chỉ có thể chọn các thành phố có modem 4G/5G.
Công khai: không cần khóa API.
Tham số
| Tên | Trong | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|---|
countryCode | path | string | Có | ISO 3166-1 alpha-2, viết hoa. |
product | query | string | Không | Chỉ áp dụng cho các địa điểm có sản phẩm này (residential, mobile, mobile-gb). |
Phản hồi 200 OK
{
"data": [
{
"id": "new_york",
"name": "New York",
"state": "ny"
}
]
}Ví dụ mã
curl -s "https://localserpproxy.com/api/v1/catalog/countries/US/cities"import os
import requests
API = "https://localserpproxy.com/api/v1"
r = requests.get(f"{API}/catalog/countries/US/cities", timeout=30)
r.raise_for_status()
print(r.json())// Node.js 18+ (built-in fetch), ES module
const API = 'https://localserpproxy.com/api/v1';
const res = await fetch(`${API}/catalog/countries/US/cities`);
if (!res.ok) throw new Error((await res.json()).error?.message ?? `HTTP ${res.status}`);
console.log(await res.json());Các ISP (ASN) có thể nhắm mục tiêu trong một quốc gia — chỉ proxy dân cư
GET/v1/catalog/countries/{countryCode}/asns
Công khai: không cần khóa API.
Tham số
| Tên | Trong | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|---|
countryCode | path | string | Có | ISO 3166-1 alpha-2, viết hoa. |
Phản hồi 200 OK
{
"data": [
{
"asn": 7922,
"name": "Comcast Cable"
}
]
}Ví dụ mã
curl -s "https://localserpproxy.com/api/v1/catalog/countries/US/asns"import os
import requests
API = "https://localserpproxy.com/api/v1"
r = requests.get(f"{API}/catalog/countries/US/asns", timeout=30)
r.raise_for_status()
print(r.json())// Node.js 18+ (built-in fetch), ES module
const API = 'https://localserpproxy.com/api/v1';
const res = await fetch(`${API}/catalog/countries/US/asns`);
if (!res.ok) throw new Error((await res.json()).error?.message ?? `HTTP ${res.status}`);
console.log(await res.json());