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

59 lines
5.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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).