{"openapi":"3.1.0","info":{"title":"NanVPN API","version":"1.0.0","description":"Buy a VPN (WireGuard, OpenVPN, VLESS+Reality; up to 10 devices, 50+ countries) with crypto (XNO, BTC, XMR, USDT, USDC, NANUSD and more). No account, no email. Flow: GET /catalog -> POST /buy {days} -> pay payinAmount of payinCurrency to payinAddress (or open paymentLink) -> poll GET /order with the returned token until status is active -> GET /servers -> GET /order/config?protocol=wireguard&server=<id> to get a config file. POST /extend with the same token renews it, same credentials."},"servers":[{"url":"https://api.nanvpn.com"}],"components":{"responses":{"Error":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"securitySchemes":{"orderToken":{"type":"http","scheme":"bearer","description":"The token (nv_...) returned once by POST /buy. It is the only way to access the VPN and extend it."},"balanceToken":{"type":"http","scheme":"bearer","description":"Balance key nb_... (store credit shared by all Nan services, not withdrawable)."}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string"}}},"Payment":{"type":"object","properties":{"kind":{"type":"string","enum":["buy","extend","topup"]},"status":{"type":"string","enum":["waiting","paid","fulfilling","fulfilled","fulfill-error","failed"]},"periodDays":{"type":"integer"},"priceUsd":{"type":"number"},"invoiceUsd":{"type":"number","description":"Amount invoiced; above priceUsd when raised to the coin minimum"},"creditUsd":{"type":"number","description":"Part of invoiceUsd credited to the balance once paid"},"paymentLink":{"type":"string"},"payinCurrency":{"type":"string"},"payinAddress":{"type":"string"},"payinAmount":{"type":"number"},"expireAt":{"type":"string","format":"date-time"},"depositDetectedAt":{"type":["string","null"],"format":"date-time"}}},"Order":{"type":"object","properties":{"orderId":{"type":"string"},"status":{"type":"string","enum":["awaiting-payment","active","expired","cancelled","error"]},"periodDays":{"type":"integer"},"expiresAt":{"type":["string","null"],"format":"date-time"},"credentials":{"type":["object","null"],"properties":{"username":{"type":"string"},"password":{"type":"string"}},"description":"OpenVPN / app login, once active"},"maxDevices":{"type":"integer"},"payments":{"type":"array","items":{"$ref":"#/components/schemas/Payment"}},"serverTime":{"type":"string","format":"date-time"}}},"Server":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"iso":{"type":"string"},"country":{"type":"string"},"city":{"type":"string"}}}}},"paths":{"/catalog":{"get":{"summary":"Plans (days, priceUsd), locations, protocols and accepted coins","responses":{"200":{"description":"plans[], locations[] {iso, country, cities, protocols}, payinCurrencies[] {ticker, feeless, minUsd}, topup limits"}}}},"/servers":{"get":{"summary":"Servers for configurations","responses":{"200":{"description":"servers[] (WireGuard + OpenVPN), vlessServers[], ports[] {id, protocol, number, default} (OpenVPN)"}}}},"/price":{"get":{"summary":"Price of a plan","parameters":[{"name":"days","in":"query","required":true,"schema":{"type":"integer","enum":[1,7,30,90,180,365]}}],"responses":{"200":{"description":"{ days, priceUsd }"}}}},"/buy":{"post":{"summary":"Order a VPN","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["days"],"properties":{"days":{"type":"integer","enum":[1,7,30,90,180,365]},"payinCurrency":{"type":"string","description":"Ticker from GET /payin-currencies (XNO, BTC, XMR, USDT-TRX...), BALANCE to pay from the balance instantly, or omit to choose on the Nanswap Pay page","example":"XNO"},"balanceToken":{"type":"string","description":"Existing balance (nb_...): coin-minimum surplus lands there; required with BALANCE"}}}}}},"responses":{"201":{"description":"{ token, orderId, orderUrl, priceUsd, payment, balanceToken? }. token is shown once."},"400":{"$ref":"#/components/responses/Error"},"402":{"description":"Insufficient balance"},"429":{"description":"Too many orders"},"503":{"description":"Temporarily unavailable"}}}},"/order":{"get":{"summary":"Order status, expiry and credentials","security":[{"orderToken":[]}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"}}}},"401":{"$ref":"#/components/responses/Error"}}}},"/order/stream":{"get":{"summary":"Live order updates (Server-Sent Events, event: order, data: Order JSON)","security":[{"orderToken":[]}],"responses":{"200":{"description":"text/event-stream"}}}},"/order/config":{"get":{"summary":"Configuration file for one server","security":[{"orderToken":[]}],"parameters":[{"name":"protocol","in":"query","required":true,"schema":{"type":"string","enum":["wireguard","openvpn","vless"]}},{"name":"server","in":"query","required":true,"schema":{"type":"integer"},"description":"id from GET /servers (vlessServers for vless)"},{"name":"port","in":"query","required":false,"schema":{"type":"integer"},"description":"OpenVPN only: id from GET /servers ports (default port otherwise)"}],"responses":{"200":{"description":"{ protocol, server, name, content }. wireguard: .conf file (import or QR). openvpn: .ovpn file, login with credentials. vless: vless:// link for v2rayN/v2rayNG/Hiddify/Streisand."},"409":{"$ref":"#/components/responses/Error"}}}},"/extend":{"post":{"summary":"Extend or renew the VPN (same credentials)","security":[{"orderToken":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["days"],"properties":{"days":{"type":"integer"},"payinCurrency":{"type":"string"},"balanceToken":{"type":"string"}}}}}},"responses":{"201":{"description":"{ orderId, priceUsd, payment }"},"409":{"$ref":"#/components/responses/Error"}}}},"/payin-currencies":{"get":{"summary":"Coins accepted as payinCurrency","responses":{"200":{"description":"{ featured[], all[] }"}}}},"/balance":{"get":{"summary":"Balance amount and recent movements","security":[{"balanceToken":[]}],"responses":{"200":{"description":"{ balanceUsd, transactions[] }"}}}},"/balance/topup":{"post":{"summary":"Prefund the balance with a crypto invoice","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["amountUsd"],"properties":{"amountUsd":{"type":"number"},"payinCurrency":{"type":"string"},"balanceToken":{"type":"string"}}}}}},"responses":{"201":{"description":"{ topupId, payment, balanceToken? }"}}}},"/balance/topup/{id}":{"get":{"summary":"Top-up status","security":[{"balanceToken":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"{ payment, balanceUsd }"}}}}}}