AR
VPN panels

Crypto payments for Marzban VPN

A small self-hosted service that sells Marzban VPN subscriptions for crypto through SnapEX Pay. Your shop or Telegram bot asks it for a checkout link, the customer pays on the SnapEX Pay page (USDT on TRC20, ERC20 or BEP20, plus other methods SnapEX offers for that amount), and once the invoice is paid the service creates or extends the user in your Marzban panel and returns the subscription link.

Download the module

Free. Version 1.0.0.

What it does

  • No wallet or blockchain node to run.
  • POST /v1/checkout creates a SnapEX Pay invoice for a plan and returns pay_url; GET /v1/orders/{invoice_id} returns the status and the subscription URL, so a bot can poll it.
  • Signed webhook (HMAC-SHA256, 5-minute timestamp window). The webhook body is never trusted: the invoice is re-read from the SnapEX Pay API and the user is provisioned only when it is paid.
  • Idempotent: repeated or concurrent webhook deliveries provision an invoice only once.
  • New users get every protocol that has an inbound in your panel; existing users are extended from their current expiry, and traffic plans add a fresh quota on top of their usage.
  • Plans are set with one environment variable; orders are kept in SQLite. Test mode moves no real funds.

Install

  1. Download and unpack the archive, then in its folder run cp .env.example .env.
  2. In the SnapEX Pay merchant cabinet create an API key with the invoices.read and invoices.write scopes and put it into SNAPEX_API_KEY.
  3. Set API_TOKEN (for example openssl rand -hex 32), MARZBAN_URL and the Marzban admin credentials (MARZBAN_USERNAME and MARZBAN_PASSWORD), and your plans in PLANS (id:days:usd:traffic_bytes, 0 bytes = unlimited).
  4. Start it: docker compose up -d, then check curl http://127.0.0.1:8080/health. Put the service behind an HTTPS reverse proxy.
  5. In the cabinet add a webhook endpoint https://<your service>/webhook subscribed at least to invoice.paid, copy its signing secret into SNAPEX_WEBHOOK_SECRET and restart the service.
  6. From your shop or bot call POST /v1/checkout with Authorization: Bearer <API_TOKEN>, send pay_url to the customer and poll GET /v1/orders/{invoice_id} for the subscription link. For a test without real funds set SNAPEX_ENVIRONMENT=test.

Settings

SNAPEX_API_KEYMerchant API key (smk_…) with invoices.read and invoices.write.
SNAPEX_WEBHOOK_SECRETSigning secret (whsec_…) of your webhook endpoint.
SNAPEX_ENVIRONMENTlive or test. Test invoices move no real funds.
SNAPEX_FEE_ONWho pays the SnapEX service fee: merchant or customer.
API_TOKENBearer token your bot or shop sends to /v1/checkout and /v1/orders/*.
MARZBAN_URL, MARZBAN_USERNAME, MARZBAN_PASSWORDPanel URL and admin credentials (or a ready MARZBAN_TOKEN; tokens expire, so username and password are better for a long-running service).
PLANSComma-separated id:days:usd:traffic_bytes, default month:30:5.00:0,quarter:90:12.00:0.

Questions

Can I use it from a Telegram bot?

Yes. The bot calls POST /v1/checkout, sends pay_url to the user and polls GET /v1/orders/{invoice_id} for the subscription link. There is also a complete Telegram bot for Marzban, 3x-ui and Remnawave.

What happens to an existing user who pays again?

The subscription is extended from the current expiry (or from now if it has already expired); traffic plans add a fresh quota on top of the usage.

Can a webhook provision a user twice?

No. Repeated or concurrent deliveries provision an invoice only once, and the service re-reads the invoice from the SnapEX Pay API before doing anything.

What if the Marzban panel is down when the payment arrives?

The webhook handler returns 502, and SnapEX Pay retries the delivery later.

Why do I need HTTPS?

SnapEX Pay delivers webhooks only to https:// URLs, so put the service behind nginx, Caddy or Traefik.

Ready to accept crypto?

Create a merchant account, get an API key and connect the module. 1% per payment, no monthly fee.