Appearance
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-apiRequires 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 expiryAccessToken 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
| Group | Notable 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
jsonbody forPOST/PUT/PATCHwhen$datais non-empty - Sends
queryparams when provided - Returns the decoded JSON body (or raw body if the response wasn't JSON)
- Throws
Elyar\MarzbanApi\Exceptions\ApiUnauthorizedExceptionon HTTP 401, orApiExceptionfor 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.