Accounts & delivery

Accounts

Accounts are the core object of Vortexa: one credential set with an expiry, a data quota, a device limit, a node scope and a protocol. This page covers every field and every action on the Accounts list and the Account detail console.

The Accounts page is the master list of every VPN credential the panel manages, across every protocol. The detail page (/accounts/<id>) is a single-account console: settings, node assignment, live traffic, connected devices and generated client configs for every node the account is scoped to.

  • Supported protocols: ssh, vmess, vless, trojan, zivpn. Creation flows also accept the unified xray alias, which is always provisioned as VLESS underneath.
  • An Xray identity can own up to three sibling rows (VLESS / VMess / Trojan) that share one uuid, username and Telegram id. The list collapses them into one card, so switching protocol never loses history.
  • Usernames are unique per plane — SSH, the Xray family and ZIVPN each have their own namespace. An SSH and a VLESS account may share a username.
FieldMeaning
idRow id, <protocol>-<uuid prefix> e.g. vless-73967b74.
accountUuidSeparate logical-account handle used in panel URLs; either id or accountUuid resolves the detail page.
protocolssh | vmess | vless | trojan | zivpn.
username1–32 chars: letters, digits, dot, underscore, hyphen. Unique per plane.
passwordSSH/ZIVPN secret; Trojan stores its client secret here. Auto-generated (12 hex) when omitted.
uuidXray client id. Sibling protocol rows share it.
createdAt / expiresAtISO timestamps. Create accepts durationDays or durationHours; default 30 days.
ipLimitMax simultaneous devices; 0 = unlimited, default 2.
speedUpKbps / speedDnKbpsPer-account throttle in kbps, 0 = unlimited. Enforced with tc plus Xray sockopt.mark.
quotaGbLifetime data cap in GB, 0 = unlimited.
usedBytes / localUsedBytesMeasured usage; usedBytes is aggregated across the whole fleet, localUsedBytes is panel-host only.
statusactive | trial | suspended | locked | pending | expired. pending means the last provisioning attempt failed — see note.
telegramId / planIdLinks the account to a bot user and to a plan.
noteFree text, also used as a machine flag: quota_locked, grace_until:<iso>, daily_quota_locked:<iso>.
blockTorrent / unlockAllPer-account torrent blocking and a bypass override for all blocking rules.
outboundIdPin this account's egress to a named outbound instead of the node IP.
resetIntervalDays / resetEnabled / lastResetAtRecurring automatic quota reset.
dailyQuotaGb / dailyQuotaEnabledDaily cap layered on top of the lifetime quota.
transportsXray only: subset of ws, httpupgrade, xhttp, grpc. Omitted on create means all four.
xhttpModeOnly used when xhttp is enabled: auto, stream-up, stream-one, packet-up. The node narrows this to a single mode, preferring stream-up.
cdnIds / cdnOnlyCDN endpoints this account may use; cdnOnly hides the direct config. Auto-set to false if cdnIds becomes empty.
subToken / showRawPublic subscription token, and whether the subscription page exposes the raw protocol link.
cfTlsPort / cfNtlsPortPreferred Cloudflare-friendly port. Values outside the allowed sets are silently zeroed.
flowVLESS flow control, e.g. empty or xtls-rprx-vision.
onlineComputed per request: count of live IPs for this account across the fleet.
  1. 1
    Open Accounts → New account.
  2. 2
    Choose the protocol. Picking the unified Xray option lets you tick VLESS, VMess and Trojan; each ticked protocol becomes a sibling row sharing one UUID.
  3. 3
    Enter a username. Leave the password blank for SSH/ZIVPN to get a generated 12-character secret.
  4. 4
    Set the limits: expiry (or duration in days/hours), data quota in GB, device limit (concurrent IPs) and optional up/down speed caps in kbps.
  5. 5
    Optionally attach a plan — its quota, device limit, speed, duration and CDN defaults pre-fill the form.
  6. 6
    For Xray protocols choose the allowed transports and, if xHTTP is enabled, the xHTTP mode.
  7. 7
    Choose the nodes this account may use. Leaving the scope untouched means “allowed on every node”.
  8. 8
    Save. The row is inserted, then provisioning is pushed to the fleet. If provisioning throws, the row survives with status=pending and the error in note — fix the cause and press Repair.
  9. 9
    Hand off the credentials: copy the config, the QR code or the subscription URL, or press Send via Telegram if the account has a Telegram id.

