Skip to content

Marzban API

Current version: V1.1.0

elyar/marzban-api (namespace Elyar\MarzbanApi) is a standalone PHP client for the Marzban VPN panel API. It has no dependency on Essence or any telegram-bot-essentials/* package — it's a plain HTTP client (built on Laravel's Http facade) that bots in this ecosystem use to provision/manage VPN accounts as the product they sell, but it's equally usable outside a Telegram bot context.

Installation

bash
composer require elyar/marzban-api

Requires Laravel (illuminate/http for the Http facade) — it is not framework-agnostic.

Authenticating and creating a client

php
use Elyar\MarzbanApi\MarzbanClient;

// One-shot: log in and get a ready-to-use client
$client = MarzbanClient::LoginAndMake($baseUrl, $username, $password);

// If you already have a valid bearer token (e.g. cached from a previous login)
$client = MarzbanClient::make($baseUrl, $token);

// If you want the token + expiry separately (e.g. to cache it yourself)
$accessToken = MarzbanClient::authenticate($baseUrl, $username, $password);
$accessToken->token;                       // string
$accessToken->expiresAt;                   // ?DateTimeInterface, decoded from the JWT
$accessToken->isValid(now(), bufferSeconds: 60); // false once within 60s of expiry

AccessToken is a plain readonly DTO — caching/refreshing it (e.g. in a database column or Cache::remember()) is left to the calling application; the client itself does not auto-refresh an expired token.

Making calls

The client exposes one method-group accessor per Marzban API section, each lazily instantiated and memoized:

php
$client->admin()->getCurrentAdmin();
$client->user()->getUser('some_username');
$client->node()->getNodes();

Available groups and key methods

GroupNotable methods
admin()createAdmin, modifyAdmin, removeAdmin, getAdmins, disableAllActiveUsers, activateAllDisabledUsers, getAdminUsage
user()addUser, getUser, modifyUser, removeUser, getUsers, resetUserDataUsage, revokeUserSubscription, getUserUsage, activeNextPlan, setOwner, getExpiredUsers, deleteExpiredUsers
userTemplate()addUserTemplate, getUserTemplates, getUserTemplate, modifyUserTemplate, removeUserTemplate
node()addNode, getNode, modifyNode, removeNode, getNodes, reconnectNode, getUsage, getNodeSettings
core()getCoreStats, restartCore, getCoreConfig, modifyCoreConfig
system()getSystemStats, getInbounds, getHosts, modifyHosts
subscription()userSubscription, userSubscriptionInfo, userGetUsage, userSubscriptionWithClientType, userAgentHeader

Every method is a thin wrapper over HttpClient::request(method, endpoint, data, query, extraHeaders), which:

  • Builds the URL from the base URL + endpoint
  • Sends json body for POST/PUT/PATCH when $data is non-empty
  • Sends query params when provided
  • Returns the decoded JSON body (or raw body if the response wasn't JSON)
  • Throws Elyar\MarzbanApi\Exceptions\ApiUnauthorizedException on HTTP 401, or ApiException for any other non-2xx response — both carry the HTTP status and response body in the message
php
try {
    $client->user()->getUser('missing_user');
} catch (\Elyar\MarzbanApi\Exceptions\ApiUnauthorizedException $e) {
    // token expired/invalid — re-authenticate
} catch (\Elyar\MarzbanApi\Exceptions\ApiException $e) {
    // any other API error (404, 422, 500, ...)
}

Extending

Each group (UserApi, AdminApi, ...) extends BaseApi, which just stores the shared HttpClient — adding a new endpoint method to any group is a one-line addition calling $this->http->request(...). If Marzban adds a new API section entirely, add a new *Api class extending BaseApi and a matching lazy accessor on MarzbanClient.

Comparison with Rebecca API

Marzban and Rebecca API share the exact same client shape (*Client::make()/LoginAndMake()/authenticate(), lazy *Api() accessors, HttpClient, AccessToken, the same exception types) because they're clients for two different self-hosted VPN panels with a similar admin/user/node/subscription API surface. If you're writing a client for a third panel, copy this package's structure.