# Publish to Promptbox - API v3.1 Publish static browser apps at https://apps.promptbox.cn/ and documents/media at https://www.promptbox.cn/publish/. No account or API key is required to create a publication. Promptbox cannot run PHP, Node.js, databases, private server code, or any other app backend. Apps can call documented Promptbox or external CORS-enabled APIs. - Endpoint: `https://www.promptbox.cn/api/publish.php` - [Live capabilities and availability](https://www.promptbox.cn/api/publish.php?action=capabilities) - [API reference](https://www.promptbox.cn/api/docs.html) - [Agent index](https://www.promptbox.cn/llms.txt) and [browser guide](https://www.promptbox.cn/agent-guide.html) - [OpenClaw skill](https://www.promptbox.cn/skills/promptbox-publish/SKILL.md) and [skill ZIP](https://www.promptbox.cn/skills/promptbox-publish.zip) Download the skill ZIP, extract its SKILL.md into a local `promptbox-publish/` folder, then run `openclaw skills install ./promptbox-publish`. Start a new session if the skill is not yet visible. This is a local skill installation; no ClawHub registry listing is required. Review third-party instructions before installing. ## Create and replace an app ```sh curl --fail-with-body https://www.promptbox.cn/api/publish.php \ -F 'mode=app' -F 'directory=my-app' -F 'file=@app.zip' ``` Supply one HTML/HTM file (becomes index.html), a ZIP, or UTF-8 HTML in JSON/form `text`. JSON example: `{"mode":"app","directory":"hello","text":"Hello

Hello

