# ponk — useful browser apps, curated ponk is a small catalogue of browser apps that are useful and free to start. The collection currently lists one app (Wobble). Everything here is a working product, not a listing directory of placeholders. Browse the app directory: `https://ponki.app/apps`. Submit an app: `https://ponki.app/submit`. ## What this site offers - Curated app pages with honest pricing, offline and data notes. - A free MIT quick-install SDK and portable coding-agent skills (`/builders`), optional. - App submission for people and agents (`/submit`, `/api/submissions`, `/api/mcp`). - A free initial app, security and hosting review for apps being onboarded (best effort; not a security certification). Submissions are reviewed by a person. Nothing is published automatically, and being submitted or reviewed is not a security certification. ## HTTP API (v1) Base: `https://ponki.app` - `POST /api/submissions` — validate (`"preview": true`) or store one submission. - `GET /api/submissions?id=<32-char-id>` — public status. Contact email and private notes are never returned. Required fields: `appUrl` (public https), `contactEmail` (private), `priceModel` (`free` | `free_with_paid_extras` | `paid`), `offline.level` (`full` | `partial` | `none` | `unknown`) plus `offline.scope` when full/partial. Optional: `notes` (private, ≤600), `requestReview` (boolean), `idempotencyKey` (16–128 chars, also accepted as the `Idempotency-Key` header). The server never fetches or scans the submitted URL. Private, loopback, IP-literal and non-HTTPS addresses are rejected rather than probed. Example: ``` curl -sS -X POST https://ponki.app/api/submissions \ -H 'content-type: application/json' \ -H 'Idempotency-Key: 8f14e45f-ceea-4a1f-9c1a-0a1b2c3d4e5f' \ -d '{"appUrl":"https://wobble.example.com","contactEmail":"you@example.com","priceModel":"free","offline":{"level":"full","scope":"Workouts stay editable offline."},"requestReview":true}' ``` Submitting returns `201` with a stable `id` only after durable storage acknowledges the write, and `200` with `idempotentReplay: true` when the same retry key is reused with unchanged details. A key reused with different details returns `409 idempotency_key_conflict` and writes nothing; send changed details under a new key. If storage is unconfigured, the API answers `503 storage_unavailable` without writing. A storage or network failure after an attempted write can leave the outcome unconfirmed; retry the same payload and key. Limits: 8192 UTF-8 bytes per request. A project firewall limits POST requests to 12 per IP per minute. Durable application counters also target 4 submissions per IP per hour and 200 per day, best effort under concurrency. Application 429 responses include Retry-After; edge firewall responses may differ. Errors are structured: ``` { "ok": false, "error": { "code": "validation_failed", "message": "...", "hint": "...", "issues": [ { "field": "appUrl", "code": "app_url_not_https", "message": "..." } ] } } ``` ## MCP `POST /api/mcp` — Streamable HTTP, JSON-RPC 2.0, stateless, JSON responses. Modern `2026-07-28` requests send `MCP-Protocol-Version`, `Mcp-Method` (and `Mcp-Name` for `tools/call`) headers plus `params._meta["io.modelcontextprotocol/protocolVersion"]`; initialize-based clients (`2025-11-25`, `2025-06-18`) are also accepted. Tools: `preview_submission`, `submit_app`, `submission_status`. They share the HTTP schema and storage path. `GET /api/mcp` returns `405`: no event stream is offered. ## Notes for agents - Do not submit on someone else's behalf without their contact email and consent. - Do not send credentials, tokens or personal data beyond the contact email you were given. - The app URL is validated as text only; no server-side browsing happens. - Public contract: https://ponki.app/developers/submissions.md. - Deployment guide: https://ponki.app/builders/deploy.