Files
autoreg-skills-max/skills/apodex-batch-reg/references/promo-credits-investigation.md

5.2 KiB
Raw Blame History

Apodex $20 Promo Credits — Investigation (2026-10-03)

VERDICT (proven, 70+ accounts)

Email-OTP registration via client_id=apodex-platform-web gets $0 promotional credits. Verified on ~70 accounts:

  • GET https://platform.apodex.ai/v1/user/credit-grants → {"grants":[]} on every account
  • GET /v1/user/account → balance_cents:0, credits.active_cents:0, topup_promo:null, discount_promo:true (topup discount only, not money)
  • GET /v1/user/resource-packages → {"active_packages":[],"expired_packages":[]}
  • Any POST api.apodex.ai/v1/chat/completions with the key → HTTP 402 insufficient_balance (key is valid, balance is zero)
  • Delayed-grant hypothesis disproven: account created 4h earlier still grants:[].

What the "$20" actually is

  1. The email «Everything you need to make your first Apodex API call» is a PRICING email, not a credit grant. Its "$20.00" is the output price per request of the Deep Research tier (Deep Research $5.00 input / $20.00 output, Deep Solve $25, Deep Discover $100). The "Limited-time 20% off Core Models" is discount_promo:true — discount at settlement, no code, no cash.
  2. The «Promotional Credits US$20.00 Active, valid until 2026-11-02» screenshot matches the promo window of the consumer app welcome bonus (see below) — same expiry 2026-11-02 (expires_at=1793616663). Accounts showing $20 were NOT created via our email-OTP platform flow.

TWO DIFFERENT PRODUCTS share auth.apodex.ai

Developer platform Consumer research app
Host platform.apodex.ai + api.apodex.ai www.apodex.ai
client_id (verify-login) apodex-platform-web apodex-web
Signup bonus for email OTP NONE ($0) Welcome Bonus 300 credits (/api/vip/info → credit_balance:300), expires 2026-11-02
Token cross-validity 401 on www APIs 401 on platform APIs
API surface /v1/chat/completions (OpenAI-compat), /v1/api-keys, /v1/user/* /api/vip/info, /api/vip/plans, /api/vip/boost, /api/vip/credit-transactions, /api/vip/invoices

Consumer 300 credits are research-chat units, NOT USD, and cannot be spent via the API. Do not advertise them as "$20".

Console endpoint inventory (captured from real logged-in browser session)

Platform console calls these on load (use for audits — all accept Authorization: Bearer <access_token>):

GET /v1/user/account
GET /v1/user/credit-grants      <- the authoritative promo-credit check
GET /v1/user/resource-packages
GET /v1/user/usage?days=30
GET /v1/payments/history?limit=20
GET /v1/api-keys
GET /auth/region

404 (do not exist): /v1/user/credits, /v1/promo-codes, /v1/credits, /v1/balance, /v1/promotions, /v1/coupons.

Remaining untested hypotheses for getting real $20 (in priority order)

  1. OAuth signup (Google / GitHub buttons on platform login). GitHub OAuth flow reachable: https://auth.apodex.ai/api/auth/github?return_to=<platform url> (validates return_to host). One pooled GH account returned error=access_denied (app previously authorized/revoked) — needs a fresh GH account per attempt, browser-based (Playwright; urllib dies on the state cookie/redirect chain). NOT yet proven to grant $20.
  2. Geo/IP gating — signup from residential US IP. Not tested (free proxies all dead at the time).
  3. Promo code — no redeem/coupon endpoint exists in either bundle (redeem:0, coupon:0, promotional:0 hits in console+www JS, 3MB scanned). Likely dead end unless a code is applied at signup via query param.
  4. The screenshot may simply be from the promo's landing/marketing or another user's OAuth account — treat channel posts claiming "$20 for everyone" as unverified bait until an OAuth/geo account reproduces it.

Auth flow details (platform, for OAuth work)

  • Login page offers: email OTP, password, Continue with Google, Continue with GitHub.
  • localStorage keys (from console bundle): apodex_auth_token, apodex-user-storage, apodex_pp_access_token, apodex_pp_refresh_token, apodex_pp_access_expires_at, apodex_signed_in; cookie apodex_auth_token.
  • Injecting tokens into localStorage does NOT authenticate the console — it redirects to /login?redirect=%2Fconsole. Only a real OTP/OAuth login in the browser yields a working console session; capture API responses during that session instead.
  • verify-login payload: {"email":..., "code":..., "client_id":"apodex-platform-web"} → data.tokens.{access_token,refresh_token}, user.id = email_xxxxxxxxxxxx.

Operational lesson: OTP stealing between concurrent processes

batch100.py running in background + a single-account probe both call read_otp() on the same Gmail inbox. The batch's reader consumes/marks messages first (UNSEEN search), so the probe gets OTP: None even though the mail arrived. Symptom: probe hangs 3 min then "no otp" while the batch log shows fresh OK registrations. Both processes hitting /api/auth/passwordless/send-code also share one rate-limit bucket → mutual 429 (PASSWORDLESS_SEND_RATE_LIMITED, backoff 60s×hits). Rule: before any single-shot OTP probe, kill ALL other python processes touching the inbox (psutil cmdline match on batch100.py; killing the terminal session is not enough if it spawned children).