Admin Portal API Docs

PasarGuard-compatible and portal-native API reference.

Base URLs

https://admin.vsl247.com
https://admin2.vsl247.com

Authorization

Use a Bearer token for PasarGuard-compatible routes. Legacy /api/v1 routes also accept HTTP Basic authentication.

Quick Start

curl -X POST https://admin.vsl247.com/api/admin/token \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'username=admin_username&password=admin_password'

curl -H 'Authorization: Bearer ACCESS_TOKEN' \
  https://admin.vsl247.com/api/users

Authentication

Create a token and inspect the authenticated portal admin.

POST /api/admin/token Create a PasarGuard-style access token.
Form body
username=admin_username&password=admin_password
Response 200
{
  "access_token": "...",
  "token_type": "bearer"
}
GET /api/admin Return the authenticated admin.
Response 200
{
  "username": "admin_username",
  "is_sudo": false,
  "telegram_id": null,
  "discord_webhook": null,
  "users_usage": 0
}

Users

Manage only the clients owned by the authenticated portal admin.

GET /api/users List owned clients with filters and pagination.
Example request
GET /api/users?offset=0&limit=10&username=client&status=active
Response 200
{
  "users": [],
  "total": 0
}
POST /api/user Create a user using the admin's remaining quota.
Request body
{
  "username": "client_username",
  "data_limit": 21474836480,
  "duration_days": 30,
  "status": "active",
  "note": "optional"
}
Response 201
{
  "username": "client_username",
  "status": "active",
  "used_traffic": 0,
  "data_limit": 21474836480,
  "subscription_url": "https://sub.vsl247.com/sub/..."
}
GET /api/user/<username> Return one owned client.
Response 200
{
  "username": "client_username",
  "status": "active",
  "used_traffic": 1073741824,
  "data_limit": 21474836480,
  "expire": 1780000000,
  "subscription_url": "https://sub.vsl247.com/sub/..."
}
PUT /api/user/<username> Increase quota or update expiry and status.
Request body
{
  "data_limit": 32212254720,
  "expire": 1780000000,
  "status": "active"
}
Response 200
{
  "username": "client_username",
  "status": "active",
  "data_limit": 32212254720,
  "expire": 1780000000
}
DELETE /api/user/<username> Delete an owned client through the panel API.
Response 200
{
  "detail": "User successfully deleted"
}
POST /api/user/<username>/reset Reset the client's used traffic.
Request
POST /api/user/client_username/reset
Authorization: Bearer ACCESS_TOKEN
Response 200
{
  "username": "client_username",
  "status": "active",
  "used_traffic": 0,
  "data_limit": 21474836480
}
POST /api/user/<username>/revoke_sub Revoke and regenerate the subscription link.
Request
POST /api/user/client_username/revoke_sub
Authorization: Bearer ACCESS_TOKEN
Response 200
{
  "username": "client_username",
  "status": "active",
  "subscription_url": "https://sub.vsl247.com/sub/NEW_TOKEN"
}

Activity

Inspect subscription fetches and traffic usage.

GET /api/user/<username>/sub_update Return subscription fetch history.
Example request
GET /api/user/client_username/sub_update?offset=0&limit=10
Response 200
{
  "updates": [
    {
      "created_at": "2026-05-29T10:25:55Z",
      "user_agent": "v2rayNG/1.8.5"
    }
  ]
}
GET /api/user/<username>/usage Return usage records for one owned client.
Example request
GET /api/user/client_username/usage?start=2026-06-01T00:00:00Z&end=2026-06-06T00:00:00Z
Response 200
{
  "username": "client_username",
  "usages": [
    {
      "node_id": 6,
      "used_traffic": 268435456,
      "created_at": "2026-06-05T12:00:00Z"
    }
  ]
}
GET /api/users/usage Return usage records for all owned clients.
Example request
GET /api/users/usage?start=2026-06-01T00:00:00Z&end=2026-06-06T00:00:00Z
Response 200
{
  "usages": [
    {
      "username": "client_username",
      "node_id": 6,
      "used_traffic": 268435456,
      "created_at": "2026-06-05T12:00:00Z"
    }
  ]
}

Portal-Native API

Legacy routes that use the portal's ok response wrapper.

GET /api/v1/me Return the current portal account and quota.
Response 200
{
  "ok": true,
  "user": {
    "username": "admin_username",
    "role": "admin",
    "quota_bytes": 107374182400,
    "remaining_bytes": 85899345920
  }
}
GET /api/v1/clients Return the portal-native client list.
Example request
GET /api/v1/clients?page=1&per_page=10&search=client&live=1
Response 200
{
  "ok": true,
  "page": 1,
  "per_page": 10,
  "total": 1,
  "has_next": false,
  "clients": []
}
POST /api/v1/admins Create a portal admin and link a non-sudo panel admin.
Request body
{
  "username": "portal_admin",
  "portal_password": "portal-password",
  "quota_gb": 100,
  "min_client_gb": 0.5,
  "subscription_host": "sub.example.com",
  "marzban_admin_mode": "existing",
  "marzban_username": "panel_admin",
  "marzban_password": "panel-password"
}
Response 201
{
  "ok": true,
  "admin_id": 42
}

No matching endpoints.

Compatibility Notes

  • PasarGuard-compatible routes manage only clients owned by the authenticated portal admin.
  • Client creation and data-limit increases follow portal quota rules.
  • Deleting a user never returns quota to the admin.
  • PasarGuard-compatible responses do not use the portal-native ok wrapper.
  • Unsupported panel administration and system routes are not proxied.