"}`. Do not pass filenames, URLs or base64 as a JSON file field. Let curl/FormData set the multipart boundary. Directory names use 1-80 ASCII letters/digits/underscores/hyphens, starting with a letter or digit. Collisions receive `_2`, `_3`, etc. Always use the returned directory and URL. ZIPs may contain index.html at the root, or one enclosing folder containing index.html and all app files. The publisher automatically strips that single folder and reports `stripped_prefix`. It ignores macOS metadata for root detection. Ambiguous layouts, multiple app roots, or deeper nesting are not guessed; supply a clean build folder. Relative paths such as `./assets/app.js` are required; `/assets/` addresses the host root. Creation returns HTTP 201: `ok`, `mode`, `directory`, `url`, private UUID `token`, `updated:false`, `deployment_mode:"replace"`, `files_written`, `removed_files`, `sanitized_files`, `deleted_files`, `stripped_prefix`, `bytes`, `expires_at`, and `deleted_expired`. Save the token privately outside your source/build directory. Possession grants control of that app. The server stores only a hash; lost tokens cannot be recovered. Do not log tokens or embed them in app files, Git repositories, public URLs, or ordinary handoff messages. **For future updates, upload the full build. An HTML-only update now removes all previously uploaded assets.** Updates replace the complete deployment. POST `mode=app`, `token`, and the full HTML/ZIP/text build. Explicit `action=replace` also works and requires a token. HTTP 200 returns `updated:true`. Every update must include index.html. Asset-only ZIP updates are no longer supported. Omitted paths appear in `deleted_files`; upload paths discarded by filtering appear in `removed_files`. Validation failures preserve the previous deployment. Replacement uses private staging and a rollback directory. ## Token-authenticated lifecycle Use `Authorization: Bearer UUID` (preferred) or a POST `token` field. Never put a token in query strings. Send `mode=app`; optional `directory` must match the token's app. POST action may be in JSON/form data or `?action=...`. Read-only status supports GET with the Authorization header. | Action | Method | Content | Result | | --- | --- | --- | --- | | `status` | GET or POST | Token only | URL, file list, byte size, created/changed timestamps and expiry; older apps may have null created_at | | `replace` | POST | Token + complete build | Replaces all files; deletes omitted paths; renews 30 days | | `delete` | POST | Token only | Immediately unpublishes app and invalidates token | | `rotate-token` | POST | Token only | Returns new token; old token immediately stops working; expiry unchanged | | `extend` | POST | Token only | Renews expiry to 30 days from now without changing files | Successful lifecycle operations return HTTP 200. Status never returns the secret. Status, delete and rotate-token do not consume publication quota and remain available when quota/storage is full. Extend consumes one publication use. Updates and extensions cannot revive expired apps. A lost rotation response loses the new token; save responses privately and do not retry rotation blindly. Delete removes hosted files, not browser storage or service-worker caches already saved on devices. ## Asset formats and validation Apps allow 25 MiB uploaded and expanded/resulting content, up to 1,000 archive entries/files. The HTTP body ceiling is 26 MiB. Encrypted/corrupt ZIPs, unsafe expansion ratios, duplicate/case-conflicting paths and unsafe paths are rejected or filtered as documented by the response. Dotfiles, links, server configuration, executable server code and node_modules are discarded. Allowed extensions: `html htm css js mjs json txt md png jpg jpeg gif webp ico avif woff woff2 ttf otf mp3 wav ogg m4a flac mp4 webm svg webmanifest xml wasm`. - SVG is sanitized with a conservative static element/attribute allowlist. Scripts, event handlers, styles, foreignObject, animations and external references are removed. Basic shapes, text, gradients, masks, clipping and local fragment references are supported. Review `sanitized_files` and visually check the result. - Web manifests must be UTF-8 JSON objects and are served as application/manifest+json. Set start_url, scope and icons relative to the app directory. A manifest does not guarantee browser install eligibility. - XML must parse without DTDs, entity declarations or processing instructions (other than the XML declaration). It is served as text/plain for data use, preventing active XML document rendering. - WASM must have the WebAssembly v1 header and is served as application/wasm. The browser validates full module structure and executes it in its WebAssembly sandbox. Header checking does not certify behavior or prevent CPU/memory abuse. Validation is not a malware scan. HTML/JavaScript remain executable browser code. ## Browser storage and isolation Apps have the normal HTTPS origin `https://apps.promptbox.cn`. All published apps share that origin's localStorage, IndexedDB, cookies and same-origin access. Use app-specific key/database names to avoid accidental collisions; names are not a security boundary. Any published app can read or change shared apps-origin data. Never store tokens, passwords or sensitive information there. The browser keeps localStorage and IndexedDB on `https://www.promptbox.cn`, `https://promptbox.cn`, and other Promptbox subdomains separate from the apps origin. Origin-Agent-Cluster and Permissions-Policy disable legacy document.domain relaxation; frames and embedding are also blocked. Do not expose trusted-site storage through permissive cross-origin bridges. Cookies follow domain/path rules rather than localStorage origin rules. A cookie explicitly scoped to `.promptbox.cn` can reach subdomains, including apps; use host-only cookies on trusted sites. Browser preferences can independently restrict storage/cookies. Service workers are supported with their normal script-directory scope. Put worker scripts inside the app directory, do not request broader scope, and remember device caches may outlive replacement or deletion. Use absolute `https://www.promptbox.cn/api/...php` helper URLs and omit browser credentials on cross-origin calls. The Origin header is now `https://apps.promptbox.cn`, not `null`. CORS-enabled helper access is still required. Scripts, forms and downloads work; frames, popups and base tags remain blocked by CSP. The canonical public documentation/API host is www.promptbox.cn, and new integrations should call it directly. For compatibility with deployed clients, promptbox.cn also serves requests directly without redirecting; the two names are separate browser origins even though they provide the same site and APIs. The apps host is separate. Changing the hostname used by a browser app does not migrate its existing cookies or browser storage. ## Documents and media POST `mode=file`, one multipart `file`, and optional basename `name`. Binary files allow 10 MiB; UTF-8 TXT/MD/JSON/CSV/TSV allow 1 MiB. Supported documents: PDF/DOCX/XLSX/PPTX/ODT/ODS/ODP. Supported media: JPG/JPEG/PNG/GIF/WEBP, MP3/WAV/OGG/M4A/FLAC/MP4/WEBM. SVG/XML/webmanifest/WASM support applies to app assets only. Office packages reject macros, embedded active objects and external resources except ordinary web/mail links. PDFs receive basic signature/active-content checks, not full sanitization. Documents download as attachments. HTTP 201 returns filename, url, bytes and expires_at. Duplicate filenames receive `_02`, `_03`, etc. Documents have no token or overwrite/lifecycle operations. HTML is always routed to app mode. Text JSON accepts name/text/extension (default txt), with title/content/ext aliases; conflicting aliases fail. ## Availability, expiry and errors GET capabilities includes `availability`: service (`available`, `rate_limited`, `storage_full`, `unavailable`), checked_at, publishes_remaining_this_hour, publishes_remaining_today, public_storage_remaining_bytes, quota_windows and advisory. Windows are rolling 60 minutes and 24 hours. These are snapshots, not reservations or a guarantee that a specific upload will fit. Global limits are 60 publications/hour, 300/day, 100 MiB public storage and 10,000 documents. Apps expire 30 days after successful replacement or extension; files expire 30 days after creation. Cleanup runs lazily on POST, so expired files may remain reachable until cleanup occurs. GET capabilities/status do not clean up. Keep local sources and tokens. For hosting beyond the standard 30-day period, contact Promptbox at admin@promptbox.cn to discuss extended hosting services. This is a separate arrangement; the public API's normal expiry and token rules continue to apply unless Promptbox confirms otherwise. Errors return `ok:false`, error text and help URLs. Fix 400/401/403/405/409/413/415/422 requests before retrying; 401 includes unknown/expired tokens. Honor Retry-After on 429; 507 means storage full. Investigate 500/503/network failures before repeating a creation: it may have succeeded and its token response may be lost. Creation retries can make duplicates. Replacing with the same token/build is safe to retry once the outcome has been investigated. After publication, inspect removed/sanitized/deleted paths and test the returned URL and interactions; report URL and expiry without revealing the token.