Tài liệu API
Base URL: http://lycheevpn.com ·
Mọi phản hồi đều là JSON, lỗi luôn có trường error.
Xác thực
Mọi endpoint tạo hoặc đóng phiên đều cần một access token gắn với thiết bị, gửi trong header:
Authorization: Bearer <token>
Token gắn với thiết bị chứ không gắn với tài khoản. Mỗi thiết bị giữ đúng một token còn hiệu lực — cấp lại sẽ thu hồi token cũ. Giới hạn tần suất: 20 request/phút cho nhóm phiên và 10 request/phút cho nhóm xác thực.
POST /v1/auth/device
Ghi danh một thiết bị chưa có tài khoản và nhận token khách.
POST /v1/auth/device
Content-Type: application/json
{
"device_id": "6f2c1b8e-9a4d-4f31-9c7e-1d2f3a4b5c6d",
"name": "Pixel 8",
"platform": "android",
"app_version": "1.0.0"
}
Phản hồi 201:
{
"token": "3|kR7f...",
"device": {
"device_id": "6f2c1b8e-...",
"name": "Pixel 8",
"platform": "android",
"is_premium": false
},
"account": null
}
POST /v1/auth/login · /v1/auth/register
Gắn thiết bị vào một tài khoản để dùng node premium và nhiều máy cùng lúc.
Cả hai nhận cùng bộ tham số thiết bị như trên, cộng thêm email và
password (đăng ký thêm name).
{
"token": "4|9Lm2...",
"device": { "device_id": "...", "is_premium": true },
"account": {
"name": "Nguyen Van A",
"email": "a@example.com",
"is_premium": true,
"device_limit": 5,
"plan": { "slug": "premium-monthly", "name": "Premium tháng" },
"expires_at": "2026-09-23T00:00:00+07:00"
}
}
POST /v1/auth/logout thu hồi token và đóng luôn tunnel đang mở của thiết bị đó.
GET /v1/auth/me trả về trạng thái hiện tại.
GET /v1/servers
Không cần token. Trả về các node đang hoạt động kèm mức tải thật.
{
"servers": [
{
"id": "sg-01",
"country": "Singapore",
"country_code": "SG",
"city": "Singapore",
"endpoint": "sg1.lycheevpn.com:51820",
"public_key": "xTIB...=",
"dns": "1.1.1.1, 1.0.0.1",
"allowed_ips": "0.0.0.0/0, ::/0",
"is_premium": false,
"load_percent": 12
}
]
}
Interface, dải mạng nội bộ và địa chỉ agent của node không bao giờ xuất hiện trong phản hồi này.
POST /v1/session
Đăng ký khoá công khai của thiết bị với một node. API chọn địa chỉ /32 còn
trống, thêm peer vào node rồi trả về cấu hình.
POST /v1/session
Authorization: Bearer <token>
{
"server_id": "sg-01",
"public_key": "L1r9...=",
"device_id": "6f2c1b8e-..."
}
{
"session_id": "0f4c9e1a-3b2d-4a7f-8c5e-9d1b2a3c4d5e",
"address": "10.8.1.7/32",
"dns": "1.1.1.1, 1.0.0.1",
"expires_at": 1787654321000
}
public_keyphải là 32 byte mã hoá base64 — đúng 44 ký tự, kết thúc bằng=.device_idphải khớp với thiết bị gắn token, nếu không nhận403.expires_atlà mili giây kể từ epoch. Gọi lại endpoint này trước khi hết hạn để gia hạn.- Một thiết bị chỉ giữ một tunnel: mở phiên mới sẽ tự đóng phiên cũ, kể cả trên node khác.
POST /v1/session/close
Gỡ peer khỏi node và trả lại địa chỉ. Trả về 204 kể cả khi phiên không tồn tại,
để client mất mạng giữa chừng có thể gọi lại mà không nhận lỗi vô nghĩa.
POST /v1/session/close
Authorization: Bearer <token>
{ "session_id": "0f4c9e1a-..." }
GET /health
Không cần token, dùng cho load balancer và trang tình trạng.
{ "ok": true, "servers": 12, "sessions": 148, "time": "2026-08-23T19:04:11+07:00" }
Mã lỗi
| HTTP | Trường hợp |
|---|---|
| 401 | Thiếu token, token sai hoặc đã bị thu hồi |
| 403 | Thiết bị bị khoá, device_id không khớp token, hoặc node premium mà tài khoản chưa trả phí (code: premium_required) |
| 404 | Không tìm thấy server_id hoặc node đang tạm dừng |
| 422 | Dữ liệu không hợp lệ; xem error và errors |
| 429 | Vượt giới hạn tần suất |
| 503 | Node từ chối thêm peer hoặc dải địa chỉ đã đầy |
Tự dựng client
Đường hầm dùng cặp khoá X25519 mã hoá base64. Sinh khoá bằng openssl,
rồi gọi API bằng curl:
openssl genpkey -algorithm X25519 -out private.pem
openssl pkey -in private.pem -outform DER | tail -c 32 | base64 -w0 > private.key
openssl pkey -in private.pem -pubout -outform DER | tail -c 32 | base64 -w0 > public.key
TOKEN=$(curl -s -X POST http://lycheevpn.com/v1/auth/device \
-H 'Content-Type: application/json' \
-d '{"device_id":"laptop-cua-toi-01","platform":"linux"}' | jq -r .token)
curl -s -X POST http://lycheevpn.com/v1/session \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d "{\"server_id\":\"sg-01\",\"public_key\":\"$(cat public.key)\",\"device_id\":\"laptop-cua-toi-01\"}"
Đưa kết quả vào tệp cấu hình đường hầm, ví dụ /etc/lychee/lychee.conf:
[Interface]
PrivateKey = <nội dung private.key>
Address = 10.8.1.7/32
DNS = 1.1.1.1, 1.0.0.1
[Peer]
PublicKey = <public_key của node>
Endpoint = sg1.lycheevpn.com:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25
Nạp tệp này vào client của bạn để dựng đường hầm. Địa chỉ 10.8.1.7/32 chỉ
có ý nghĩa bên trong đường hầm; ra Internet bạn mang địa chỉ công cộng của node.
Nhớ gọi /v1/session/close khi không dùng nữa. Không gọi thì địa chỉ bị
giữ tới khi phiên hết hạn, và mỗi node chỉ có 253 chỗ.