LycheeVPN
Dành cho lập trình viên

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 emailpassword (đă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_key phải là 32 byte mã hoá base64 — đúng 44 ký tự, kết thúc bằng =.
  • device_id phải khớp với thiết bị gắn token, nếu không nhận 403.
  • expires_at là 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

HTTPTrường hợp
401Thiếu token, token sai hoặc đã bị thu hồi
403Thiế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)
404Không tìm thấy server_id hoặc node đang tạm dừng
422Dữ liệu không hợp lệ; xem errorerrors
429Vượt giới hạn tần suất
503Node 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ỗ.