Errors & status codes
Marvel keeps error surfaces narrow and category-only on purpose: you learn what to fix, never an internal detail or whether some other account’s email or key exists.
Proxy status codes
Section titled “Proxy status codes”Returned by the gateway at resi.marvel.sh:9000 during CONNECT.
| Status | Meaning | Fix |
|---|---|---|
407 | Missing or invalid credentials — no auth, or an unknown/revoked API key | Check the key is current and sent as the username. |
400 | Bad target string | See target errors for the exact reason. |
402 | Insufficient balance | Top up a bundle; a zero balance cannot proxy. |
503 | No live capacity for the requested country right now | Check /v1/availability; retry or pick a live country. |
502 | Gateway error | Transient — retry with backoff. Upstream, dial, and internal faults deliberately look identical here. |
Target errors
Section titled “Target errors”A malformed password (target string) is rejected with 400 and one of these fixed, safe reasons.
The message names the category of mistake — it never echoes your raw input back.
| Reason | Cause |
|---|---|
missing required target: country-<CC> (ISO 3166-1 alpha-2) | No country- field. |
invalid country code; expected ISO 3166-1 alpha-2, e.g. country-US | country wasn’t two letters. |
targeting is country-only; ASN/ISP selection is not supported | An -asn- or -isp- token was present. |
unknown target field; supported fields: country, session, min_purity | An unrecognized key. |
duplicate target field; country, session, and min_purity may each appear once | A field repeated. |
malformed target; each field must be <key>-<value> joined by '-' | A dangling key or empty token. |
invalid session id; allowed: letters, digits, underscore (1-64 chars) | Session id outside [A-Za-z0-9_]{1,64}. |
invalid min_purity; expected an integer 0-100 | min_purity not an integer in range. |
Control-API status codes
Section titled “Control-API status codes”Returned by api.marvel.sh/v1/*. The body is always { "error": "<message>" }.
| Status | Meaning |
|---|---|
401 Unauthorized | Missing/invalid bearer token, or a bad email/password at sign-in. |
402 Payment Required | Issuing a node on an empty balance. |
404 Not Found | Unknown resource — e.g. a key id that isn’t yours, or a country with no live capacity. |
409 Conflict | Sign-up with an email that already exists. |
422 Unprocessable Entity | Validation — bad country, session id, min_purity, email, or a password under 8 chars. |
503 Service Unavailable | A required subsystem (Reserve/selector) is not available right now. |
500 Internal Server Error | A fault on our side — logged, never detailed on the wire. |
Troubleshooting
Section titled “Troubleshooting”- Every request returns
407. The key is unknown or revoked, or it’s in the wrong field. Confirm it’s a currentmk_live_…key sent as the proxy username. 402even though I just paid. Credit lands when Stripe’s webhook confirms payment, not on the redirect. CheckGET /v1/usage—balance_bytesshould be non-zero once it settles.503for a country I expected. Capacity is live-only and honest. QueryGET /v1/availabilityto see what’s serveable this moment.- Sticky session changed IP. Exits expire (see
expires_at) or get dropped; the next request re-pins a fresh vetted exit. That’s self-healing, by design. - A whole country looks lower-grade than usual.
dominant_gradeandmean_purityfromGET /v1/availability/{country}reflect the current pool — grade availability moves with the Reserve.