diff --git a/src/x3-client/client.go b/src/x3-client/client.go
new file mode 100644
index 0000000..c13bf66
--- /dev/null
+++ b/src/x3-client/client.go
@@ -0,0 +1,27 @@
+package x3_client
+
+import (
+	"net/http"
+	"net/http/cookiejar"
+)
+
+type X3Client struct {
+	Host string
+
+	httpClient *http.Client
+}
+
+func NewX3Client(host, port string) (*X3Client, error) {
+	jar, err := cookiejar.New(nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return &X3Client{
+		Host: host + ":" + port,
+
+		httpClient: &http.Client{
+			Jar: jar,
+		},
+	}, nil
+}
diff --git a/src/x3-client/http.go b/src/x3-client/http.go
new file mode 100644
index 0000000..d440ef0
--- /dev/null
+++ b/src/x3-client/http.go
@@ -0,0 +1,163 @@
+package x3_client
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"io"
+	"net/http"
+)
+
+func makeGetRequest[R any](httpClient *http.Client, url string) (R, error) {
+	var res R
+
+	resp, err := httpClient.Get(url)
+	if err != nil {
+		return res, err
+	}
+	respBody, err := io.ReadAll(resp.Body)
+	if err != nil {
+		return res, err
+	}
+	err = json.Unmarshal(respBody, &res)
+	if err != nil {
+		return res, err
+	}
+	return res, nil
+}
+
+func makePostRequest[Q, R any](httpClient *http.Client, url string, req Q) (R, error) {
+	var res R
+	body, err := json.Marshal(req)
+	if err != nil {
+		return res, err
+	}
+	resp, err := httpClient.Post(url, "application/json", bytes.NewReader(body))
+	if err != nil {
+		return res, err
+	}
+	respBody, err := io.ReadAll(resp.Body)
+	if err != nil {
+		return res, err
+	}
+	err = json.Unmarshal(respBody, &res)
+	if err != nil {
+		return res, err
+	}
+	return res, nil
+}
+
+const loginURL = "/login"
+
+func (c *X3Client) Login(request LoginRequest) (GeneralResponse[LoginResponse], error) {
+	return makePostRequest[interface{}, GeneralResponse[LoginResponse]](c.httpClient, c.Host+loginURL+fmt.Sprintf("?username=%s&password=%s", request.Username, request.Password), nil)
+}
+
+const inboundsURL = "/panel/api/inbounds/list"
+
+func (c *X3Client) GetInbounds() (GeneralResponse[[]Inbound], error) {
+	return makeGetRequest[GeneralResponse[[]Inbound]](c.httpClient, c.Host+inboundsURL)
+}
+
+const inboundURL = "/panel/api/inbounds/get/%d"
+
+func (c *X3Client) GetInbound(inboundId int) (GeneralResponse[Inbound], error) {
+	return makeGetRequest[GeneralResponse[Inbound]](c.httpClient, c.Host+fmt.Sprintf(inboundURL, inboundId))
+}
+
+const inboundClientTrafficURL = "/panel/api/inbounds/getClientTraffics/%s"
+
+func (c *X3Client) GetInboundClientTraffic(email string) (GeneralResponse[ClientStats], error) {
+	return makeGetRequest[GeneralResponse[ClientStats]](c.httpClient, c.Host+fmt.Sprintf(inboundClientTrafficURL, email))
+}
+
+const inboundClientTrafficByIdURL = "/panel/api/inbounds/getClientTrafficsById/%s"
+
+func (c *X3Client) GetInboundClientTrafficById(uuid string) (GeneralResponse[ClientStats], error) {
+	return makeGetRequest[GeneralResponse[ClientStats]](c.httpClient, c.Host+fmt.Sprintf(inboundClientTrafficByIdURL, uuid))
+}
+
+const inboundCreateBackupURL = "/panel/api/inbounds/createbackup"
+
+func (c *X3Client) CreateInboundBackup() (GeneralResponse[interface{}], error) {
+	return makeGetRequest[GeneralResponse[interface{}]](c.httpClient, c.Host+inboundCreateBackupURL)
+}
+
+const clientIpsURL = "/panel/api/inbounds/clientIps/%s"
+
+func (c *X3Client) GetClientIps(email string) (GeneralResponse[string], error) {
+	return makePostRequest[interface{}, GeneralResponse[string]](c.httpClient, c.Host+fmt.Sprintf(clientIpsURL, email), nil)
+}
+
+const addInboundURL = "/panel/api/inbounds/add"
+
+func (c *X3Client) AddInbound(inbound Inbound) (GeneralResponse[Inbound], error) {
+	return makePostRequest[Inbound, GeneralResponse[Inbound]](c.httpClient, c.Host+addInboundURL, inbound)
+}
+
+const addClientToInboundURL = "/panel/api/inbounds/addClient"
+
+func (c *X3Client) AddClientToInbound(client CreateClient) (GeneralResponse[interface{}], error) {
+	return makePostRequest[CreateClient, GeneralResponse[interface{}]](c.httpClient, c.Host+addClientToInboundURL, client)
+}
+
+const updateInboundURL = "/panel/api/inbounds/update/%d"
+
+func (c *X3Client) UpdateInbound(inbound Inbound) (GeneralResponse[Inbound], error) {
+	return makePostRequest[Inbound, GeneralResponse[Inbound]](c.httpClient, c.Host+fmt.Sprintf(updateInboundURL, inbound.Id), inbound)
+}
+
+// TODO: Check if client id is int not an uuid
+const updateClientInboundURL = "/panel/api/inbounds/updateClient/%d"
+
+func (c *X3Client) UpdateClientInbound(client CreateClient) (GeneralResponse[interface{}], error) {
+	return makePostRequest[CreateClient, GeneralResponse[interface{}]](c.httpClient, c.Host+fmt.Sprintf(updateClientInboundURL, client.Id), client)
+}
+
+const clearClientIpsURL = "/panel/api/inbounds/clearClientIps/%s"
+
+func (c *X3Client) ClearClientIps(email string) (GeneralResponse[interface{}], error) {
+	return makePostRequest[interface{}, GeneralResponse[interface{}]](c.httpClient, c.Host+fmt.Sprintf(clearClientIpsURL, email), nil)
+}
+
+const resetAllTrafficURL = "/panel/api/inbounds/resetAllTraffics"
+
+func (c *X3Client) ResetAllTraffic() (GeneralResponse[interface{}], error) {
+	return makePostRequest[interface{}, GeneralResponse[interface{}]](c.httpClient, c.Host+resetAllTrafficURL, nil)
+}
+
+const resetAllClientTrafficByInboundURL = "/panel/api/inbounds/resetAllClientTraffics/%d"
+
+func (c *X3Client) ResetAllClientTrafficByInbound(inboundId int) (GeneralResponse[interface{}], error) {
+	return makePostRequest[interface{}, GeneralResponse[interface{}]](c.httpClient, c.Host+fmt.Sprintf(resetAllClientTrafficByInboundURL, inboundId), nil)
+}
+
+const resetClientTrafficURL = "/panel/api/inbounds/%d/resetClientTraffic/%s"
+
+func (c *X3Client) ResetClientTraffic(inboundId int, email string) (GeneralResponse[interface{}], error) {
+	return makePostRequest[interface{}, GeneralResponse[interface{}]](c.httpClient, c.Host+fmt.Sprintf(resetClientTrafficURL, inboundId, email), nil)
+}
+
+const deleteClientURL = "/panel/api/inbounds/%d/delClient/%s"
+
+func (c *X3Client) DeleteClient(inboundId int, uuid string) (GeneralResponse[interface{}], error) {
+	return makePostRequest[interface{}, GeneralResponse[interface{}]](c.httpClient, c.Host+fmt.Sprintf(deleteClientURL, inboundId, uuid), nil)
+}
+
+const deleteInboundURL = "/panel/api/inbounds/del/%d"
+
+func (c *X3Client) DeleteInbound(inboundId int) (GeneralResponse[interface{}], error) {
+	return makePostRequest[interface{}, GeneralResponse[interface{}]](c.httpClient, c.Host+fmt.Sprintf(deleteInboundURL, inboundId), nil)
+}
+
+const deleteDepletedClientsURL = "/panel/api/inbounds/delDepletedClients/%d"
+
+func (c *X3Client) DeleteDepletedClients(inboundId int) (GeneralResponse[interface{}], error) {
+	return makePostRequest[interface{}, GeneralResponse[interface{}]](c.httpClient, c.Host+fmt.Sprintf(deleteDepletedClientsURL, inboundId), nil)
+}
+
+const onlineClientsURL = "/panel/api/inbounds/onlines"
+
+func (c *X3Client) GetOnlineClients() (GeneralResponse[interface{}], error) {
+	return makePostRequest[interface{}, GeneralResponse[interface{}]](c.httpClient, c.Host+onlineClientsURL, nil)
+}
diff --git a/src/x3-client/models.go b/src/x3-client/models.go
new file mode 100644
index 0000000..989a3c0
--- /dev/null
+++ b/src/x3-client/models.go
@@ -0,0 +1,51 @@
+package x3_client
+
+type GeneralResponse[T any] struct {
+	Success bool   `json:"success"`
+	Message string `json:"msg"`
+	Object  T      `json:"obj"`
+}
+
+type LoginRequest struct {
+	Username string `json:"username"`
+	Password string `json:"password"`
+}
+
+type LoginResponse struct {
+}
+
+type Inbound struct {
+	Id             int           `json:"id"`
+	Up             int           `json:"up"`
+	Down           int           `json:"down"`
+	Total          int           `json:"total"`
+	Remark         string        `json:"remark"`
+	Enable         bool          `json:"enable"`
+	ExpiryTime     int           `json:"expiryTime"`
+	ClientStats    []ClientStats `json:"clientStats"`
+	Listen         string        `json:"listen"`
+	Port           int           `json:"port"`
+	Protocol       string        `json:"protocol"`
+	Settings       string        `json:"settings"`
+	StreamSettings string        `json:"streamSettings"`
+	Tag            string        `json:"tag"`
+	Sniffing       string        `json:"sniffing"`
+	Allocate       string        `json:"allocate"`
+}
+
+type ClientStats struct {
+	Id         int    `json:"id"`
+	InboundId  int    `json:"inboundId"`
+	Enable     bool   `json:"enable"`
+	Email      string `json:"email"`
+	Up         int    `json:"up"`
+	Down       int    `json:"down"`
+	ExpiryTime int    `json:"expiryTime"`
+	Total      int    `json:"total"`
+	Reset      int    `json:"reset"`
+}
+
+type CreateClient struct {
+	Id       int    `json:"id"`
+	Settings string `json:"settings"`
+}