<!-- BEGIN CHANGE: mapa vivo da API do Novo Portal -->

# Portal API map

Base URL (prod): `https://ot.whiteantidote.com/api/`  
Tambem: `dev.` (:8083), `ot-test.` (:8084), `ot-beta.` (:8085).  
Codigo: `html/portal/api/*.php`  
Auth: Bearer HMAC (`waMakeToken` / `waRequireAuth`). Contas `blocked` sao rejeitadas.

## Tiers

| Codigo | Significado |
|---|---|
| Public | Sem token |
| Optional | Token enriquece resposta |
| Auth | Bearer obrigatorio |
| Staff | `page_access > 2` |
| Subadmin | `page_access >= 5` |
| Admin | `page_access >= 6` |

## Endpoints (resumo)

### Publicos / leitura

| Endpoint | Auth | Notas |
|---|---|---|
| `home.php`, `news.php`, `changelog.php` | Public | CMS |
| `online.php`, `highscores.php`, `records.php`, `last-kills.php` | Public | Community; highscores inclui `patents` + `tasks` (stor 30602). Rankings/last-kills: so `salvar < 1`; online: `salvar <= 1` |
<!-- BEGIN CHANGE: character inclui task/addons lidos do DB + definicoes do servidor -->
| `character.php?name=` | Public | Perfil, task atual/daily (progresso/rank) e addons adquiridos |
<!-- END CHANGE -->
| `guilds.php`, `guild.php`, `wars.php`, `top-guilds.php` | Public/Optional | Guilds (sem cleanup em GET) |
<!-- BEGIN CHANGE: item-drops usa loot XML direto + sync de metadata por mtime -->
| `monsters.php`, `monster.php`, `item-drops.php`, `vocations.php`, `spells.php` | Public | Library (`item-drops`: loot direto dos XML do server, cache invalidado por mtime) |
<!-- BEGIN CHANGE: vocation-guide + matcher -->
| `vocation-guide.php` GET | Public | Guia `/vocations` + scores usados pelo `VocationMatcher` no create char |
<!-- END CHANGE -->
| `events.php`, `lottery.php`, `casting.php`, `tradeoff.php` | Public | Events |
| `serverinfo.php`, `team.php`, `rules.php`, `bans.php`, `addons.php` | Public | Info; addons = bonus level + Varkhal (`addon_itens.lua`) + drops via loot XML |
| `cleanup-notify.php` | CLI ou `?key=` (= secret.key) | E-mail aviso inactivity (idempotente) |
| `raids.php` | Public | Agenda raid.lua + Random_Raids |
| `tasks.php` | Public | Story + daily + ranks de `task_func.lua` |
| `items.php` | Public | Gear relevante de items.xml (+ wands) |
| `npcs.php` | Public | NPCs so de imported-spawn.xml |
| `potions.php` | Public | Potions + `?resource=heals` formulas |
| `community.php?resource=` | Public | Router legado |

### Conta

| Endpoint | Auth | Notas |
|---|---|---|
| `login.php` POST | Public | Token; bloqueia `blocked` |
| `register.php` POST | Public | Conta + 1 char |
| `lost-account.php` POST | Public | Recovery |
| `me.php` GET | Auth | Conta logada |
| `account-manage.php` POST | Auth | Senha/email/chars |
| `account-history.php` GET | Auth | Historico shop (PP+GP) + doacoes MP/PayPal |

### Economia

| Endpoint | Auth | Notas |
|---|---|---|
| `shop.php` GET/POST | Optional / Auth | `?catalog=donate\|guild` (campo na oferta unificada); buy -> fila OTS; `choices` se `needsChoice` |
| `shop-admin.php` | Subadmin | CRUD `z_shop_offer` (+ grupos) filtrado por `catalog` |
| `character-market.php` | Optional / Auth | list/unlist/buy PP |
| `serial-items.php` | Auth | Lista seriais do char (inv/depot/house) + busca por serial |
| `donate.php` | Optional / Auth | So checkout MP/PayPal (min R$20) |
| `mercadopago-webhook.php` | Public (MP) | Credita PP; idempotente `processed` |
| `mercadopago-return.php` | Public | Redirect pos-checkout |
| `paypal-ipn.php` | Public (PayPal) | Credita PP; idempotente `processed` |

### Guild manage

| Endpoint | Auth | Notas |
|---|---|---|
| `guild-create.php` | Auth | |
| `guild-manage.php` | Auth + rank | |
| `guild-update.php` | Auth + owner | |
| `guild-logo.php` | Auth + owner | Upload |
| `guild-admin.php` | Auth; delete/cleanup_guilds = Admin | cleanup_players scoped |

### Staff

| Endpoint | Auth | Notas |
|---|---|---|
| `portal-cms.php` | Staff | Hero/news/changelog/polls/contacts. News: `news_add` (notifica todos), `news_edit`, `news_delete`, `news_hide` |
| `admin-panel.php` | Staff GET; mutacoes 5/6 + audit + adminPassword | Wipe: `wipe_players` / `wipe_accounts`; POST `mass_delete_players`, `zero_guild_points`, `restore_premium_from_backup`, `orphan_delete` (ACL >= 6). Tools GET: `orphan_scan`, `player_trace`, `page_access_values` (dropdown dinamico), `houses` (livres/alugadas/em risco), `player_serials` (serial inline no inspector). Ver `docs/portal-security.md` |
| `admin-sql.php` POST | Admin (>=6) | Console SQL do portal (1 comando/vez). SELECT/SHOW direto; escrita exige `confirm`. Bloqueia information_schema/mysql/sys e DDL de banco/usuario. Toda execucao no Audit Log |
| `notifications.php` GET/POST | Auth | Sino do menu: `?countOnly=1`, lista; POST `mark_read`, `broadcast` (staff). Tabelas `z_notifications` + `z_notification_reads` |
| `status.php` GET | Public | Badge navbar tempo real (online/offline + count). Cache 10s do status protocol; conta so `salvar <= 1` |
<!-- BEGIN CHANGE: OTCv8 client updater -->
| `updater.php` POST/GET | Public | Manifesto OTCv8 (`url` + `files` CRC32 + `binary` opcional). Le `WA_HTML_ROOT/files-otc`. Sem auth. |
<!-- END CHANGE -->
| `namelock.php` | Staff | |
| `home-videos.php` POST | Admin | |
| `vocation-guide.php` POST | Admin | |
| `spells.php` / `community.php?resource=spells` | Public | Auto-sync `z_spells` a partir de `data/spells/spells.xml` (trigger por mtime). Ver `spells-sync-lib.php` |
| `helpdesk.php` | Flexible | Create notifica staff (sino, `page_access > 2`); staff reply notifica dono do ticket. Evitar expandir `?token=` |

## Money contracts

1. **Shop donate**: debit `premium_points` -> `z_ots_comunication` -> history `z_shop_history_*`
2. **Shop guild**: debit `guild_points` -> mesma fila -> `z_shop_history_*` com `catalog=guild`
3. **Character market**: soft-delete listado; buy transfere `account_id` + PP
4. **Donate**: portal **nao** credita no checkout; so webhooks com `processed`

<!-- END CHANGE -->
