# 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`. ## 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_... ``` Project-aware MCP tools should be preferred for new appshare work: - `list_projects` - `create_project` - `publish_app` - `promote_project_app` - `list_project_publications` - `get_project_me` - `list_table_rows` - `create_table_row` - `update_table_row` - `delete_table_row` - `get_project_table_schema` - `upsert_project_table_schema` - `delete_project_table_schema` - `list_storage_objects` - `put_storage_object` - `delete_storage_object` - `list_project_secrets` - `upsert_project_secret` - `delete_project_secret` - `generate_project_llm` - `list_project_llm_logs` - `create_project_job` - `list_project_jobs` - `get_project_job` - `list_project_functions` - `upsert_project_function` - `invoke_project_function` - `delete_project_function` - `list_project_webhooks` - `create_project_webhook` - `delete_project_webhook` - `list_project_webhook_deliveries` - `get_project_runtime_policy` - `upsert_project_runtime_policy` - `generate_project_sdk` - `list_project_audit_logs` Use `publish_app` with a concrete `project_id` for new appshare publications. It defaults to the server-side `dev` environment for Codex iteration. Pass `environment` when reading or writing project resources, and use `promote_project_app` to promote a selected or latest app publication from `dev` to `prod`. A publication or folder can include `allowed_runtime_roles` such as `["admin"]` or `["legal"]`; empty means normal visibility rules only. Use `publish_html` only for legacy account-owned publishing. For browser mini apps, prefer the SDK at `/sdk/appshare.js` instead of hand-writing REST calls. Initialize it with `Appshare.create({ projectId, environment })` or include `data-project-id` and `data-environment` on the script tag. The SDK provides `me()`, `table(name)`, `storage(bucket)`, `function(name)`, `functions()`, `email()`, `llm()`, and `jobs()`. Use `/examples` and `examples/pending-incidents/` as the golden path before inventing a new structure. Use `jobs().create(...)` for asynchronous work. Supported job kinds include `function`, `table_import`, `table_export`, `storage_zip`, and `webhook_retry`. Use `function` when the job needs business logic. Use `table_import` only for mechanical CSV/JSON imports with declarative field mapping. Jobs are persisted and the server worker recovers queued or stale running jobs. Runtime access control is configured server-side with the console visual+JSON editor, `get_project_runtime_policy` and `upsert_project_runtime_policy`, or REST `GET/PUT /api/projects/{project_id}/runtime-policy`. Policies map runtime roles (`admin`, `guest`, and project-defined roles) to resource actions, table `list_fields`, constraints, and rate limits. Use `policy.assignments.emails` or `policy.assignments.users` to assign a concrete user to a custom runtime role without making them a project editor. Do not enforce these rules only in frontend code. Use `generate_project_sdk` or `GET /api/projects/{project_id}/sdk?environment=dev` when a mini app has table schemas or project functions and needs an ad-hoc business SDK. The generated SDK wraps `/sdk/appshare.js`; do not hand-write DTOs that can be derived from schemas. Table schemas can mark fields with `pii: true` or `x-pii: true`, plus `privacy_level` (`public`, `internal`, `confidential`, `restricted`) and optional `pii_category`; server responses that expose PII are audited. Frontend generation lanes: - Use `/llms-bootstrap.txt` for the default lane: HTML, vanilla JS, appshare SDK, Bootstrap 5, appshare theme CSS, and the official `as-combobox` searchable dropdown from `/sdk/appshare-ui.js`. - Use `/llms-react.txt` only for advanced mini apps with complex local state, nested editors, rich interactions, or reusable components. The React lane is closed: use the appshare React Kit before adding local primitives and do not install arbitrary component packages. Bootstrap mini apps should load the approved Bootstrap 5 CSS, `/sdk/appshare-bootstrap.css`, `/sdk/appshare.js`, and `/sdk/appshare-ui.js`. React mini apps should keep the same visual base and use `/sdk/appshare-react.js` or an equivalent local kit wrapper. Project API keys use the `hpk_...` prefix and are scoped to a single project. They can be limited with scopes such as `project:read`, `publications:write`, `tables:read`, `tables:write`, `storage:read`, `storage:write`, `email:send`, `email:read`, `secrets:read`, `secrets:write`, `llm:generate`, `llm:read`, `jobs:write`, `jobs:read`, `functions:read`, `functions:write`, `functions:invoke`, `webhooks:write`, `webhooks:read`, `runtime:read`, and `runtime:write`. Tables, storage, email logs, secrets, LLM logs, jobs, functions, webhooks, webhook deliveries, audit logs, and project publications are isolated by `environment` (`dev`, `test`, or `prod`). Project functions are synchronous JavaScript snippets that define `handler(event, ctx)` or `module.exports.handler`; they receive only the safe project context and no Node APIs, network, filesystem, `require`, `fetch`, or `process`. Email in `dev` and `test` is sandboxed: it records logs and quota usage but does not deliver to the real provider. Secrets are never returned by REST, UI, or MCP. LLM prompts and outputs are not persisted in LLM usage logs. The LLM proxy records provider/model/status/token usage and blocks prompts that include project secret values. Jobs are asynchronous; create a job, then poll `get_project_job` or `list_project_jobs`. Webhooks are signed with `x-appshare-signature`; the signing secret is returned only when the webhook is created, delivery attempts can be inspected with `list_project_webhook_deliveries`, and repeated failures end as `dead_letter` after configured retries/backoff. Runtime `403` denials are audited as `access.denied`. ## 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.