# htmlshare publisher API instructions
htmlshare publishes generated HTML/CSS/JS bundles and returns URLs that humans can open. This deployment is account-controlled: publishing requires a confirmed publisher account or an `hsk_...` API key.
Production base URL:
```text
https://share.ecija.ai
```
Use htmlshare when an assistant has generated an HTML report, explanation, prototype, market scan, or other static artifact and an authorized publisher wants to share it.
## Default: registered publish
```http
POST https://share.ecija.ai/api/v1/publish
Authorization: Bearer hsk_...
Content-Type: application/json
{
"mode": "registered",
"title": "My report",
"folder": "my-report",
"visibility": "recipients",
"share": {
"emails": ["reader@example.com", "@example.com"]
},
"files": {
"index.html": "
My report
"
}
}
```
Copy-ready curl example:
```bash
curl -X POST https://share.ecija.ai/api/v1/publish \
-H 'authorization: Bearer hsk_...' \
-H 'content-type: application/json' \
--data '{"mode":"registered","title":"My report","folder":"my-report","visibility":"recipients","share":{"emails":["reader@example.com","@example.com"]},"files":{"index.html":"My report
"}}'
```
Optional `folder` sets the public URL folder: `/f/my-report/`. It is normalized to URL-safe lowercase letters, numbers, and dashes. The publish request fails with `409 Conflict` if the folder already exists. `slug` is accepted as an alias for `folder`.
## Updating an existing publication
Use the MCP tool `configure_html` to change settings without replacing files:
```json
{
"publication_id_or_slug": "my-report",
"title": "Updated report title",
"visibility": "recipients",
"require_registration": true,
"emails": ["reader@example.com", "@example.com"]
}
```
Valid visibility values are `private`, `company`, `recipients`, `signed`, and `public`. `emails` or `share.emails` add recipient/domain targets; signed visibility requires specific email addresses, not domain targets.
Use `unpublish_html` to remove a publication from shared/public access without deleting its files:
```json
{
"publication_id_or_slug": "my-report",
"revoke_access": true
}
```
`unpublish_html` sets visibility to `private` and requires registration. By default it removes recipient/domain shares, pending magic links, and signed access tokens while retaining signed audit proofs.
Use `delete_html` only when the publication and its files must be permanently deleted:
```json
{
"publication_id_or_slug": "my-report",
"confirm_delete": true
}
```
Use the MCP tool `update_html` to update an owned publication. Identify it with `publication_id_or_slug`, `id`, or `slug`.
```json
{
"publication_id_or_slug": "my-report",
"title": "Updated report",
"visibility": "company",
"files": {
"index.html": "Updated
",
"assets/app.js": "console.log('updated')"
},
"delete_files": ["assets/old.js"]
}
```
Files listed in `files` are added or replaced. To replace the main document, upload a new `index.html`. `delete_files` can remove secondary files, but `index.html` cannot be deleted; replace it instead.
## Publishing a React/Vite build
You can publish a React app when it is compiled to static files. Build locally first:
```bash
npm run build
```
Then publish the generated `dist/` contents, including `index.html` and referenced `assets/*.js` and `assets/*.css` files, as entries in the `files` object.
For Vite apps, prefer relative asset paths so the app works under the htmlshare publication URL (`/f//`):
```ts
// vite.config.ts
export default defineConfig({
base: "./",
});
```
If the app uses client-side routing, prefer hash routing (`HashRouter`) instead of browser history routing. Direct paths such as `/dashboard` may not reload correctly inside a static htmlshare publication, while `/#/dashboard` will.
Current upload support is text-oriented (`html`, `css`, `js`, `json`, `svg`, `txt`, `md`, etc.). If the React build includes binary images, fonts, videos, or other binary files, either inline them as base64/data URLs during the build or ask for ZIP/multipart bundle support before publishing.
The maximum publication payload is 100 MB.
## Roles
- `viewer`: can sign in and open files shared with their email or domain.
- `publisher`: can publish files, create API keys, manage recipients, and inspect access activity.
- `admin`: same publishing permissions, reserved for administrative expansion.
New accounts become publishers only when their email domain is configured in `PUBLISHER_EMAIL_DOMAINS`. Other accounts can register as viewers but cannot create publications or API keys.
## Access modes
- `private`: only the owner can open it from the console.
- `company`: any signed-in account whose email domain is configured in `PUBLISHER_EMAIL_DOMAINS` can open it.
- `recipients`: only listed emails or domain targets such as `@example.com` can open it.
- `signed`: specific email recipients receive a signed-access token and htmlshare records proof.
- `public`: anyone with the link can open it.
For `signed`, use specific email addresses only. Domain targets are valid for `recipients`, not signed legal proof.
## Getting an API key
1. Sign in with a publisher account.
2. Open the app.
3. Create an Agent key.
4. Store the `hsk_...` token in the assistant or CI secret store.
The `/api/v1/ai/signup` endpoint can start publisher onboarding, but it only returns or emails keys for domains allowed by `PUBLISHER_EMAIL_DOMAINS`. If the email is external, htmlshare sends a viewer login link and rejects publishing.
## Fast publish
Anonymous or no-token publishing is disabled by default on this deployment. `mode: "fast"` is only available when the server is explicitly configured with `ENABLE_FAST_PUBLISH=true`.
Do not use `mode: "fast"` unless `/api/v1/publish` discovery returns `"fast_enabled": true`.
## MCP
Remote MCP endpoint:
```text
https://share.ecija.ai/mcp
```
For Claude remote MCP, add the endpoint above and press Connect. htmlshare advertises OAuth metadata, asks the user to sign in with Microsoft, and issues Claude a per-user OAuth bearer token. Do not use one shared token for all users.
For scripts, CI, or local stdio MCP clients that cannot use browser OAuth, create a personal `hsk_...` key from `Agent keys` and configure:
```text
HTMLSHARE_URL=https://share.ecija.ai
HTMLSHARE_TOKEN=hsk_...
```
## Safety
Never publish secrets, credentials, private keys, tokens, raw personal data, or confidential material unless the user explicitly instructs you and the visibility is appropriately restricted.