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.17.0; 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"}