Go SDK
Официального SDK XLADA на Go нет. API XLADA идентичен API Remnawave, поэтому
клиент собирается на стандартной библиотеке net/http без единой внешней
зависимости — так вы не зависите от чужого релизного цикла.
Для Remnawave сообщество поддерживает Go-SDK, сгенерированный из той же OpenAPI-спецификации. XLADA отвечает на те же пути, поэтому он применим и здесь, но официально с XLADA мы его не тестировали. Пример ниже ни от каких модулей не зависит.
Установка
Нужен Go 1.18+ (используется any) и модуль проекта:
mkdir xlada-bot && cd xlada-bot
go mod init example.com/xlada-bot
Внешние пакеты не требуются — только net/http, encoding/json и context.
Клиент
Токен — это либо JWT от POST /api/auth/login, либо долгоживущий API-токен от
POST /api/tokens. Оба передаются в заголовке Authorization: Bearer. При
прямом обращении к панели добавьте заголовки X-Forwarded-For и
X-Forwarded-Proto: https, иначе middleware панели разорвёт соединение.
package main
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"time"
)
type Client struct {
baseURL string
token string
http *http.Client
}
func NewClient(baseURL, token string) *Client {
return &Client{
baseURL: baseURL,
token: token,
http: &http.Client{Timeout: 30 * time.Second},
}
}
func (c *Client) do(ctx context.Context, method, path string, body, out any) error {
var payload []byte
if body != nil {
var err error
if payload, err = json.Marshal(body); err != nil {
return err
}
}
req, err := http.NewRequestWithContext(ctx, method, c.baseURL+path, bytes.NewReader(payload))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+c.token)
req.Header.Set("X-Forwarded-For", "127.0.0.1")
req.Header.Set("X-Forwarded-Proto", "https")
res, err := c.http.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
if res.StatusCode >= http.StatusBadRequest {
return fmt.Errorf("xlada: %s %s: %s", method, path, res.Status)
}
if out != nil {
return json.NewDecoder(res.Body).Decode(out)
}
return nil
}
Список пользователей
Постраничный вывод задаётся query-параметрами start (смещение) и size
(размер страницы, 1–1000).
type user struct {
ID int `json:"id"`
Username string `json:"username"`
Status string `json:"status"`
ShortUUID string `json:"shortUuid"`
ExpireAt string `json:"expireAt"`
}
type usersResponse struct {
Response struct {
Users []user `json:"users"`
Total int `json:"total"`
} `json:"response"`
}
func listUsers(ctx context.Context, c *Client) error {
var out usersResponse
if err := c.do(ctx, http.MethodGet, "/api/users?start=0&size=25", nil, &out); err != nil {
return err
}
for _, u := range out.Response.Users {
fmt.Printf("%s\t%s\t%s\n", u.Username, u.Status, u.ExpireAt)
}
fmt.Printf("всего: %d\n", out.Response.Total)
return nil
}
Создание пользователя
POST /api/users принимает username (3–36 символов, только a-z, A-Z,
0-9, _, -) и обязательный expireAt в формате ISO 8601.
type createUserRequest struct {
Username string `json:"username"`
Status string `json:"status,omitempty"`
ExpireAt string `json:"expireAt"`
TrafficLimitBytes int64 `json:"trafficLimitBytes,omitempty"`
TrafficLimitStrategy string `json:"trafficLimitStrategy,omitempty"`
}
func createUser(ctx context.Context, c *Client) error {
var out struct {
Response struct {
ID int `json:"id"`
ShortUUID string `json:"shortUuid"`
} `json:"response"`
}
err := c.do(ctx, http.MethodPost, "/api/users", createUserRequest{
Username: "john_doe",
Status: "ACTIVE",
ExpireAt: "2026-01-17T15:38:45.065Z",
TrafficLimitStrategy: "NO_RESET",
}, &out)
if err != nil {
return err
}
fmt.Printf("создан id=%d, shortUuid=%s\n", out.Response.ID, out.Response.ShortUUID)
return nil
}
Получение ноды
Конкретная нода запрашивается по uuid, список нод — по GET /api/nodes.
func getNode(ctx context.Context, c *Client, uuid string) error {
var out struct {
Response struct {
Name string `json:"name"`
Address string `json:"address"`
Port *int `json:"port"`
IsConnected bool `json:"isConnected"`
} `json:"response"`
}
if err := c.do(ctx, http.MethodGet, "/api/nodes/"+uuid, nil, &out); err != nil {
return err
}
fmt.Printf("%s (%s) connected=%v\n", out.Response.Name, out.Response.Address, out.Response.IsConnected)
return nil
}
Все структуры ответов описаны в спецификации на странице
API Specification. Теги json берите прямо оттуда — поля панели
называются в camelCase.
Что дальше
- TypeScript SDK — клиент на
fetchи axios. - Python SDK — клиент на
requests. - API Specification — полная спецификация OpenAPI.
- Вебхуки — события панели без опроса API.