Go SDK
There is no official XLADA SDK for Go. The XLADA API is identical to the Remnawave API,
so the client is assembled on the standard net/http library with no external
dependency at all â that way you do not depend on someone else's release cycle.
For Remnawave the community maintains a Go SDK generated from the same OpenAPI specification. XLADA responds on the same paths, so it applies here too, but we have not tested it with XLADA officially. The example below depends on no modules at all.
Installationâ
You need Go 1.18+ (any is used) and a project module:
mkdir xlada-bot && cd xlada-bot
go mod init example.com/xlada-bot
No external packages are required â only net/http, encoding/json, and context.
Clientâ
The token is either a JWT from POST /api/auth/login or a long-lived API token from
POST /api/tokens. Both are passed in the Authorization: Bearer header. When calling
the panel directly, add the X-Forwarded-For and
X-Forwarded-Proto: https headers, otherwise the panel's middleware will drop the connection.
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
}
Listing usersâ
Paginated output is set by the start (offset) and size
(page size, 1â1000) query parameters.
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("total: %d\n", out.Response.Total)
return nil
}
Creating a userâ
POST /api/users accepts username (3â36 characters, a-z, A-Z,
0-9, _, - only) and a required expireAt in ISO 8601 format.
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("created id=%d, shortUuid=%s\n", out.Response.ID, out.Response.ShortUUID)
return nil
}
Getting a nodeâ
A specific node is requested by uuid; the node list â by 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
}
All response structures are described in the specification on the
API Specification page. Take the json tags straight from there â panel
fields are named in camelCase.
What's nextâ
- TypeScript SDK â a client on
fetchand axios. - Python SDK â a client on
requests. - API Specification â the full OpenAPI specification.
- Webhooks â panel events without polling the API.