Pilot · API v0.2.0-dev
API Reference

Score a Telegram user in one HTTP call.

Two endpoints, one auth header, deterministic verdicts. Built for Telegram Mini Apps and TON projects that need to gate user actions in real time.

Updated · 2026-05-24 3 endpoints JSON over HTTPS

Introduction

Nexalix Guard is an anti-sybil scoring API for Telegram Mini Apps and TON projects. Send a user's tg_user_id plus their signed Telegram initData, get back a verdict — clean, suspicious, or sybil — with explainable reasons and a numeric score.

The surface is intentionally small: one scoring endpoint, one feedback endpoint, one health check. Everything interesting happens server-side.

Pilot status — 2026 Q2: first wave of merchants is onboarding. Email hello@nexalix.io for an API key. Pilots are free in exchange for score-request logs and post-hoc labelling.

Quickstart · 5 steps

  1. Get an API key from Nexalix Labs. Format nxg_<32 base62 chars>. Shown once — store it in your secret manager.
  2. Capture raw initData from Telegram.WebApp.initData on your client, send it to your own backend.
  3. POST to /api/v1/score from your backend with the key in the X-API-Key header.
  4. Branch on verdict — let clean through, soft-challenge suspicious, block sybil.
  5. Send feedback later when you confirm a user as a real human or as a farm — this trains the cross-project graph.

Authentication

