1. Cookbook
TunnelSats Public Wireguard API
  • About our team
  • 📢 Public
    • List available VPN servers
      GET
    • Create a new VPN subscription
      POST
    • Claim a WireGuard configuration after payment
      POST
    • Check subscription status via payment hash
      GET
    • Renew an existing VPN subscription
      POST
    • Get Subscription Status
      POST
  • 🔐 Authenticated
    • Sync Subscription
      POST
    • Create Referral Code
      POST
    • Referral History
      GET
    • List all active/paid subscriptions for the account
      GET
  • 🔧 Tools
    • Lightning Node Network Address Discovery
      POST
    • Universal Connectivity Probe
      POST
  • Announcements
    • 💫 What is TunnelSats?
    • 🚀 Introducing the TunnelSats Public API v1
    • How TunnelSats Leverages Public APIs for Confined VPN Management
  • Cookbook
    • 🛠️ Automation & Code Examples
    • 🐚 Bash One-Liners
    • 🛑 Error Codes & Troubleshooting
    • 🎁 Referral Program: Earn Bonus Months
    • 🚑 Node Health & Upkeep
    • 🛡️ Security & Authentication
  • Schemas
    • Server
    • InvoiceOrder
    • SubscriptionStatus
    • WireGuardConfig
    • ReferralCode
    • ReferralHistory
    • NodeLookup
    • ConnectivityResult
    • RenewalOrder
    • ClaimResult
    • ApiError
    • SubscriptionListItem
  1. Cookbook

🛑 Error Codes & Troubleshooting

TunnelSats uses standardized machine-readable error codes. Since our API involves real-world Lightning transactions, understanding these codes is the difference between a smooth automation and a broken one.

📊 Machine-Readable Error Codes#

All error responses follow the ApiError schema: {"error": "CODE", "message": "Reason"}.
CodeHTTPMeaningMitigation
ERR_INVALID_INPUT400Invalid serverId, duration, or malformed pubkey.Check your request body JSON syntax.
ERR_UNAUTHORIZED401Missing or invalid Authorization header.Use Bearer <api_key> or Nostr <token>.
ERR_PAYMENT_REQUIRED402Subscription exists but hasn't been paid yet.Poll the status until it returns paid.
ERR_MIGRATION_REQUIRED403Attempting to renew on a legacy server (us1).Use the migration tool to move to us3.
ERR_RESOURCE_NOT_FOUND404No subscription found for that paymentHash.Verify your hash from the /create call.
ERR_RATE_LIMIT_EXCEEDED429You've hit the rate limit.Implement exponential backoff (Max 1 req/5s).
ERR_INTERNAL_ERROR500/503Backend node is syncing or maintenance mode.Wait 30 seconds and try again.

🔍 Specific Scenarios#

Invoice Expiration
Rate Limiting (429)
Development Envs (dev2)
402 vs. 404
If a user waits too long to pay, the invoice will expire.
Scenario: You poll and keep getting ERR_PAYMENT_REQUIRED.
Expiry: If the invoice expires, the paymentHash may eventually return ERR_RESOURCE_NOT_FOUND.
Action: Generate a new subscription request via /create.

📝 Node Integration Checklist#

For developers building integrations for Umbrel, Start9, or RaspiBlitz, follow this checklist to ensure a seamless user experience.

1. The Provisioning Flow#

Server Selection: Use GET /api/public/v1/servers to allow users to pick the region closest to them.
In-App Payment: Display the BOLT11 invoice clearly.
Polling UI: Progress indicator while polling GET /api/public/v1/subscription/{paymentHash}.

2. Configuration Management#

WireGuard Claim: Always offer a way to "Claim" the config again if the initial download fails.
Self-Healing: If wg show indicates no handshake for >3 minutes, automatically call /sync or /status to verify the server hasn't migrated.
Custom Keys
We recommend generating keys on our server (leaving wgPublicKey empty) for the easiest setup. However, for maximum privacy, allow advanced users to provide their own wgPublicKey.
Modified at 2026-04-12 13:22:57
Previous
🐚 Bash One-Liners
Next
🎁 Referral Program: Earn Bonus Months
Built with