Overview
Artifacts v2 is the one store every Allternit surface reads and writes: Desktop, ai.allternit.com, the phone layout, the m.allternit.com PWA, cloud computers and gizzi. An artifact is something the assistant (or a person) made that you would show someone. Each one has akind, an immutable list of versions, and sharing settings. The design contract is docs/design/artifacts-v2.md in allternit-platform.
This is a different API from the sectioned Artifacts API under
/api/v1/artifacts, which lives on your data-plane node. Artifacts v2 is served by the hosted Cloud API under the separate /api/v2 prefix.Base URL
Authentication
Every route except the public link route takes one of:- a Clerk session JWT (
Authorization: Bearer <jwt>). This is the only caller that carries an organization, a role and an email; - an
allternit_*API token with thecomputescope (or*). A token without it gets403; - a paired device’s token (
allternit_runtime_…, whatgizzi loginstores). It acts as the device’s owner, with no organization.
Kinds
When a create leaves out
body_format, the kind’s default is used. The server also accepts well-formed kinds it doesn’t know (lower-case, at most 32 characters) so newer clients keep working. Apps show an unknown kind as a page when the body is HTML and as code otherwise.
runtime_version is 2 for current artifacts. 1 marks legacy artifacts imported from the old local stores. A create with runtime_version: 1 must set origin.legacy_source.
Access
Your access to an artifact is the highest of:
If you have no access, every route answers
404, so it doesn’t reveal that the artifact exists. If you can see it but lack the level an action needs, you get 403.
Viewers and commenters see
shared_version, or the latest version when it is null (“always share latest”). Editors and the owner see every version. An outside email invite counts as accepted the first time its invitee opens the artifact while signed in with that email. From then on it no longer expires.
Objects
ArtifactSummary
Artifact
AnArtifactSummary plus:
List artifacts
Returns
{ "items": [ArtifactSummary], "next_cursor": string | null }, newest updated_at first.
Create an artifact
201 with the Artifact (version 1). Optional fields: id, icon, template_id, origin, capabilities, body_format, meta, runtime_version.
- Idempotent create. If you send an
idyou already own, you get that artifact back unchanged with200. If someone else owns theid, you get409 id_conflict. Client ids areart_followed by letters, digits,_or-, at most 128 characters. Legacy imports useart_legacy_<source>_<localId>. - Body limit. A body can be at most 16 MiB. A larger one gets
413 body_too_large. - Organization. The artifact belongs to the creator’s active Clerk organization, and its sharing follows that organization. If the org has turned artifacts off, the create gets
403 artifacts_disabled. If the org has turned connectors off,capabilities.connectorsgets422 connectors_disabled.
Get, update and delete
PATCH returns the Artifact. title and icon need edit. shared_version (from 1 to current_version, or null) and capabilities need owner. Turning on ai or connectors for an artifact shared by link gets 422 link_not_allowed.
DELETE is owner-only and permanent. There is no trash. Versions, shares and comments are deleted with the artifact. It returns 204.
Dashboard body
Adashboard artifact’s body is JSON with body_format application/vnd.allternit.dashboard+json. The server stores it like any other body; the apps parse and validate it. A tile that fails validation is skipped and the rest of the dashboard still draws.
A tool result is read as a table: an array of objects,
{ "columns": [], "rows": [[]] }, or JSON or CSV text.
Dashboards run as the viewer: each call goes through the viewer’s own connectors, and a tool that is not read-only is refused (a SQL tool is allowed for a single read-only statement). The owner’s client sets capabilities.connectors to the connectors and tools the tiles call, so visibility: "link" is refused for a dashboard (see Sharing). Dashboards saved before this format, with application/vnd.allternit.openui, still open as cards.
Versions
edit and returns 201 with the Artifact. body_format defaults to the previous version’s. If base_version is not the current version, the server answers:
base_version: 4. Viewers only see the shared version, so asking them for any other version gets 404.
Sharing
PUT replaces the whole share list. Rows you leave out are removed, and rows you keep only change level. Both return a Sharing object:
link_url appears only when visibility is link. policy.reason explains why links are not allowed. The server sets the link base from ARTIFACTS_PUBLIC_BASE_URL (default https://ai.allternit.com/a).
Sharing rules
All of these failures return422 with the code shown.
The owner always has access, so a share naming the owner is dropped. If the same principal is listed twice, the higher level is kept.
Public link
{id, kind, title, icon, body, body_format, meta, version, updated_at, runtime_version, owner_name}. It works only while visibility is link and the policy still allows links. If an org turns off external sharing or artifacts, its links stop working at once. Viewers get shared_version, or the latest version when it is null. Every other case answers 404. Responses carry Cache-Control: private, no-store and X-Robots-Tag: noindex.
Organization settings
GET returns the settings for your active organization, plus org_id, updated_by, updated_at and can_edit. Personal accounts get the defaults with org_id: null. PUT changes only the fields you send. It needs the Clerk organization role admin (or org:admin). Everyone else gets 403.
Admins can list what the org has shared outside with GET /api/v2/org/artifact-shared-outside. It returns {items: [{id, title, kind, owner_id, owner_name, by_link, outside_invites, allowed, updated_at}]} for artifacts that are public by link or have email invites, and needs the same admin role. allowed is whether the artifact is in allowed_external.
Page runtime
Pages that store data, call AI or use connectors have their own routes under/api/v2/artifact-runtime/{id}. See the Page runtime API.
Comments
Comments are threaded: a root comment plus replies one level deep. They are stored inartifact_comments.
A comment has
id, artifact_id, version, anchor, parent_id, author_id, author_name, author_image_url, body, to_assistant, resolved_at and created_at. body is 1 to 4000 characters. anchor is an opaque object up to 16 KB; the app writes { kind: "text" | "cell" | "slide" | "element", ... }. A comment that mentions @gizzi or @allternit is stored with to_assistant: true. Docs have no Commenter level, so a viewer of a doc can’t comment.
Presence
Presence is shared by every Cloud API instance. Each heartbeat upserts one row per artifact and user inartifact_presence (migration 086_artifact_presence.sql); the table holds only the current state and is not a viewing history.
Send a heartbeat about every 15 seconds.
GET returns the entries seen in the last 45 seconds, up to 200, ordered by user_id. left deletes the caller’s entry. Entries older than 10 minutes are deleted as a side effect of about one request in 50. When the owner’s organization turned presence off, GET returns { enabled: false, users: [] } and POST does nothing.
Errors
Errors use the standard Cloud API shape{ "error", "message", "code" }. Artifact-specific codes are listed above. 401 means you are not signed in. 404 means the artifact doesn’t exist or you have no access.
Storage
The schema iscmd/allternit-cloud-api/migrations_pg/085_artifacts_v2.sql. It creates artifacts, artifact_versions, artifact_shares and org_artifact_settings, plus artifact_storage and artifact_consents (used by the page runtime) and artifact_comments for comments. The migration is idempotent and is applied to production by hand.
Navigation presentation
The shared client usessrc/styles/artifact-navigation.css for the Artifacts toolbar and inline mode selector. ArtifactsView keeps its title outside a nonwrapping, horizontally scrollable controls group; ModeDock uses nonshrinking buttons in the same single-row pattern. Both use --font-ui. Selection uses neutral translucent gradients and inset highlights rather than mode accent tokens, with solid surfaces for reduced transparency or increased contrast. This CSS is imported by the shared components used on Desktop, web and the phone PWA.