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"}.| Code | HTTP | Meaning | Mitigation |
|---|
ERR_INVALID_INPUT | 400 | Invalid serverId, duration, or malformed pubkey. | Check your request body JSON syntax. |
ERR_UNAUTHORIZED | 401 | Missing or invalid Authorization header. | Use Bearer <api_key> or Nostr <token>. |
ERR_PAYMENT_REQUIRED | 402 | Subscription exists but hasn't been paid yet. | Poll the status until it returns paid. |
ERR_MIGRATION_REQUIRED | 403 | Attempting to renew on a legacy server (us1). | Use the migration tool to move to us3. |
ERR_RESOURCE_NOT_FOUND | 404 | No subscription found for that paymentHash. | Verify your hash from the /create call. |
ERR_RATE_LIMIT_EXCEEDED | 429 | You've hit the rate limit. | Implement exponential backoff (Max 1 req/5s). |
ERR_INTERNAL_ERROR | 500/503 | Backend node is syncing or maintenance mode. | Wait 30 seconds and try again. |
🔍 Specific Scenarios#
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#
2. Configuration Management#
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.