Artifact API reference
Complete reference for the REST CRUD API around artifacts.
The Artifacts CRUD API (supabase/functions/artifacts, deployed public) is a
plain-REST interface for pushing artifacts in and out of SupaNet without MCP or
holding a Supabase session. Every call is authenticated by a bearer token
(either a personal mcp_tokens token or a Supabase session JWT), and the function
runs as the token's owner with re-enforced ownership in code (using the service
role + code checks, not RLS).
Base URL
https://<your-project>.supabase.co/functions/v1/artifactsA bare GET with no Authorization header, or GET /artifacts/docs, returns
plain-text documentation.
Endpoints
| Method | Path | Purpose |
|---|---|---|
GET | /artifacts | List your artifacts (metadata by default). |
POST | /artifacts | Create an artifact. |
GET | /artifacts/:id | Read one (includes content and collections). |
PATCH | PUT | /artifacts/:id | Update fields; add collection tags. |
DELETE | /artifacts/:id | Delete one. |
GET /artifacts — list
Query parameters (all optional):
| Param | Meaning |
|---|---|
collection | Only artifacts in this collection (name or id). |
type | Filter by type: markdown, code, html, or text. |
q | Title contains (case-insensitive). |
include=content | Include the full content in each row (omitted by default). |
limit | 1–200, default 50. |
offset | Paging offset, default 0. |
Response:
{
"artifacts": [
{
"id": "…",
"title": "Hello",
"type": "markdown",
"language": null,
"visibility": "private",
"public_slug": null,
"url": "/artifacts/…",
"public_url": null,
"standalone_url": null,
"created_at": "…",
"updated_at": "…"
}
],
"count": 1
}Each artifact includes three URL fields:
url- the signed-in editor link (always present).public_url- the public share link, or null if the artifact is not shared (unlistedorpublicwith a slug). Format:/share/a/<slug>.standalone_url- for HTML artifacts only, the full-page view (e.g./p/<slug>), or null otherwise.
POST /artifacts — create
JSON body:
| Field | Required | Type | Notes |
|---|---|---|---|
title | yes | string | |
content | yes | string | The artifact body. |
type | no | string | markdown (default), code, html, or text. |
language | no | string | Hint for code artifacts (e.g., ts, py). |
visibility | no | string | private (default), workspace, unlisted, or public. Only unlisted and public mint a public_slug. |
collection | no | string | Collection name or id (created if missing). |
collections | no | array | Array of collection names/ids (created if missing). |
Returns 201 with the created artifact (including content and its collections).
Example:
curl -X POST "https://<project>.supabase.co/functions/v1/artifacts" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"title": "My Blog Post",
"content": "# Hello\n\nThis is a post.",
"type": "markdown",
"collection": "Blog"
}'GET /artifacts/:id — read
Returns the full artifact including content and the list of collections it
belongs to.
Example:
curl "https://<project>.supabase.co/functions/v1/artifacts/<id>" \
-H "Authorization: Bearer $TOKEN"Returns 404 if not found or not owned by the token's user.
PATCH /artifacts/:id (or PUT) — update
Send only the fields you want to change:
| Field | Type |
|---|---|
title | string |
content | string |
type | string |
language | string |
visibility | string |
Passing collection or collections adds the artifact to those collections.
Existing tags are kept; this API cannot remove tags (use the app UI for that).
Flipping visibility to non-private mints a share link if one did not exist.
Returns the updated artifact.
Example:
curl -X PATCH "https://<project>.supabase.co/functions/v1/artifacts/<id>" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"content": "# Updated", "visibility": "public"}'POST /artifacts/:id/share — share an artifact (MCP tool)
Note: This is exposed only through the MCP server as the share_artifact tool, not as a REST endpoint. It publishes an artifact by link.
share_artifact (MCP tool)
Publish an artifact you own by link. Sets its visibility to "unlisted" (default, anyone with the link) or "public" (discoverable), creates its public slug if missing, and returns the shareable links.
Input:
artifact(string, required) - the artifact id or its exact title.visibility(string, optional) -"unlisted"(default) or"public".
Returns:
url— the signed-in editor link.public_url— the public share link, or null if not shared.standalone_url— the full-page view for HTML artifacts, or null.id— the artifact id.visibility— the visibility setting.public_slug— the generated slug.
Example via MCP (Claude):
Share my artifact "Dashboard" publicly.This tells the assistant to use share_artifact with visibility: "public", which generates a public link if one doesn't exist.
DELETE /artifacts/:id
Deletes the artifact. Returns { "deleted": true, "id": "…" }.
Example:
curl -X DELETE "https://<project>.supabase.co/functions/v1/artifacts/<id>" \
-H "Authorization: Bearer $TOKEN"Returns 404 if not found or not owned by the token's user.
Errors
All errors are JSON: { "error": "message" } with an appropriate HTTP status:
| Status | Meaning |
|---|---|
400 | Bad input (missing required field, invalid type, etc.). |
401 | Missing or invalid bearer token. |
404 | Artifact not found or not owned by the token's user. |
405 | Wrong HTTP method or path (e.g., POST to /artifacts/:id). |
500 | Server error. |
Collections
A collection is a named group of artifacts you can chat with in SupaNet. When pushing artifacts via this API:
- Reference by name (any string; created automatically if it does not exist) or by id (UUID).
- Collection tagging is additive: update operations add to existing tags, they do not replace them.
- To remove a tag, use the app UI.
Collections respect workspace membership: a collection you create is private by default, but it can be shared with the workspace if you mark it shared in the UI.
Sharing and public links
Visibility options and their effects:
- private or workspace: only visible internally. No external link (public_url is null).
- unlisted or public: generates a unique
public_slugand mints shareable links.- All artifacts get
public_url— the shareable public link at/share/a/<public_slug>. - HTML artifacts only also get
standalone_url— a full-screen, chrome-free page at/p/<public_slug>. Use this for dashboards, diagrams, or landing pages you want to host at the app's own URL.
- All artifacts get
Important: Public share routes resolve by public_slug, not by artifact id. This prevents accidental exposure — an agent building a link from the artifact id will get a 404, forcing it to use the ready-made public_url field instead. Always use public_url when sharing; never construct share links from the id.
Authentication note
The bearer token can be a personal connection token (mcp_tokens) or a Supabase
session JWT (verified server-side via auth.getUser). Connection tokens should be
treated like a password:
- Rotate it if leaked.
- Revoke it anytime from Settings → Connect Claude.
- Requests are authenticated at the token → owner level; the function runs with the service role and re-enforces ownership in code.
CORS
The API ships with permissive CORS headers. You can call it from a browser.
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, OPTIONSExamples
See Artifact API for use-case examples and typical workflows.