License verification and tool results for tool developers.
All endpoints live under https://hydra-hq-ecru.vercel.app. Always use the production address — preview deployment addresses change and may be protected. Every request is a live database check: there is no caching anywhere in the verify path, so a change on the website (delete, block, expiry) is visible to the very next call.
https://hydra-hq-ecru.vercel.app
Every tool has its own API key (qyrx_live_…, shown on the tool's page in the panel). Send it as the x-api-key header, or as the api_key field in a JSON body. The key identifies the tool; the license key identifies the customer. Both are required for verify and results. A wrong or missing API key returns 401 bad_api_key.
The only call that decides whether a tool may run.
POST https://hydra-hq-ecru.vercel.app/api/verify
Content-Type: application/json
x-api-key: qyrx_live_...
{
"license_key": "QYRX-XXXX-XXXX-XXXX",
"hwid": "B47F14C8B467CE95...",
"ip": "103.96.71.241", // optional
"app_version": "1.4.2", // optional
"device_name": "DESKTOP-ABC", // optional
"device_os": "Windows 11", // optional
"ip_country": "BD" // optional
}Success (200):
{
"valid": true,
"expires_at": "2026-12-12T09:00:00.000Z",
"device_limit": 1,
"devices_used": 1,
"reverify_after_seconds": 3600,
"issued_at": "2026-11-12T13:00:00.000Z",
"notifications": [ ... ],
"ads": [ ... ],
"latest_version": "1.5.0", // only when the tool sets one
"update_available": false, // only when the tool sets one
"signature": "…" // HMAC-SHA256, see below
}reverify_after_seconds is the deadline for the next check (currently 3600 = 1 hour). issued_at is when this response was created — a tool must only trust a response issued moments ago, never a stored one. notifications and ads are panel announcements / Telegram channel ads for the tool to display; they are absent from error responses.
Every failure returns { "valid": false, "error": "<code>" }:
| HTTP | Error | What it means / what the tool must do |
|---|---|---|
| 503 | system_disabled | The owner turned the whole license system OFF (kill-switch). Stop immediately, show “system is down”. Retry later — never work around it. |
| 400 | invalid_hwid | No HWID was sent, or it is shorter than 8 characters. Fix the HWID the tool reports (a real device id is a long hex string) — it does not consume a device slot, and it is not a ban. |
| 401 | bad_api_key | Wrong or missing tool API key. Stop and show a configuration error — retrying the same key will trip the rate limit and then the IP auto-block. |
| 403 | ip_blocked | This IP is blocked. Stop; the user must ask the owner to unblock it. Auto-blocks lift themselves after 24 hours; manual blocks do not. |
| 403 | license_blocked | The license was blocked on the website. Stop; only the owner can unblock it. |
| 403 | expired | The license expired. Stop; only the owner can extend it. |
| 403 | device_blocked | This device (HWID) was blocked. Stop. |
| 403 | device_limit | All device slots are used (default 1). The user must request an HWID reset from the panel, or the owner must raise the limit. A placeholder HWID sent on the first run binds a slot — see HWID rules below. |
| 403 | tool_disabled | The whole tool was disabled on the website. Stop. |
| 403 | update_required | The tool version is older than the minimum set on the website. The user must update the tool. |
| 404 | license_not_found | No such license for this tool — it was deleted, or the key was mistyped. Stop. (A deleted license fails here on the very next verify.) |
| 429 | rate_limited | Too many failed attempts (20 failures per IP or per tool in 10 minutes, or 300 total calls per IP in 10 minutes). Wait retry_after_seconds (600) before retrying — hammering on will get the IP auto-blocked. |
A successful verify carries signature: HMAC-SHA256 (hex) of the canonical string {"tool":"<slug>","license_key":"<key>","expires_at":"<ISO>","devices_used":<n>} keyed by AUTH_SECRET (shared with each tool out of band, like the API key). Recompute it and compare in constant time: a match proves the response came from HydraHQ and was not tampered with. Only success responses are signed; if AUTH_SECRET is not set, the field is omitted. Note: the signature proves the response is genuine — it does NOT make a stored response fresh. Always call the API live and check issued_at.
POST https://hydra-hq-ecru.vercel.app/api/deactivate
Content-Type: application/json
x-api-key: qyrx_live_...
{ "license_key": "QYRX-XXXX-XXXX-XXXX", "hwid": "B47F14C8B467CE95..." }Removes one device binding from a license (200 { "ok": true, "deactivated": true }). Limited to 5 HWID resets per license per 30 days — further attempts return 429 reset_limit. The same license/tool checks as verify apply (bad_api_key, license_not_found).
GET https://hydra-hq-ecru.vercel.app/api/health?api_key=qyrx_live_... GET https://hydra-hq-ecru.vercel.app/api/info?api_key=qyrx_live_...
Lightweight checks that need only the tool API key (query parameter or x-api-key header) — no license needed. Success: 200 { "ok": true, "tool": "<name>", "notifications": [...], "ads": [...] }. Wrong key: 401 { "ok": false, "error": "bad_api_key" }./api/info additionally returns 403 tool_disabled when the tool is disabled. Neither endpoint verifies a license and neither grants access to run — they are for connectivity and announcements only.
POST https://hydra-hq-ecru.vercel.app/api/results
Content-Type: application/json
x-api-key: qyrx_live_...
{
"license_key": "QYRX-XXXX-XXXX-XXXX",
"hwid": "B47F14C8B467CE95...",
"type": "valid_data", // or "keyword" | "target_hit"
"data": { ... }, // required: string or JSON object, max 64 KB
"keyword": "paypal", // optional, max 500 chars
"target": "paypal.com", // optional, max 500 chars
"ip": "103.96.71.241" // optional
}The license check runs FIRST, with the exact verify contract above: on any verify failure the same status and error body are returned and nothing is stored. On success the result is stored and forwarded to the owner on Telegram as .txt files (valid data, keywords, target hits). Success: 200 { "ok": true, "id": 12, "tool": "<slug>", "received_at": "<ISO>" }. Bad payload: 400 invalid_payload; over 64 KB: 413 payload_too_large.
For the files to render in the owner's format, send structured data: email + password, country, emails (count), smtp (host:port, only when SMTP works), and keyword matches as matches: [{ keyword, count, items: [{ subject, date }] }]. A plain-string data still works — it is delivered as-is.
GET https://hydra-hq-ecru.vercel.app/api/content?api_key=…&license_key=…&hwid=… returns the tool's custom content payload, but only when the license verifies — it runs the same license check as POST /api/verify, so the same errors apply.
The server can only enforce the license when the tool asks. These rules are not optional — a tool that breaks them can keep working on a deleted, blocked or expired license, and nothing on the website can stop it:
POST /api/verify with the license key and the real HWID. Never skip it because the tool “was activated before”.reverify_after_seconds (1 hour) while the tool is open. A license deleted, blocked or expired on the website takes effect on the next verify, so this is what bounds the delay to at most one hour.license_not_found, license_blocked, expired, system_disabled, and also network errors, timeouts, HTTP 5xx, and an unreachable website. There is no offline grace period, no cached activation, no “keep working if the site is down”. If the website is off, the tool is off.issued_at and reject responses older than a few minutes."1") is rejected with invalid_hwid — and if a placeholder ever did bind, it would consume the license's device slot and lock out the real device with device_limit.rate_limited, wait retry_after_seconds before retrying. Hammering on failure trips the IP auto-block (20 failures in 10 minutes), which blocks the whole IP for 24 hours.Minimal correct loop (Python):
import time, requests
BASE = "https://hydra-hq-ecru.vercel.app"
API_KEY = "qyrx_live_..." # per-tool key, never shipped to users
LICENSE = "QYRX-XXXX-XXXX-XXXX"
HWID = get_machine_hwid() # stable device id, >= 8 chars
def verify():
try:
r = requests.post(f"{BASE}/api/verify",
headers={"x-api-key": API_KEY},
json={"license_key": LICENSE, "hwid": HWID},
timeout=15)
except requests.RequestException:
return None # unreachable -> STOP (fail closed)
if r.status_code != 200:
return None # any failure -> STOP
return r.json()
# on launch, and again at least every reverify_after_seconds:
result = verify()
if not result or not result.get("valid"):
print("License check failed - stopping.")
raise SystemExit(1)
time.sleep(result.get("reverify_after_seconds", 3600))
# ... verify() again before the next work session ...The owner can turn the whole license system OFF from the panel (Settings → System kill-switch, Owner only). While it is off, POST /api/verify returns 503 { "valid": false, "error": "system_disabled" } for every license, and POST /api/results is rejected the same way — so every tool stops on its next verify. The panel itself keeps working, so the owner can turn it back on at any time. Tools must treat system_disabled like any other failure: stop, do not work around it, retry later.
Verify enforces, per 10-minute window: 20 failed attempts per IP or per tool, and 300 total calls per IP. Past that it returns 429 rate_limited with retry_after_seconds (600). 20 failed attempts in 10 minutes also auto-blocks the IP for 24 hours (it lifts itself; a manual block from the panel is permanent until an admin unblocks it). Failed attempts include mistyped keys and wrong API keys — so a tool must stop and show the error instead of retrying in a loop.
Each license has a device limit (default 1). The first verify from a new HWID registers that device; further HWIDs are rejected with device_limit until a slot is freed (POST /api/deactivate, or an HWID reset approved in the panel — at most 5 resets per license per 30 days). A blocked device returns device_blocked. HWIDs are case-sensitive strings; send the same value every time.
Questions? This page documents the live system — if an error string appears here it is returned by the code, and if a field is listed here the API accepts it. Panel sign-in: /login.