What provisioning actually does

  • Validates the protocol, rejects ZIVPN if the ZIVPN tunnel is not installed on the target host, and rejects reserved SSH usernames.
  • For SSH: derives the real Linux login, cleans orphaned grvpn-* users, and refuses with 409 on a genuine system-user conflict.
  • Generates the password/UUID, derives the row id and mints a fresh accountUuid.
  • Normalises transports and xHTTP mode, unions the plan's CDN ids, snaps the Cloudflare ports to the allowed sets.
  • Pushes the account to the fleet: Xray client add + config test + restart, SSH useradd with expiry, or ZIVPN password-list reconcile.
  • Rebases the Xray per-email traffic baseline for new non-SSH accounts so a reused username never inherits the previous holder's counters.
  • Re-applies the fleet torrent-block and unlock-all policies, and writes a coalesced audit-log entry for sibling creations made within 20 seconds.
  • Rename: the UUID and accountUuid are preserved, so history and usage survive. Session state is moved to the new username, then the account is revoked under the old identity and re-provisioned under the new one.
  • Protocol switch is allowed only inside the Xray family (VLESS ↔ VMess ↔ Trojan). Switching to Trojan mints a password if none exists; switching to VLESS/VMess mints a UUID if none exists. Both revoke and re-provision.
  • Transport-only change re-syncs the Xray inbound client lists without touching the protocol.
  • Quota edits auto-unsuspend accounts the system suspended (note quota_locked or usage ≥ old quota) when the new quota is above current usage. Manual suspensions are untouched.

Note the new secret

Switching an Xray account to Trojan mints a fresh password. Not recording it is the most common cause of “my old link stopped working”.
ActionWhat happens
DeleteRow disappears optimistically, the server deletes it, then a best-effort purge scrubs the account from every node's live config and reports nodes that failed.
ExtendAdds N days (default 30) and re-provisions SSH accounts so the OS expiry moves too.
Lock / UnlockSets status=locked or status=active, clears note on unlock and re-provisions SSH.
RepairRe-runs provisioning for one account. The fix for “invalid username or password” after a node reboot or reimage.
Reset trafficZeroes the panel ledger and pushes a reset watermark to every node, so the fleet stops enforcing the old over-quota total.
Copy subscription URLFetches the account subscription and copies the public URL.
Rotate subscriptionIssues a new subToken, invalidating the previous public URL.
Cancel with refundCancels a prepaid account and optionally refunds to wallet, showing which funding source would be refunded.
Send via TelegramRe-delivers connection details to the linked Telegram user.
Export / Import CSVExports every account, or imports rows from CSV (bad rows are skipped silently).

The stats strip at the top counts Total, Active, Disabled, Expired, Grace (7d) and Limited. Grace and Limited are derived from the note markers grace_until: and daily_quota_locked:.

  1. 1
    Accounts → Bulk create.
  2. 2
    Pick the kind: SSH, Xray or ZIVPN. For Xray, tick the protocols each user should get.
  3. 3
    Pick a count (presets 10 / 50 / 100 / 250 / 500 / 1000; the server caps a job at 2000).
  4. 4
    Optionally pick a plan to auto-fill device limit, quota, speed and duration.
  5. 5
    Set a username prefix (sanitised, max 20 chars). Final usernames are prefix-XXXXXX with an alphabet that excludes ambiguous characters.
  6. 6
    Choose the password mode: random per account, or fixed for the whole batch (SSH/ZIVPN only).
  7. 7
    Pick the target nodes. Only nodes with that protocol's service installed are selectable.
  8. 8
    Generate. The dialog polls the job and shows live progress until it reports done; each created account gets the chosen node scope applied.

