Happy Decoder API
БеÑплатный API Ð´Ð»Ñ Ñ€Ð°Ñшифровки зашифрованных VPN-подпиÑок Happ
Quick Start
Ð”Ð»Ñ Ð±Ñ‹Ñтрого Ñтарта иÑпользуйте демо-ключ:
hd_demo_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6
Пример запроÑа:
curl -X POST https://happy-decoder.cc/api/v1/decrypt \
-H "Authorization: Bearer hd_demo_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6" \
-H "Content-Type: application/json" \
-d '{"url": "happ://crypt5/iaii..."}'
Свой API-ключ
Жмёшь — получаешь ключ. Ðикакой региÑтрации, никакой почты. Лимит ключа: 10 запроÑов/мин. Создание новых ключей — не чаще 1 раза в минуту Ñ Ð¾Ð´Ð½Ð¾Ð³Ð¾ IP.
Endpoint
{"url": "happ://crypt5/..."}{"decryptedUrl": "https://..."}OPTIONS → 204 без тела.Рабочий пример
Скопируйте и вÑтавьте — тот же payload иÑпользуетÑÑ Ð² наших теÑтах, раÑшифровываетÑÑ Ð´ÐµÐ¼Ð¾-ключом:
curl -sS -X POST https://happy-decoder.cc/api/v1/decrypt \
-H "Authorization: Bearer hd_demo_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6" \
-H "Content-Type: application/json" \
-d '{"url":"happ://crypt5/iaiiXVJvtrK5hvgAzi561Ub7bhqQlpjpmsUNxtcqWsVviJdXWYA+I6O+tYTuBn/sFOrKzmcz=Kw=R4rgbtm2XcU7s6dCaKIe5RNS06AbbBwQGeItWP66cevhs9VRlJ3wi0JMgHGnTixCd1I3GzbzXS4lAl4UFPHLM3HD1RMBR0Ok7uko/Vt6cnacwhNH/Dp+e0h1Pz/cYKAHTF8tA7SsKbe+amxgad8KgOrHNRhqjYNE1xwaEy3i9oRRVl+TvtXtmaocLZgN+WyCt2sHHWSS1hGj6trwrqJIrOFwLrD0yODDZX1OuWDE3/mnfM9BgWjWjpuvcu9IVF9bFn66WFEw5Yi28DYGP+qyQ3EEC+u64QAbbnpJPb8DNZjcatdBc9swPN5PifFIxIxJ+VMDpRJgIs81phWN3x/7yqktB0rYulYuPG5ScA4yWEgErp1/68nwmjaG0XrH9H1zMYSAIf65eL3h5SWyx5fnNrUXQ0gbm02jd6hpAsW4lcGnJDENGA6xm/VQTn/JmZRxyU5lZCgNNd2DdiizI4jckj0bzxiAg9Hd70sRIBOQ1SDHyYLD5NWlRhiwMKmMSi9LXDa57euTDs1hN8zUVEf9sTy0AUy4W9aSnGIvxJhmYjXq87E/LZnsFsBbf6CuKPJ2pQTY4kHuCZNAdG/JZwyTxSR+BRoRnci6PJDENuSoAnNFEM6bQJZppbvgSr0tI1YNVMcx97uanNW2FcJFpXdEU1CZY5Pb09l54cNqQyF6=oxgadi"}'
Ожидаемый ответ:
{"decryptedUrl": "https://sometext"}
Формат happ://add/<url> — passthrough, проÑто Ñрезает префикÑ:
curl -sS -X POST https://happy-decoder.cc/api/v1/decrypt \
-H "Authorization: Bearer hd_demo_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6" \
-H "Content-Type: application/json" \
-d '{"url":"happ://add/https://sub.example.com/abc"}'
{"decryptedUrl": "https://sub.example.com/abc"}
Примеры кода
Ð’ примерах ниже — обработка ошибок. API вÑегда возвращает JSON; при ошибке — поле error. Status code в теле не дублируетÑÑ, иÑпользуйте HTTP-код.
# -sS: молча, но ошибки транÑпорта показывать
# -w: выводим HTTP-код поÑле тела
curl -sS -w "\n%{http_code}\n" -X POST https://happy-decoder.cc/api/v1/decrypt \
-H "Authorization: Bearer hd_demo_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6" \
-H "Content-Type: application/json" \
-d '{"url": "happ://crypt5/..."}'
# Пример парÑинга через jq:
# curl -sS ... | jq -r '.decryptedUrl // .error'
import requests
def decrypt_happ(url: str, api_key: str) -> str:
r = requests.post(
"https://happy-decoder.cc/api/v1/decrypt",
headers={"Authorization": f"Bearer {api_key}"},
json={"url": url},
timeout=10,
)
data = r.json()
if "error" in data:
raise RuntimeError(f"{r.status_code}: {data['error']}")
return data["decryptedUrl"]
print(decrypt_happ("happ://crypt5/...", "hd_demo_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"))
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
)
func decryptHapp(url, apiKey string) (string, error) {
body, _ := json.Marshal(map[string]string{"url": url})
req, _ := http.NewRequest("POST",
"https://happy-decoder.cc/api/v1/decrypt",
bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+apiKey)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
var out struct {
DecryptedURL string `json:"decryptedUrl"`
Error string `json:"error"`
}
if err := json.NewDecoder(resp.Body).Decode(&out); err != nil {
return "", err
}
if out.Error != "" {
return "", fmt.Errorf("%d: %s", resp.StatusCode, out.Error)
}
return out.DecryptedURL, nil
}
func main() {
plain, err := decryptHapp("happ://crypt5/...", "hd_demo_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6")
if err != nil { fmt.Println("err:", err); return }
fmt.Println(plain)
}
using System.Net.Http;
using System.Text;
using System.Text.Json;
async Task<string> DecryptHapp(string url, string apiKey) {
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {apiKey}");
var body = new StringContent(
JsonSerializer.Serialize(new { url }),
Encoding.UTF8, "application/json");
var resp = await client.PostAsync("https://happy-decoder.cc/api/v1/decrypt", body);
var json = await resp.Content.ReadAsStringAsync();
using var doc = JsonDocument.Parse(json);
var root = doc.RootElement;
if (root.TryGetProperty("error", out var err)) {
throw new Exception($"{(int)resp.StatusCode}: {err.GetString()}");
}
return root.GetProperty("decryptedUrl").GetString()!;
}
Console.WriteLine(await DecryptHapp("happ://crypt5/...", "hd_demo_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"));
// Работает из браузера (CORS включён) и из Node.js (18+)
async function decryptHapp(url, apiKey) {
const r = await fetch("https://happy-decoder.cc/api/v1/decrypt", {
method: "POST",
headers: {
"Authorization": `Bearer ${apiKey}`,
"Content-Type": "application/json"
},
body: JSON.stringify({ url })
});
const data = await r.json();
if (data.error) throw new Error(`${r.status}: ${data.error}`);
return data.decryptedUrl;
}
decryptHapp("happ://crypt5/...", "hd_demo_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6")
.then(console.log)
.catch(err => console.error(err));
Rate Limiting
Счётчик — per-key, не per-IP. Сколько бы IP вы ни иÑпользовали Ñ Ð¾Ð´Ð½Ð¸Ð¼ ключом — лимит общий.
Ðлгоритм — sliding window: окно в 60 Ñекунд Ñкользит от момента каждого запроÑа. Счётчик уменьшаетÑÑ Ð¿Ð¾ мере иÑÑ‚ÐµÑ‡ÐµÐ½Ð¸Ñ Ñтарых запроÑов, а не ÑбраÑываетÑÑ Ñ€Ð°Ð· в минуту.
При превышении лимита Ñервер вернёт 429:
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
{"error": "rate limit exceeded"}
Коды ошибок
Ð’Ñе ответы — JSON Ñ Content-Type: application/json, Ð²ÐºÐ»ÑŽÑ‡Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ¸.
| Code | Response | ОпиÑание |
|---|---|---|
| 200 | {"decryptedUrl": "..."} |
УÑÐ¿ÐµÑˆÐ½Ð°Ñ Ñ€Ð°Ñшифровка |
| 204 | нет тела | Ответ на CORS preflight (OPTIONS) |
| 400 | {"error": "invalid request body"} |
Ðекорректный JSON в теле запроÑа |
| 400 | {"error": "crypt5: RSA decrypt failed..."} |
Ошибка раÑшифровки (невалидные или чужие данные) |
| 400 | {"error": "crypt5: payload too short..."} |
Повреждённый или обрезанный payload |
| 401 | {"error": "missing or invalid api key"} |
ОтÑутÑтвует или неверный API-ключ |
| 403 | {"error": "api key is inactive"} |
Ключ деактивирован админиÑтратором |
| 405 | {"error": "method not allowed, use POST"} |
ИÑпользован неверный HTTP-метод |
| 429 | {"error": "rate limit exceeded"} |
Превышен лимит запроÑов (Ñм. Rate Limiting) |
Поддерживаемые форматы
happ://crypt/— RSA-1024 / PKCS#1 v1.5 (Ñамый Ñтарый, клиенты ранних верÑий)happ://crypt2/— RSA-4096 / PKCS#1 v1.5happ://crypt3/— RSA-4096 / PKCS#1 v1.5 (другой приватный ключ)happ://crypt4/— RSA-4096 / PKCS#1 v1.5 (другой приватный ключ)happ://crypt5/— гибридное: RSA-4096 оборачивает ÑеÑÑионный ключ, ChaCha20-Poly1305 шифрует данные (актуальный формат)happ://add/— passthrough, Ð¿Ñ€ÐµÑ„Ð¸ÐºÑ ÑрезаетÑÑ, URL возвращаетÑÑ ÐºÐ°Ðº еÑтьhttps:///http://— passthrough, URL возвращаетÑÑ ÐºÐ°Ðº еÑть
Universal Proxy Link
Ðндпоинт /p/ — публичный HTTP-прокÑи Ð´Ð»Ñ Ð¿Ð¾Ð´Ð¿Ð¸Ñок. Идёт за вашей подпиÑкой Ñ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÐ°Ð¼Ð¸ выбранного клиента (Happ User-Agent, HWID, модель уÑтройÑтва) и возвращает тело как еÑть. КонÑтруктор ÑÑылки Ñ UI — на Ñтранице Proxy.
Ð’ отличие от /api/v1/decrypt, Ñтот Ñндпоинт не требует API-ключа: его задача — быть подÑтавленным напрÑмую в любой xray/Mihomo/sing-box-клиент.
u — URL подпиÑки (https://, http://, happ://crypt*/, happ://add/) — обÑзательныйua — User-Agent (по умолчанию Happ/3.24.1; none — не отправлÑть)hwid — 1/0 или произвольное значение HWIDos — android (по умолчанию) или iosver — верÑÐ¸Ñ ÐžÐ¡, по умолчанию 14model — модель уÑтройÑтва, по умолчанию Pixel 8seed — 1: HWID детерминированно из URL подпиÑкиContent-Type, Profile-Title, Subscription-Userinfo, Profile-Update-Interval) проброшены от апÑтрима.Примеры
# Минимум: только URL подпиÑки (дефолтный Happ-identity) curl -sS 'https://happy-decoder.cc/p/?u=https%3A%2F%2Fexample.com%2Fsub' # Ð¡Ð²Ð¾Ñ Ð¼Ð¾Ð´ÐµÐ»ÑŒ и верÑÐ¸Ñ iOS curl -sS 'https://happy-decoder.cc/p/?u=https%3A%2F%2Fexample.com%2Fsub&os=ios&ver=17.4&model=iPhone+16+Pro' # Ð—Ð°ÑˆÐ¸Ñ„Ñ€Ð¾Ð²Ð°Ð½Ð½Ð°Ñ happ://crypt5/ ÑÑылка curl -sS 'https://happy-decoder.cc/p/?u=happ%3A%2F%2Fcrypt5%2Fiaii...' # Детерминированный HWID, чтобы провайдер видел один и тот же device-id curl -sS 'https://happy-decoder.cc/p/?u=https%3A%2F%2Fexample.com%2Fsub&seed=1'
Лимиты
Коды ошибок
| Code | Тело | ОпиÑание |
|---|---|---|
| 400 | missing 'u' parameter | Ðе передан URL подпиÑки |
| 400 | invalid url scheme | ПоддерживаютÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ http(s):// и happ:// |
| 400 | decrypt: ... | Ðе удалоÑÑŒ раÑшифровать happ://crypt* ÑÑылку |
| 403 | private/local address blocked | ÐпÑтрим резолвитÑÑ Ð² приватную/локальную Ñеть |
| 429 | rate limit exceeded | Превышен лимит 30 запроÑов/мин Ñ Ð²Ð°ÑˆÐµÐ³Ð¾ IP |
| 502 | upstream: ... | ÐпÑтрим не отвечает / timeout / TLS-ошибка |
| 502 | upstream returned HTTP NNN | ÐпÑтрим вернул ≥ 400 (текÑÑ‚ ответа прокÑируетÑÑ ÐºÐ°Ðº еÑть) |
ПриватноÑть
Ð’ логах ÑохранÑетÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ SHA-256-хеш URL, домен апÑтрима и факт обращениÑ. Сама ÑÑылка подпиÑки в открытом виде не ÑохранÑетÑÑ.
Health check
Ðндпоинт Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ¸ доÑтупноÑти ÑервиÑа. Возвращает 200 OK когда ÑÐµÑ€Ð²Ð¸Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ð°ÐµÑ‚. ИÑпользуйте в uptime-мониторах.
curl -sS https://happy-decoder.cc/health
{"status": "ok"}