The API is HAL (application/hal+json) with HAL-FORMS negotiable
alongside it. Every relation Wyldcards defines is namespaced under the
wyldcards curie, whose template points at this page:
/docs/api-rels.html#{rel}. IANA relations such as
self stay bare.
Start at GET /api. It answers with the relations the caller may
follow: everyone signed in gets account; an admin also gets
users. A signed-out caller gets a 401 whose body advertises
forgotPassword, passkeyLogin and, when sign-up is
on, signUp.
| Relation | Meaning |
|---|---|
| users | The collection of accounts. Admin only. |
| account | The signed-in user's own account. Not an admin's view of someone else's. |
| forgotPassword | Ask for a password-reset email. POST {"email"}. Always answers 202 with the same message, whether or not the address is registered. Advertised on the 401 challenge, since nothing behind the sign-in can advertise it. |
| resetPassword | Set a new password using the token from a recovery email. POST {"token","password"}. GET the same URL with ?token= to ask whether a token is still good and whose account it belongs to. |
| passkeys | The passkeys registered to the signed-in user. Present only where passkeys are configured. |
| passkey | A single registered passkey. |
| registerPasskey | Begin registering a passkey: POST (no body) answers the standard WebAuthn creation options under publicKey plus a challengeId, with a verify link to POST {"challengeId","label","credential"} back to. The ceremony state lives behind the challengeId — no cookies involved — and expires after a few minutes, single-use. |
| passkeyLogin | Begin a passkey sign-in. Advertised on the 401 challenge, like forgotPassword: the caller is signed out by definition. POST (no body) answers WebAuthn request options under publicKey plus a challengeId, with a verify link; a verified assertion answers {"username","token"} — a bearer token the client sends as Authorization: Bearer in place of Basic, since a passkey leaves it with no password. |
| signUp | Make an account for a device that has none. Advertised on the 401 challenge beside passkeyLogin, only while the sign-up feature flag is on. POST (no body) answers 201 with the new account's username and password, shown once: the client keeps them and authenticates with Basic from then on, as with a typed password. Rate limited per address; 404 when the feature is off. |
| verify | The second half of a WebAuthn ceremony: where the authenticator's response is POSTed. |
| revokeToken | DELETE, with the bearer token in the Authorization header, to revoke it — the API's sign-out. Links from /api/token: a password sign-in POSTs there with HTTP Basic (optional body {"label"} naming the device) and gets 201 with {"username","token"}, the same kind of session token a passkey sign-in mints, so a client need not keep the password. |
| stacks | The caller's own stacks, not archived and not trashed. Owner-only, exactly like the web: another user's uid answers 404. ?archived=true lists the archive instead. |
| home | The signed-in user's stack arrangement (All stacks): its title, layout, sort order, sign-in stack (null opens the Home stack), the widgets shown under the Home card, and active stacks in their displayed order. Each stack includes its uid, whether it is docked, and its immediate group parent. This is the entry point for an AI client that needs to organize the stack screen. |
| stack | One stack: name, description, icon (an emoji or a glyph), card size, script, cardCount, and the template it was cloned from. Links to its cards, its export, and the mutations below. |
| cards | A stack's cards in order, each with its 1-based number. ?include=fields adds each card's field text by name as fields; ?field= (a field name or id) with ?value=, and ?name=, keep only exact trimmed, case-insensitive matches. Its create accepts an optional name and fields (keyed by field name or id): every value is validated first, and a bad one answers 400 without creating the card. |
| card | One card. Links to its parts (background parts first, then its own), to fields for a batch field write, to next / prev, which wrap, and to its audioRecordings. |
| audioRecordings | The recordings kept with a card, in the order they are shown. Each is described (title, file name, content type, byte size, duration when known) and none is transferred: the bytes are behind each recording's audioFile. Carries uploadAudio. |
| audioRecording | One recording kept with a card. Links to its audioFile, and to update (rename, PATCH {"title"}) and delete. |
| audioFile | The recording itself, served with the content type it was uploaded as and Accept-Ranges: bytes, so a player can seek. The one href a player, a download and a share sheet all want. |
| parts | Every part a card shows, with owner = background or card, and for a field this card's text. |
| part | One part: rect, z, style, script, and the kind-specific fields (field style / shared / locked, and for a list field multipleLines, for a list or a checklist dontWrap, for a checklist hideCount; for a dropdown field options, the choices in order (PATCH options as one per line to set them; the field's text is the option picked); for a styled paragraphs field paragraphStyles — each style's key, label, element type, whether it is the default, caps, bold, italic, underline, align, indent and right in character widths, space before, the style Return starts (enter) and Tab moves to, the starts prefixes that turn a line into it, and parens; button label / icon; widget type / config). |
| field | PUT {"text"} to write a field's text on this card — the API's autosave. Only on parts of kind FIELD. A list field's text is one item per line; a checklist field's carries the marks too, [x] done and [ ] not. Rewriting one item's wording is the same PUT with that line changed. Add "base", the part's textHash from when editing began, and a write made after someone else saved the field answers 409 {"conflict","message","text","textHash"} with their text instead of overwriting it; send again without base to keep yours. |
| fields | PUT {"fields":{"field name or part ID":"text"}} to write several fields on a card in one request. Every supplied value is validated before any field changes. Prefer stable part IDs; names are accepted when they are unique on the card. |
| export | The whole stack as a .wyldcards.json bundle (see docs/STACK-FORMAT.md). GET answers the JSON with a download filename. |
| exportMarkdown | The stack as a portable Markdown copy, the web's Download Markdown: card titles and field text (# the stack, ## each card, ### each field), without layouts, widgets or scripts. GET answers text/markdown with a download filename. Owners and editors only. |
| importPreview | The Import page's preview. POST a file's raw bytes with ?filename= — a .wyldcards.json backup, a .md Markdown copy, or a .docx Word document, up to 2 MB — and nothing is created: the answer carries the stack's name, backgroundCount, cardCount and partCount, and the bundle to POST to import once the person confirms. In Markdown, # names the stack, ## starts a card and ### a field; in Word, headings start cards and paragraphs and tables become card text. A file that can't be read answers 400 naming file. |
| import | POST a .wyldcards.json bundle as the request body to make a new stack of it. Advertised on the stack collection. |
| templates | The stacks that ship with Wyldcards. Advertised while the templates feature flag is on. |
| template | One shipped template: key, name, description, counts. Links to clone. |
| clone | POST (no body) to make a stack of your own from a template. Answers 201 with the new stack. |
| search | Find, across every stack the caller owns — not every stack they may open, so an admin sweeps their own shelf and nobody else's. ?q= carries the words; under two characters answers an empty collection but still reports stacksSearched. Matches a stack's name and description, a card's name, field text, button labels, private presenter notes, and audio attachment titles or filenames; scripts and attachment bytes are not searched. Archived stacks are included, trashed ones are not. Beside _embedded.searchHits the collection carries query, capped and stacksSearched; capped means the answer stopped at a limit rather than running out of matches. Note that search is an IANA-registered relation whose meaning is exactly this one, so it is advertised uncuried — "search" rather than "wyldcards:search" — unlike every project rel beside it. |
| find | The same search narrowed to one stack — HyperCard's Cmd+F. It searches cards, fields, buttons, and audio attachment metadata, but deliberately leaves out private presenter notes. Each hit carries the card's n, the number in /stack/{uid}/card/{n}: a position rather than an identity, so cardId rides along for a client that wants to survive a deletion. |
| next | The card after this one, wrapping to the first past the end. |
| prev | The card before this one, wrapping to the last before the start. |
| apiTokens | The caller's personal access tokens, newest first: id, label, created, lastUsed. Never the secret. create (POST {"label":"Zapier"}) answers 201 with the raw token, shown once; it is refused with 403 to a request that is itself authenticated by a bearer token. Send the token as Authorization: Bearer wyld_…. |
| apiToken | One personal access token. Its delete revokes it. |
| hooks | The caller's REST-hook subscriptions (?stack= narrows to one stack). create POSTs {"event","targetUrl","stack","label"}; events are card.created, card.updated, card.deleted and public_form.submitted. The 201 answer carries the HMAC secret once. See the integrations section of the automation guide for the delivery format. |
| hook | One subscription: event, targetUrl, stackUid, label, lastDeliveredAt, lastStatus. Its delete unsubscribes; a delivery answered with 410 Gone does the same. |
| hookSamples | Payloads shaped exactly like deliveries, built from a stack's newest cards: GET with ?event=, ?stack= and optional ?limit= (at most 10). The array is samples. |
| fieldDefinitions | The fields a new card in the stack starts with — the last card's background fields, then its own — each with id, name (null when unnamed), style, background, required and unique. What an integration builds its input form from. |
| fieldDefinition | One field definition in fieldDefinitions. |
| sharedStacks | Other people's stacks shared with the caller that they can open, each with the caller's role (editor or viewer) and a leave link. A viewer can read cards; an editor can also change them, though on a shared stack a script runs only once its owner has approved it, and only for a collaborator who chooses to run it in the web app. |
| collaborators | Who the owner shared a stack with, each with a role and a delete link. Only the owner may read it. POST {"username","role"} or {"email","role"} (which emails an invitation) to share the stack; sharing with someone again changes their role. |
| collaborator | One person a stack is shared with, listed in its collaborators. |
| tags | Named tags inside a stack, HyperCard-style card collections. On a stack's cards, the stack's tags with a cardCount and a cards link to the tagged cards; on a card, the tags it carries. PUT {"tagIds":[…],"newTag":"name"} to a card's tags to replace them, making the new tag if needed. |
| tag | One tag, listed in tags. |
| publicSharing | The owner's view of a stack's password-protected publicLink and publishedUrl. PUT {"password","form"} to …/public/link to create a new link and DELETE it to revoke; PUT {"slug"} to …/public/published to publish and DELETE to unpublish. Only cards with publiclyVisible appear in either. |
| savedFinds | The caller's saved finds in a stack: private "this field contains this text" searches, each with a cards link that runs it and a delete link. POST {"name","fieldName","value"} to save one. They stay private even in a shared stack. |
| savedFind | One saved find, listed in savedFinds. |
| savedViews | The caller's saved table views in a stack: which columns to show (fieldIds with their fieldNames), an optional filterFieldId/filterFieldName and value, a tagId/tagName, and the sort (sortFieldId, null when sorting by card name, with sortDirection asc or desc). POST {"name","fieldIds","filterFieldId","value","sortFieldId","sortDirection","tagId"} to save one; each carries a delete link, and a cards link when it filters. These are the same saved views the web data workspace keeps, and stay private even in a shared stack. |
| savedView | One saved table view, listed in savedViews. |
| teams | The caller's teams: groups of people who share stacks together. GET lists each team's uid, name, whether the caller is a manager, and its memberCount; POST {"name"} makes one, which the maker manages. /api/teams/{uid} answers the members (each with its id, username, name, role member or manager, and whether it is you), the stacks shared with the team and at what access, and — for managers — pending invitations. A manager PATCHes {"name"} to rename, DELETEs the team (members keep only access given to them directly), POSTs {"person","role"} to …/members — a username, or an email, which adds the person with that account now and sends anyone else an invitation that works for 14 days — PATCHes {"role"} on …/members/{id}, and DELETEs …/invitations/{id} to withdraw one. DELETE on …/members/{id} removes someone, or leaves the team when the id is the caller's own membership. Advertised on the API root. |
| stackTeams | The teams a stack is shared with, for its owner: the shares (each with its id, teamUid, teamName, access value and accessLabel), the owner's teams it could be shared with, and the access options — viewer, writer, editor, and the stack's named roles. POST {"team","role"} shares it with a team the owner is in: everyone in the team gets it, and so does anyone who joins later. DELETE …/teams/{id} stops sharing; people keep access given to them directly. A collaborator whose access comes through a team carries that team, where the access is changed. |
| editions | A stack's editions: parallel copies of it, a script's blue draft beside its white one. GET answers the family, the original first — each edition's stack uid, label, whether it is the original, the isDefault one people with edit access open, the published one people with view-only access see, and the current one this request named — plus whether the caller canManage them and whether the stack is shared. Open another edition by its uid. The owner POSTs {"name"} here to make a new edition from this one, which copies every card and field; the answer's uid is the new edition. On …/edition, the owner PATCHes {"name"} to rename it, POSTs …/edition/default to make it the default, PUTs or DELETEs …/edition/published to publish it to viewers or publish nothing, and DELETEs …/edition to move it to the trash (never the original; the answer is the original's family). Listed for anyone who can edit the stack. A stack that is an edition carries its editionName. |
| read | The read view: a stack's styled paragraphs field from every card, in order, as one script — the same content the web read view shows. The answer carries the title and, when there is one, the titlePage; the stack's styled paragraphs fields and the field being read (choose another with ?field=); the styles, each with its key, label, element type (scene, character, dialogue and so on), caps, bold, italic, underline, align, indent and right in character widths, space before, and whether it is drawn in parens; the sections, one per card with its lines (each a style key and text, and an anchor on a scene heading); and the contents of scene headings to jump to. ?marked=true reads only the marked cards. Anyone who can open the stack may read it. |
| automations | A stack's automations: rules that send a signed webhook after a response to the stack's public form is saved, as in Stack Settings on the web. GET answers whether the publicFormEnabled (rules fire only when it is), the formFields a condition may read, and the automations — each with its name, whether it is enabled, its condition (conditionFieldId and conditionFieldName, conditionOperator EQUALS or NOT_EMPTY, and conditionValue), and the webhookHost it posts to. The full URL and the signing secret are never sent back. POST {"name","conditionFieldId","conditionOperator","conditionValue","url","secret"} to add one — the URL must be HTTPS on a public address; PATCH {"enabled"} on …/automations/{id} turns one on or off, and DELETE removes it. Each delivery is public_form.submitted JSON signed in X-Wyldcards-Signature as HMAC-SHA256 of the raw body. Present on a stack only for its owner. |
| calendar | A stack's Google Calendar sync, for its owner. GET answers whether this server is configured for Google Calendar, whether the stack is connected, how many datedCards it has, and the settingsUrl where the owner connects — Google's consent returns to one registered address and checks state held in the web session, so connecting happens on the web. POST …/calendar/sync sends the dated cards to the owner's primary calendar as all-day events and brings back date and title changes made to those events, answering exported, imported and a message; it answers 400 when the server is not configured, the stack is not connected, or Google has withdrawn the authorization, and 502 when Google cannot be reached. DELETE disconnects, leaving events already on the calendar in place. Present on a stack only for its owner. |
| paint | A card's paint layer, the picture behind its parts. PUT {"image","background"} with the whole picture as a PNG data URL (data:image/png;base64,…), up to 4,096 pixels a side — the same thing the web's paint mode posts; background true paints the card's background instead, which every card on it shows. DELETE wipes it (?background=true for the background's). Either answers the card, whose paintUrl and backgroundPaintUrl are then the fresh, cache-busted paths to the pictures. Authoring level, like moving a part. |
| sort | HyperCard's Sort over a whole stack, which changes the order of the cards themselves. POST {"field","order","from"}: field is a field's name (absent sorts by card name), order is descending or absent for ascending, and from is the card number the caller is on. The answer gives that card's new number and the stack's cardCount, so a client can sort without losing the reader's place. Editors only. |
The stack on paper, as the web print sheet draws it: each card with its fields where they sit on the card (x, y, width, height, style, text), plus the stack's cardWidth and cardHeight to lay them out against. Buttons and widgets are left out — a button is a thing you press and a widget is a thing that sounds, and neither survives the trip to paper. ?from= and ?to= name card numbers in the stack, and ?marked=true narrows the range to the marked cards (a stack with none marked prints the range as it stands). availableCount is how many cards there are to print from. | |
| report | HyperCard's Print Report over a stack: its cards grouped by one field and another subtotalled, the same arithmetic as the web report page. GET with ?group= and ?summary= (field ids, both optional). The answer carries the stack's report fields to choose from, the chosen groupFieldName and summaryFieldName, the groups — each with its name, its rows (card number, name, and summary value) and a subtotal — and the total. Cards with no value for the grouping field are grouped as "Unassigned", and a summary value that is not a number counts as nothing. |
| reportLayout | HyperCard's Print Report layouts, what the web's printable report page lays out. GET with ?layout=columns (a row per card) or labels, repeated ?field= ids to print (0 is the card's name; unknown and repeated ids are skipped, and none prints the card name), ?marked=true for the marked cards only (every card when none is marked), ?title= (the stack's name when blank, up to 120 characters), and ?perRow= 2 or 3 labels to a row. The answer carries the title, layout, perRow, whether it is markedOnly, the chosen fields, the rows — each card's number in the stack and its values in field order — and printedOn. A client pages and prints it, with the title at the top of each sheet and Page n of m at the foot. |
| canvas | Where a stack's cards sit on its freeform board, the web Canvas. Each card carries canvasX and canvasY, absent while no one has placed it — a client lays those out itself, as the web does. PUT {"placements":[{"cardId","x","y"}]} to place cards; a placement with no x and no y returns that card to the automatic layout, and positions stay within 100,000 pixels of the origin. Many placements in one request is how lining up and undoing a move save. The answer is the stack's cards. Editors only. |
| importCards | Reads delimited text into a stack's cards, the web data workspace's CSV import. POST {"text","mapping","fieldIds","uniqueFieldId"}: text is the file (comma-separated, or tab-separated when it holds no commas, up to 2 MB and 2,000 rows). Without a mapping the header row is read, where the first column must be Card Name and each later header fills the field of that name — fieldIds narrows which fields may be filled. A mapping gives one target per column instead: name, ignore, or field-<id>. With a uniqueFieldId, a row whose key matches a card updates that card rather than adding another. The answer carries created, updated, a rejected list naming each row that could not be written, and a message; a rejected row leaves its card unchanged. Editors only. |
| changes | A stack's change history, the web's Changes: every edit to a field or a card's name, newest first (the newest 500 are kept). GET (optionally ?card= a card number) answers changes, each with id, when, author, action, subject, cardNumber, cardName, whether it was undone, and a word-by-word diff of segments whose kind is same, removed or added. POST /{id}/put-back returns the text to how it was before that change; if it has changed again since, the answer is 409 with changedSince, and POST {"anyway":true} replaces what is there now. POST /undo takes back the caller's own most recent change and /redo brings it back; neither writes over someone else's later edit (409 with a message). Answers carry a message and the affected cardNumber. For people who can type in the stack; others get 404. |
| helpTopics | The Help Center's topics, for a client that searches and shows help itself. GET answers topics, each with a unique key, the id the web page anchors it by (/help#id; a part of a topic, such as Presenter Notes, opens its topic), its title, a one-line description where the feature finder has one, the feature finder's keywords for it, the longer pageKeywords the Help Center page searches (worth less in a ranking), and its paragraphs as plain text. They are read from the same help page the web serves, so they change with it. |
| components | Components, the web inspector's saved copies of a field, button or widget, kept per person. GET /api/components answers components, each with id, name, kind and createdAt. POST {"partId","cardId","name"} saves a part as it shows on that card (editors of its stack; a script the owner hasn't approved isn't saved with it). POST /api/cards/{id}/components/{componentId} puts a copy on the card, or on its background with ?placement=background, and answers the new part; changing it doesn't change the component. DELETE /api/components/{id} removes one. A copied card link starts unassigned. |
| scriptFile | The page view's files. GET with ?format= pdf (the default), fountain, fdx, txt, docx, epub or musicxml, optionally ?field= (the styled paragraphs field to use) and ?marked=true, and the page settings the web passes along — paper (letter or a4), margins, numbers, numberFirst, cardBreaks, titlePage — and the answer is the file with its type and a download filename. A field that can't be written that way answers 400 naming format. POST a Fountain or Final Draft file's raw bytes with ?filename= to read it in: ?placement=scenes (the default, editors) adds a card for each scene; placement=card&card= (people who can type) replaces that card's text. The answer carries paragraphs, cards and a message. |
| titlePage | The script's title page, which the read view and the script files put first. PUT {"title","credit","authors","source","draftDate","contact","notes"} to save it; the answer is the saved page. The read rel's answer carries it for reading. Editors only. |
| linkedFrom | Linked cards, the field type that links as many cards as you like from any stack you can open. GET on a card's linkedFrom answers the cards whose Linked cards fields name it, grouped by stack and field (stackName, stackUid, fieldName, cards); stacks the reader can't open are left out. For one field, GET /api/cards/{id}/parts/{partId}/links answers its links in the order they were made, and /link-options?q= the options a person who can type could link, found by name (the field's own stack first, or only the stack in its config). Each link carries uid, visible (false for a card in a stack the reader can't open, whose name is then withheld), name, number, stackName, stackUid, href and sameStack. Link and unlink by saving the field's text: the linked cards' uids, one per line. A part that isn't a Linked cards field on that card answers 404. |
| linksHere | The cards pointing at this one, the web card page's Links here: GET answers links, each with the linking card's cardId, cardNumber and cardName and the partLabel of the button or card-link field that points here, in stack order. A background button counts once for every card on that background; parts the reader's role hides are left out. |
| relatedCards | A card's Related cards, the undirected connection the web edits under Related cards and the Map draws as a dotted line. GET answers related — each with cardId, cardNumber and cardName, in stack order, archived cards left out. PUT {"cardIds"} replaces them with cards from the same stack (the card itself is ignored), and the relationship appears on both cards; a card from another stack answers 400. PUT is for editors. |
| emailCards | Email Cards, the web card list's Email selected. POST {"cardIds","recipient"} to send the chosen cards — each card's title and its non-blank text fields, in card order, as plain text; no layouts, widgets, scripts, recordings or attachments — to one address. Archived cards and ids from other stacks are skipped. The answer carries how many cards were sent and a message; a missing or malformed address, or no cards to send, answers 400 naming recipient or cardIds. Editors only. |
| bulk | One action across every card in a stack. POST {"action"} — mark, unmark, or delete (which deletes the marked cards, never a stack's last card) — and the answer carries how many cards changed and a message. Editors only. |
| linkMap | A stack's explicit card-to-card connections, as the web Map lists them: connections (each with source and target card numbers and names, a type, label, and kind), brokenLinks whose target was archived or deleted, unconnectedCards, and a count of otherStackLinks. It also carries the diagram the web draws: nodes (each card's number, name, and placed rectangle), the canvas width and height, and kindCounts per connection kind. Script navigation is not included. |
| cardTemplates | A stack's saved card layouts, by name, each with its backgroundName, a create link, and a delete link. POST {"cardId","name"} to save a card's parts and background as a template; POST {"after"} to a template's create link to add a card from it after that card number (or at the end). Editors only. |
| cardTemplate | One saved card layout, listed in cardTemplates. |
| snapshots | The owner's saved snapshots of a whole stack, newest first, each with a name and a restore link. POST {"name"} to save one. Restoring makes a new stack from the snapshot and leaves the original unchanged. |
| snapshot | One saved copy of a stack, listed in snapshots. |
| trash | Stacks the caller moved to the trash, newest first. Each carries deletedAt and links to restore and purge; the collection links to emptyTrash. |
| notes | A card's private presenter notes as {"presenterNotes"}. Only people who can edit the stack may read them; PUT the same shape to replace them, and a blank value clears them. |
| history | A card's saved versions, newest first (up to the most recent 50), each with a changeSummary such as "Before card date changed" and a restore link. Only people who can edit the stack may read it. |
| revision | One saved version of a card, listed in its history. |
| comments | A card's comments, oldest first, each with its author, text, and time. Anyone who can open the card may read them and POST {"text"} to add one; a comment's delete link appears for its author and the stack's owner. |
| comment | One comment on a card, listed in its comments. |
| archivedCards | A stack's archived cards, most recently archived first. Each carries archivedAt and an unarchive link. |
| bookmarks | The caller's bookmarked cards, newest first, across every stack they can still open. Each names its card (id, uid, number, name) and stack (uid, name, icon) and links to the card. |
| bookmark | Whether the caller bookmarked this card, as {"bookmarked"}. PUT (no body) to bookmark it and DELETE to remove the bookmark. Bookmarks are personal, so anyone who can open the card may set one. |
| Relation | Method | Meaning |
|---|---|---|
| create | POST | Create a new resource in a collection. |
| update | PUT | Replace the resource's editable fields. |
| delete | DELETE | Delete the resource. |
| changePassword | POST | Change the signed-in user's own password. The current password is required. |
| preferences | PUT | Save the signed-in user's appearance and text size: {"theme","textSize"}, where theme is system, light, or dark and textSize is a percentage from 80 to 200. Leave either out to keep what is saved. Answers the account, which carries both. |
| scripts | GET | /api/stacks/{uid}/scripts answers {"reviewed","owner","runs"}: whether the stack has been shared (so only approved scripts run), whether the caller is its owner, and whether scripts run for the caller. POST /run or /stop on it to choose, as a collaborator does from the card page. |
| events | GET | /api/stacks/{uid}/events is a server-sent event stream for anyone who may open the stack: ready when it opens, then card {"cardId"} each time a card's name or text is saved. Read the card again to see what changed; a comment every 25 seconds keeps it open. |
| archive | POST | Put a stack or card aside: it leaves the list but stays whole and openable. A stack keeps at least one card, and protected cards refuse. |
| unarchive | POST | Bring an archived stack back into the list, or an archived card back to the end of its stack. |
| restore | POST | Bring something back: a stack out of the trash (answers the stack), or a card's saved version from its history (answers the card; the state it replaces is kept as a version first). |
| purge | DELETE | Delete a trashed stack for good, with its cards, parts, and recordings. There is no undo. |
| emptyTrash | DELETE | Delete every stack in the caller's trash for good. Answers {"purged"} with how many went. |
| leave | POST | Give up access to a stack someone shared with the caller. The owner cannot leave their own stack. |
| replace | POST | Find and replace across a stack: POST {"find","replacement"} to change every exact, case-sensitive occurrence in card names and field text. Answers {"replaced"} with how many values changed; a shared background field counts once. Editors only. |
| duplicate | POST | Make a new card right after this one. With no body it copies the name, script, presenter notes, date, parts, and field text (not the mark); {"layoutOnly":true} copies just the parts and their layout, with blank text. Answers 201 with the new card. |
| cardDate | PUT | Set a card's date with {"cardDate":"2026-09-14"}, or clear it with {"cardDate":null}. Answers the card. |
| reset | DELETE | Return the home screen to its defaults. Docked stacks stay docked. |
| pin | POST | Dock the stack identified by the uid URI template parameter. |
| unpin | POST | Remove the stack identified by the uid URI template parameter from the dock. |
| reorder | POST | Replace one pinned or unpinned sibling group's custom order. POST {"stackUids":[...]}; supply every stack in that group exactly once. |
| group | POST | Place one stack inside another. POST {"stackUid","folderUid"}. Both must be the caller's stacks, have the same dock state, and cannot form a cycle. |
| moveOut | POST | Promote the stack identified by the uid URI template parameter one group level. |
| uploadAudio | POST | Add a recording to a card: multipart/form-data with file (MP3, M4A, WAV, AIFF, FLAC, OGG or WebM, 25 MB or less), optional title and durationMs. Answers 201 with the recording; 400 with {"file": "…"} when refused. Up to fifty per card. |