Job history

Only the 20 most recent bulk jobs are retained in memory. Export the created list if you need a permanent record.

Tabs: Overview, Settings, Nodes, Devices, Traffic, Configs. The active tab is remembered per account.

Save
Persists node scope, the field patch and the outbound assignment in one click, then pushes an instant sync to the nodes.
Node scope
Two-state: an untouched scope means “allow on every node”. Once you pick specific nodes the scope becomes restricted — even if that list later empties, which the UI warns about rather than silently reverting to all nodes.
Usage math
usedBytes is aggregated across every node that measured the account: 50 GB on node A plus 50 GB on node B is 100 GB.
Online detection
Authoritative node-reported presence, not byte activity, so a sibling protocol row with the same username never shows a false green dot.
Devices
Merges the panel's active-IP table with node-reported presence inside a 20-second freshness window matched to the heartbeat cadence.
Configs
One client config block per node the account is scoped to, falling back to the single-host profile only when no nodes are registered.
Traffic
Per-account history, polled while the page is open.
  • Lifetime quota (quotaGb) suspends the account when exceeded and marks note=quota_locked. Raising the quota above current usage auto-reactivates it.
  • Daily quota (dailyQuotaGb) limits per day and marks daily_quota_locked:<iso> until the next window.
  • Recurring reset (resetEnabled, resetIntervalDays) zeroes usage on a cycle — the “30 GB per month, renewing” model.
  • Grace is expressed with grace_until:<iso> in the note, and the list counts accounts in grace for the next 7 days.

Always reset traffic through the panel button

Editing the quota alone does not clear node-side ledgers. Reset traffic pushes the reset watermark to every node; without it the fleet keeps enforcing the old total.
account endpoints (session-authenticated)
GET    /api/accounts?protocol=<p>          list, with computed online counts
GET    /api/accounts/{id}                   single row
GET    /api/accounts/{id}/detail            usage, host, activeIps, connectionProfiles
GET    /api/accounts/{id}/traffic           traffic history
GET    /api/accounts/{id}/config            client config text
GET    /api/accounts/{id}/subscription      subscription payload + public URL
POST   /api/accounts/{id}/subscription/rotate
GET    /api/accounts/{id}/subscription/hits?limit=
POST   /api/accounts                        create
PATCH  /api/accounts/{id}                   partial update
DELETE /api/accounts/{id}                   delete + queue node cleanup
POST   /api/accounts/{id}/repair            re-run provisioning
POST   /api/accounts/{id}/cancel-prepaid    {refund, reason}
POST   /api/accounts/{id}/telegram          re-send details over the bot
PATCH  /api/accounts/{id}/outbound          pin/clear the egress outbound
POST   /api/accounts/{id}/rotate-token
POST   /api/accounts/bulk                   {action: extend|delete|lock|unlock, ids[], days?}
POST   /api/accounts/bulk-create            -> {jobId, total}
GET    /api/accounts/bulk-create/{jobId}    progress
GET    /api/accounts/export                 CSV
POST   /api/accounts/import                 {csv}
GET    /api/accounts/revoke-queue           {pending}

Every write invalidates the panel’s short GET cache, so the list reflects changes on the next poll.

  • A 409 “username already exists” is per plane, not global.
  • Deleting removes the DB row instantly but node cleanup is queued and drained one item at a time. Check /api/accounts/revoke-queue; on a very large fleet credentials can work for a few more seconds.
  • cdnOnly=true with an emptied cdnIds list is auto-corrected to false, unless the same patch explicitly re-enables it.
  • cfTlsPort/cfNtlsPort outside the allowed sets reset to 0 with no error.
  • Raising a quota never unlocks a manually locked account.
  • ZIVPN account creation returns 400 until the ZIVPN UDP tunnel is installed on the target host.