Python SDK
Install superartifacts, publish a page, read back what it collected, share it, and handle errors, retries, paging, uploads and async.
guide~4 minVerified v0.178.0
superartifacts needs Python 3.10 or newer. It is server side only:
keep the key on a server.
Install
pip install superartifacts
Create a key in Settings → API keys and put it in
SUPERARTIFACTS_API_KEY.
First call
import os from superartifacts import SuperArtifacts sa = SuperArtifacts(api_key=os.environ["SUPERARTIFACTS_API_KEY"]) print(sa.account.whoami()["handle"]) sa.artifacts.publish( slug="hello", html="<!doctype html><h1>Hello</h1>", ) for artifact in sa.artifacts.list()["artifacts"]: print(artifact["slug"]) for row in sa.data.iter_artifact_rows(artifact="hello"): print(row)
api_key falls back to SUPERARTIFACTS_API_KEY, so SuperArtifacts() is enough.
Keyword arguments hold path, query and body fields together, in snake_case: values_file= goes out
as valuesFile. Values nested inside a dict keep the API's spelling. Answers are plain dicts, as
API endpoints describes them.
AsyncSuperArtifacts is the same surface, awaited.
import asyncio from superartifacts import AsyncSuperArtifacts async def main(): async with AsyncSuperArtifacts() as sa: print(await sa.account.whoami()) async for row in sa.data.iter_artifact_rows(artifact="hello"): print(row) asyncio.run(main())
Configuration
SuperArtifacts( api_key=None, # or SUPERARTIFACTS_API_KEY base_url="https://superartifacts.app", timeout=60.0, # seconds max_retries=2, http_client=None, # your own httpx.Client; yours to close )
Every method also takes timeout= for that call, and every POST takes idempotency_key=. Use
the client as a context manager, or call close().
Publish a page you made
from pathlib import Path from anthropic import Anthropic from superartifacts import SuperArtifacts # Your model, your key. We run no inference. msg = Anthropic().messages.create( model="claude-haiku-5-5", max_tokens=4000, messages=[{ "role": "user", "content": "A launch checklist. HTML only.", }], ) Path("checklist.html").write_text( msg.content[0].text ) # We host the file. Reads SUPERARTIFACTS_API_KEY sa = SuperArtifacts() page = sa.artifacts.publish_file( "checklist.html" ) print(page["url"])
publish_file(path, **fields) takes an HTML file or a folder with an index.html; the slug defaults to its name. Pages are private at first, and the same slug adds a version. prompt is optional: the request, shown on the card.
Collect data and read it back
Without a policy, a form stores nothing. This one is an answer sheet: one row per person. The
form in rsvp.html saves to it, as Collect responses describes.
from pathlib import Path sa.artifacts.publish( slug="rsvp", html=Path("rsvp.html").read_text(), policy={ "policyVersion": 1, "writes": "upsert", "perUser": "single", "read": "own", "retentionDays": None, "recordCap": {"perVisitor": 1, "perArtifact": 500}, "fields": [ {"name": "attending", "type": "boolean", "required": False, "pii": "none", "description": "Yes or no."}, ], }, ) for row in sa.data.iter_artifact_rows(artifact="rsvp"): print(row)
Share an artifact
sa.shares.add_to_artifact( artifact="launch-notes", emails=["dana@example.com"], role="commenter", )
Each person gets an email. The role is viewer unless you say otherwise, and sharing endpoints
allow 20 calls an hour per key.
Errors
Everything raised is a SuperArtifactsError, with .status, .code, .message, .retry_after
and the full error object in .details. Error codes lists every code.
A client-side failure has .status 0 and its own .code: a missing key is an AuthenticationError
with missing_api_key.
| Status | Exception |
|---|---|
| 400 | InvalidArgumentsError |
| 401 | AuthenticationError (also raised when there is no key) |
| 402 | PlanLimitError |
| 403 | PermissionError, or ScopeRequiredError when a read key tried a write |
| 404 | NotFoundError |
| 409 | ConflictError |
| 413 | PayloadTooLargeError |
| 429 | RateLimitError |
| 5xx | InternalError |
| none | APIConnectionError, APITimeoutError |
from superartifacts import NotFoundError try: sa.artifacts.get(artifact="missing") except NotFoundError as error: print(error.code, error.message)
superartifacts.PermissionError is not the builtin of that name: import it by name when you catch
it.
Retries and idempotency
Up to max_retries more tries, two by default:
- A
429is retried after itsRetry-After. Past 60 seconds it is not waited out: theRateLimitErrorcomes straight back withretry_afterset. 502,503,504and network errors are retried with exponential backoff and jitter, forGET,DELETEandPOST.PATCHandPUTare retried on429only.500and every other4xxare never retried.
Every POST sends an Idempotency-Key, one per call and the same across its retries, so a retried
publish happens once. Pass idempotency_key= to choose your own, which also makes a retry of your
own code safe.
Pagination
iter_* methods walk every page and yield one item at a time, taking the same arguments as the
list they wrap.
for row in sa.data.iter_rows(dataset="signups"): print(row) for row in sa.data.iter_artifact_rows(artifact="hello"): print(row) for entry in sa.entries.iter(collection="posts"): print(entry) for mention in sa.mentions.iter(): print(mention)
Uploads
A JSON body stops at 1 MiB. uploads.upload stages bigger files and sends the bytes straight to
their upload URLs. It takes a mapping of path in the artifact to bytes or a local file, within 5 MiB
a file and 10 MiB a set.
staged = sa.uploads.upload({"images/hero.png": "./hero.png", "notes.txt": b"hello"}) sa.artifacts.publish( slug="hello", html='<!doctype html><img src="images/hero.png">', uploads=staged["uploadId"], )
Every method
| Method | Does |
|---|---|
sa.account.whoami | Who this key publishes as |
sa.account.help | How the operations fit together |
sa.artifacts.list | List your artifacts, newest first |
sa.artifacts.publish | Publish an artifact, or a new version of one |
sa.artifacts.publish_file | Publish an HTML file, or a folder with an index.html |
sa.artifacts.get | One artifact: its versions, published version and declaration |
sa.artifacts.update | Change visibility, gallery label, live phase or submission email |
sa.artifacts.delete | Delete an artifact with every version, permanently |
sa.artifacts.read_file | Read one file of a version as text (default: the published index.html) |
sa.artifacts.open | A ten-minute viewer URL for an artifact, private included |
sa.artifacts.serve_version | Serve an existing version again |
sa.live.start | Turn an artifact's live room on |
sa.live.stop | Turn an artifact's live room off, disconnecting every visitor |
sa.uploads.stage | Stage big files for a publish; PUT each to its URL |
sa.uploads.upload | Stage files and send their bytes |
sa.data.list_artifact_rows | Rows visitors submitted to one artifact, newest first |
sa.data.iter_artifact_rows | Every row of one artifact, page by page |
sa.data.write_artifact_rows | Write rows into an artifact you may edit |
sa.data.list_rows | Rows submitted to a dataset or a gallery label |
sa.data.iter_rows | Every row of a dataset or label, page by page |
sa.data.query | Aggregate what was collected: numbers, never rows |
sa.schema.get | The data catalog: datasets and content collections, or a comparison |
sa.schema.define_collection | Create or replace a content collection |
sa.entries.list | One page of a content collection's entries |
sa.entries.iter | Every entry, page by page |
sa.entries.create | Create one entry, or a batch |
sa.secrets.use | Call an approved API with a stored secret you cannot read (workspace keys) |
sa.templates.list | Find, rank or list templates |
sa.templates.save | Create or revise a template draft |
sa.templates.get | One template in full, with its install prompt |
sa.templates.get_history | A template's changelog |
sa.templates.get_feedback | Comments on a template's artifacts, as themes |
sa.templates.act | Install, uninstall, rate, report, roll back or request verification |
sa.templates.release | Release one version of your template |
sa.projects.list | Your projects |
sa.projects.create | Create a project, optionally seeded with artifacts |
sa.projects.get | One project and its items |
sa.projects.update | Rename, set visibility, reorder, move, fold groups or set a rule |
sa.projects.delete | Delete a project; its artifacts stay |
sa.projects.add_artifacts | Add artifacts to a project |
sa.projects.remove_artifact | Remove one artifact (or item) from a project |
sa.shares.add_to_artifact | Give named people access to an artifact |
sa.shares.add_to_project | Give named people access to a project |
sa.shares.add_to_workspace | Invite editors to a workspace (returns accept links) |
sa.comments.list | Comment threads on an artifact, newest first |
sa.comments.respond | Reply to and/or resolve threads, one outcome each |
sa.comments.get_screenshot | One message's screenshot, base64 in `image` |
sa.mentions.list | Where people @mentioned you; listing marks them seen |
sa.mentions.iter | Every mention, page by page |
sa.signatures.list | An artifact's signature requests, newest first |
sa.signatures.request | Ask named people to sign one version of an artifact |
sa.signatures.get | One signature request and its signers |
sa.signatures.remind | Email a signer their link again |
sa.signatures.withdraw | Close an open signature request |