Every request to /api/v1/* requires an API key in the X-API-Key header. The key value is a secret. The first 8 characters after the nxg_ prefix are a non-secret identifier safe to show in your own logs and UI.

http · header required on /api/v1/*
X-API-Key: nxg_abc12345xyz...
  • Soft limit: up to 10 active keys per merchant. Rotate by issuing a new key, then revoking the old one.
  • Keys are stored as Argon2id hashes — even Nexalix cannot recover the raw value.
  • Compromised key? Email security@nexalix.io for immediate revocation.

Base URL & versioning

EnvironmentBase URL
Productionhttps://guard.nexalix.io/api
Local developmenthttp://localhost:3000/api

Version lives in the URL path (/api/v1/...). Backwards-incompatible changes get a new major version. Additive changes within a major version never silently change response semantics. Track changes in the changelog section.

POST /v1/score

POST /api/v1/score X-API-Key required
Score a Telegram user. Returns verdict + explainable reasons.

Request body

FieldTypeRequiredNotes
tg_user_idinteger (int64)yesPositive Telegram user ID.
init_datastringyesRaw Telegram.WebApp.initData. HMAC-SHA256 verified server-side. Max 8192 chars.
wallet_addressstringnoTON wallet address if the user has connected one.
eventenumnosignup · claim_points · withdraw · custom
ipstringnoEnd-user IP if your backend can pass it.
user_agentstringnoEnd-user User-Agent header.

Example request

curl · POST application/json
curl -X POST https://guard.nexalix.io/api/v1/score \
  -H "X-API-Key: $NEXALIX_GUARD_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "tg_user_id": 123456789,
    "init_data": "query_id=AAH...&user=%7B%22id%22%3A123456789...&auth_date=1747900000&hash=...",
    "wallet_address": "EQDrjaLahLkMB-...-Tt2",
    "event": "claim_points"
  }'

200 response

json · 200 OK verdict: suspicious
{
  "score": 55,
  "verdict": "suspicious",
  "reasons": [
    { "code": "tg_account_age_lt_7d", "weight": 35 },
    { "code": "tg_no_username", "weight": 20 }
  ],
  "request_id": "01J4F7K2P8X9V6T2Q5R8N0M3W1"
}

Keep the request_id — you'll reference it when sending feedback. It's also returned on every error response for support requests.

Status codes

StatusWhen
200Verdict computed and persisted.
401 missing_api_keyNo X-API-Key header.
401 invalid_api_keyKey not recognized or revoked.
401 invalid_init_dataHMAC mismatch, expired auth_date, or tampered payload.
413Body exceeds the size limit.
422 VALIDATION_FAILEDPayload doesn't match the schema (e.g. missing tg_user_id).
503 SERVICE_UNAVAILABLEDatabase or Redis unreachable — retry with backoff.

POST /v1/feedback

POST /api/v1/feedback X-API-Key required
Confirm or refute a prior verdict. Drives model improvement.

Request body

FieldTypeRequiredNotes
request_idstringyesThe request_id from a prior /v1/score response.
kindenumyesconfirmed_sybil · confirmed_clean · unknown
commentstringnoFree text · max 2000 chars.

Example request

curl · POST application/json
curl -X POST https://guard.nexalix.io/api/v1/feedback \
  -H "X-API-Key: $NEXALIX_GUARD_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "request_id": "01J4F7K2P8X9V6T2Q5R8N0M3W1",
    "kind": "confirmed_sybil",
    "comment": "Wallet drained on first claim, never returned"
  }'

200 response

json · 200 OK
{
  "feedback_id": "a1b2c3d4-...",
  "request_id": "01J4F7K2P8X9V6T2Q5R8N0M3W1"
}

Status codes

StatusWhen
200Feedback recorded.
401Authentication failed (same codes as /score).
404request_id not found, or belongs to a different merchant.
409 CONFLICTFeedback for this request_id already exists. Each request can receive feedback exactly once.
422Invalid kind or oversized comment.
503Database unreachable.

GET /health

GET /health no auth
Liveness check. No DB or Redis calls — just confirms the process is up.
http · response 200 OK
GET /health  →  200 OK
{ "status": "ok", "version": "0.0.1" }

Wire this into your orchestrator's healthcheck. Extra headers (including a valid X-API-Key) are ignored — health is intentionally unauthenticated.

Verdict semantics

The score is a deterministic weighted sum, 0–100, clamped at both ends. Each triggered rule contributes its weight. The thresholds:

Score rangeVerdictRecommended action
0–39cleanLet the action proceed.
40–69suspiciousSoft challenge — extra captcha, delayed reward, manual review.
70–100sybilBlock the action. Optional appeal flow.

A rule may also raise a hard-block flag (e.g. known sybil cluster, blacklisted wallet). Hard-block forces verdict = "sybil" regardless of the numeric score. The score in the response still reflects the weighted sum so you can see why.

Thresholds are configurable. If you have a low-tolerance flow (token claim) or a high-tolerance one (free game level), tell us — we can tune per-merchant or per-endpoint.

Reason codes

Each entry in the reasons array has a stable code string and the weight it contributed. Codes do not change semantics within a major API version — you can safely match on them in your own logic and dashboards.

The first batch lands in Week 2 of the MVP:

tg_account_age_lt_7d
Telegram account younger than 7 days.
+35
tg_no_username
Account has no public username.
+15
tg_premium_bonus
Telegram Premium subscriber. Lowers score.
−20
tg_lang_mismatch
Language hint missing or inconsistent.
+10
tg_known_bot
`is_bot=true` in initData. Forces sybil verdict.
hard-block

More codes land as we add TON on-chain signals (Week 3) and behavioural signals (Week 4). Each new code is documented here before it ships.

Error envelope

Every error response, regardless of endpoint or status, has the same shape:

json · error envelope used on all 4xx/5xx
{
  "error": {
    "code": "invalid_api_key",
    "message": "API key not recognized or revoked",
    "details": { /* optional, structured */ }
  },
  "request_id": "01J4F7K2P8X9V6T2Q5R8N0M3W1"
}

The request_id field appears in every response — success or failure. Keep it in your logs; quoting it lets us trace any incident on our side.

Limits & retention

  • Request body size — up to 1 MB. init_data alone is capped at 8 KB.
  • Active API keys — up to 10 per merchant. Need more? Email us.
  • Score request retention — 90 days hot, then soft-deleted. Feedback windows count from the original request timestamp.
  • Rate limits — none enforced during pilot. Production rate limits will be per-merchant and disclosed at least 14 days before activation.
  • Payload privacy — we store a strict whitelist of fields from each request (parsed Telegram user id, auth date, platform, language, country code, user-agent, request id). Raw init_data, HMAC hashes, and any field outside that whitelist are never persisted.

Changelog

Public API changes are tracked in the repo's CHANGELOG.md (link active when the repo is published). Highlights:

  • v0.2.0-dev — first end-to-end implementation of /v1/score and /v1/feedback; explicit whitelist payload snapshot; Argon2id key hashing; 90-day retention.

Questions, missing docs, or want a key? Email hello@nexalix.io.