artifacta.io/a/{slug}. The page is viewable by anyone with the URL — no Artifacta account required. Agents can publish a build report, a rendered chart, or a Markdown summary and hand the URL to a human in the same step — see share an agent’s report with a client for a worked example.
How it works
- Upload an artifact with
POST /v1/artifacts(orartifacta push, orstore_artifactvia MCP). - Publish it with
POST /v1/artifacts/{id}/publish. The API mints a stablepage_id(pg_...) and returns apublic_url. - The viewer at
artifacta.io/a/{slug}fetches page metadata via theget_public_pageRPC (anon key, no tenant data exposed) and renders the content. - Unpublish at any time with
DELETE /v1/artifacts/{id}/publish. The URL stops resolving immediately. The artifact itself is unaffected.
page_id (and therefore the URL) is stable across re-publishes. Calling publish again on the same artifact updates the title, visibility, and access mode without changing the URL.
Content types and rendering
The viewer selects a renderer based on the artifact’s MIME type:application/xhtml+xml is treated as HTML for gating — password protection is rejected for it at publish time, same as text/html — but it currently renders as a download card, not in the iframe (only text/html routes to the iframe). Markdown is also matched by the .md/.markdown filename extension, so an artifact stored as text/plain or application/octet-stream with one of those extensions still uses the Markdown renderer.<img>, including PNG, JPEG (and .jfif), GIF, WebP, SVG, and APNG. .webp, .jfif, and .apng are stored with the correct image/* type by a server-side content-type override even on hosts whose MIME database omits them.
Content origin isolation
Artifact bytes are never served fromartifacta.io directly. They are served from a separate registrable domain:
- Untrusted HTML or scripts in an artifact cannot access
artifacta.iocookies or session data. - The iframe
sandboxattribute provides a second layer: noallow-same-originmeans the framed document cannot escalate past its sandbox even if the content-origin were compromised. - The Worker sets strict
Content-Security-PolicyandX-Content-Type-Options: nosniffheaders.
Provenance receipt
Every published page renders a receipt — a small provenance panel beside the content that answers who made this, with what, when, built entirely from data already on the artifact:
Fields without a value are simply absent — publishing never invents
provenance, and no schema or API change is involved: the receipt reads
metadata.model directly.
Declared vs. captured model values
metadata.model carries one of two claim strengths:
- Declared — the caller supplied the model ID (
--model,--meta model=,ARTIFACTA_MODEL, or MCPmodel). Absence ofmetadata.model_sourcemeans declared. This is a declared producer claim. - Captured — the model ID was machine-read from the agent runtime’s own
session log by the Claude Code SessionEnd hook or the
capture-transcriptskill, and markedmetadata.model_source=transcript. Artifacta records the model automatically from the agent runtime’s own session log and freezes it at store time — a captured producer claim, not a cryptographic attestation.
Visibility
Password protection
Pages can be protected with a passcode (Pro plan). The access flow:- The viewer calls
GET /v1/public/pages/{slug}/gate-infoto check whether a password prompt is needed. - The visitor submits the password.
- The viewer calls
POST /v1/public/pages/{slug}/unlockwith{"password": "..."}. - The API verifies the passcode (argon2id) and returns a
content_token— a short-lived JWT (5 minutes). - The viewer passes the token to the content-origin Worker, which serves the gated bytes.
Password protection is not available for HTML artifacts (
text/html, application/xhtml+xml). The restriction is enforced at publish time.unauthorized error as a missing or unpublished slug — the endpoint never reveals whether a slug exists.
After unlock, gated (password-protected) content selects its renderer from the artifact’s stored MIME type only — there is no filename-extension fallback on this path. So, for example, Markdown renders after unlock only when it is stored as
text/markdown. The platform ensures this for .md and .markdown uploads via a server-side content-type override, so artifacts uploaded with those extensions render correctly whether or not the page is password-protected.Abuse reporting
Any visitor can report a page viaPOST /v1/public/pages/{slug}/report. The endpoint:
- Accepts an optional
reason("spam","phishing","malware","abuse","copyright","other") and a free-textdetail. - Always returns
202 Accepted, regardless of whether the slug exists. - Forwards the report to PostHog (and optional Slack webhook) for operator review.
- Does not automatically take down the page. Confirmed violations are unpublished by an operator.
Indexing policy
All Artifact Pages are served withnoindex at launch. They do not appear in search engine results.
API reference
CLI
Python SDK
MCP (agent usage)
store_artifact then publish_artifact. The public_url is available in the tool result immediately.
unpublish_artifact with artifact_id: "art_abc123".