{"openapi":"3.1.0","info":{"title":"SaveHQ API","version":"1.1.0","description":"SaveHQ is a free, visual board for everything a person saves. This API can do everything the person can do on their board: save links, search and list saves, and organize the board (categories, moving, editing, pins, privacy, views, group chat settings), including deletes. Deleting, merging and making saves public answer 202 with a preview and a confirmToken first; only the same request with the token makes the change. Every change returns a changeId that /api/v1/undo reverses; GET /api/v1/changes lists recent ones, including changes made elsewhere. The same powers are available over MCP at https://savehq.app/api/mcp (Streamable HTTP), for Claude, ChatGPT, Muse and any MCP client. Full guide: https://savehq.app/llms-full.txt","contact":{"email":"support@savehq.app","url":"https://savehq.app/support"},"termsOfService":"https://savehq.app/terms"},"servers":[{"url":"https://savehq.app"}],"externalDocs":{"description":"Guide for AI apps and agents","url":"https://savehq.app/llms-full.txt"},"security":[{"bearer":[]}],"tags":[{"name":"Save and read"},{"name":"Change the board","description":"The same actions as SaveHQ's own AI and the MCP tools."}],"paths":{"/api/v1/saves":{"post":{"operationId":"save_links","summary":"Save links","tags":["Save and read"],"description":"Save up to 1,000 links. Links already on the board are skipped.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"},"urls":{"type":"array","items":{"type":"string"}},"text":{"type":"string","description":"Any text with links in it"},"items":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"note":{"type":"string"},"title":{"type":"string"},"collection":{"type":"string"}},"required":["url"]}},"note":{"type":"string"},"collection":{"type":"string","description":"A list name, created if new"}}}}}},"responses":{"201":{"description":"Saved: found, added, duplicates, skipped, alreadySavedFiled (links already saved, filed into the collection), alreadySavedKept (left where the person put them), alreadySavedChangeId (undoes the filing), board_url"},"401":{"description":"Missing, expired or revoked API key or token"},"422":{"description":"No links in the request"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}}},"get":{"operationId":"search_saves","summary":"Search saves, or list the newest","tags":["Save and read"],"parameters":[{"name":"q","in":"query","schema":{"type":"string"},"description":"Search by meaning and keywords; leave out for the newest saves"},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":50}}],"responses":{"200":{"description":"Saves","content":{"application/json":{"schema":{"type":"object","properties":{"query":{"type":["string","null"]},"saves":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":["string","null"]},"url":{"type":["string","null"]},"author":{"type":["string","null"]},"category":{"type":["string","null"]},"saved_at":{"type":["string","null"],"format":"date-time"}}}}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}}}},"/api/v1/boards":{"get":{"operationId":"list_custom_boards","summary":"The custom boards the person is on","description":"Custom boards: boards with a name, a public description and (for the person who made each) private instructions for what gets suggested, shared by a link; people who join add their own saves. Each with id, name, made_by_user, who else is on it (with) and join_url, the link to send. Make and change them with POST /api/v1/actions/create_board, add_to_board, take_off_board and the rest.","tags":["Save and read"],"responses":{"200":{"description":"boards (id, name, made_by_user, with, join_url)"},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}}}},"/api/v1/boards/{id}":{"get":{"operationId":"get_custom_board","summary":"One custom board: its saves, who's on it, its link, and suggestions","description":"Its description (public: everyone with the link sees it), its instructions for suggestions (private: only in the answer when the person made the board), who's on it, join_url, the saves on it with who added each (private ones included: everyone on the board sees them), and the saves of the person's suggested for it, waiting for them to add or skip (each with why it fits only when the person made the board: for anyone else the reason would say what the private instructions name). Read-only.","tags":["Save and read"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"board (id, name, description, instructions — the maker only, made_by_user, join_url, people), saves, save_count, suggestions (id, title, url, why — the maker only, private), message"},"401":{"description":"Missing, expired or revoked API key or token"},"404":{"description":"Not a board the person is on"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}}}},"/api/v1/feed":{"get":{"operationId":"friends_saves","summary":"What the people you follow and your group chats have saved","description":"The other saves on the person's board, newest first: public saves of people they follow, and saves other people posted in group chats they're in. A link several of them saved is one entry, with who else. Read-only.","tags":["Save and read"],"parameters":[{"name":"from","in":"query","schema":{"type":"string"},"description":"A friend's name or @handle, or a group chat's name"},{"name":"q","in":"query","schema":{"type":"string"},"description":"Words to find; every word must appear. With `from` a chat's name, searches that group chat's saves"},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":50}}],"responses":{"200":{"description":"saves (id, title, url, from, from_kind friend|group, from_handle, category, saved_at, also_saved_by), following, chats, matched, message"},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}}}},"/api/v1/saves/count":{"get":{"operationId":"count_saves","summary":"Count saves: all, or by category, period, words they mention, kind and privacy","description":"The exact total, a count per category, links/notes/files, and the newest matches. Places are matched by the words in each save, so a save that never names the place isn't counted.","tags":["Save and read"],"parameters":[{"name":"category","in":"query","schema":{"type":"string"},"description":"A category id or name"},{"name":"period","in":"query","schema":{"type":"string"},"description":"e.g. today, last week, the past 30 days, in July, since June, this year"},{"name":"since","in":"query","schema":{"type":"string","format":"date"}},{"name":"until","in":"query","schema":{"type":"string","format":"date"}},{"name":"mentions","in":"query","schema":{"type":"string"},"description":"Words the save mentions, e.g. San Francisco"},{"name":"kind","in":"query","schema":{"type":"string","enum":["link","note","file"]}},{"name":"private","in":"query","schema":{"type":"boolean"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":0,"maximum":25,"default":5},"description":"Newest matches to list"}],"responses":{"200":{"description":"total, by_category, by_kind, newest"},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}}}},"/api/v1/saves/{id}":{"get":{"operationId":"get_save","summary":"One save in full: note, extra links, comments, files (also someone else's save the caller can see: on a board with them, or a note tags them)","tags":["Save and read"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The save, with links, comments and files (download links valid for an hour)"},"401":{"description":"Missing, expired or revoked API key or token"},"404":{"description":"No such save, or not one the caller can see"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}}}},"/api/v1/notes":{"post":{"operationId":"save_note","summary":"Save a text note","tags":["Save and read"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"type":"string"},"title":{"type":"string"},"categoryId":{"type":"string"},"private":{"type":"boolean","default":true}},"required":["text"]}}}},"responses":{"201":{"description":"Saved: id, title, private"},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}}}},"/api/v1/files":{"post":{"operationId":"upload_file","summary":"Upload a photo, video or file","description":"As a new save, or attached to an existing one (itemId). With itemId and cover: true, a photo or video becomes the picture on that save's tile (nothing is deleted; a file that was in front stays behind it). fileUrl: a public https link, up to 25 MB. data: base64, up to 3 MB. Counts against the person's storage.","tags":["Save and read"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fileUrl":{"type":"string"},"data":{"type":"string","description":"base64"},"filename":{"type":"string"},"mimeType":{"type":"string"},"itemId":{"type":"string"},"cover":{"type":"boolean","description":"With itemId: make this photo or video the save's tile picture."},"caption":{"type":"string"},"categoryId":{"type":"string"},"private":{"type":"boolean","default":true}}}}}},"responses":{"201":{"description":"Stored: save_id, file_id, kind, size_bytes, new_save, title, title_is_automatic, remaining_bytes, and cover.previous_file_id when cover was set. With no caption the title is \"Photo: IMG_4823\" (kind and file name), renamed to what the file shows once SaveHQ has read it."},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"404":{"description":"No such save on this board"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}}}},"/api/v1/me":{"get":{"operationId":"get_board_link","summary":"The link to share the board, and the board link","tags":["Save and read"],"responses":{"200":{"description":"handle, display_name, share_url (send this to friends: public saves, no sign-in), public_profile_url, board_url (the person's own board; needs their sign-in)"},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}}}},"/api/v1/board":{"get":{"operationId":"get_board_overview","summary":"Categories, views, group chats, people followed, custom boards, invites waiting and notes that tag the caller, with ids","tags":["Save and read"],"responses":{"200":{"description":"categories, views, groups, people, boards, invites, tagged_notes"},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}}}},"/api/v1/actions":{"get":{"operationId":"list_actions","summary":"Every change the API can make (public)","tags":["Change the board"],"security":[],"responses":{"200":{"description":"actions: name, title, description, needs_ok, destructive, input"}}}},"/api/v1/actions/create_category":{"post":{"operationId":"create_category","summary":"Create a SaveHQ category","description":"Create a new category (a list on the user's board), e.g. \"Ramen\".\n\nNeeds the person's OK: never.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","description":"Display name, e.g. 'Ramen'."},"emoji":{"type":"string","description":"A single emoji for the category."},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["label"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}}}},"/api/v1/actions/rename_category":{"post":{"operationId":"rename_category","summary":"Rename a SaveHQ category","description":"Rename one of the user's categories. Its saves stay in it.\n\nNeeds the person's OK: never.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"categoryId":{"type":"string","description":"A category id exactly as given to you."},"label":{"type":"string"},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["categoryId","label"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}},"x-destructive":true}},"/api/v1/actions/set_category_emoji":{"post":{"operationId":"set_category_emoji","summary":"Set a category's emoji","description":"Set or remove (emoji: null) the emoji on a category's chip.\n\nNeeds the person's OK: never.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"categoryId":{"type":"string","description":"A category id exactly as given to you."},"emoji":{"type":["string","null"]},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["categoryId","emoji"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}},"x-destructive":true}},"/api/v1/actions/reorder_categories":{"post":{"operationId":"reorder_categories","summary":"Reorder SaveHQ categories","description":"Put the category chips in a new order. List category ids in the order wanted; any left out keep their order after them.\n\nNeeds the person's OK: never.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"order":{"type":"array","items":{"type":"string"}},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["order"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}},"x-destructive":true}},"/api/v1/actions/merge_categories":{"post":{"operationId":"merge_categories","summary":"Merge two SaveHQ categories","description":"Merge one category into another: every save in the first moves into the second, and the first is removed. The old name still finds it in search. Needs the user's OK: the first call returns a preview and a confirmToken.\n\nNeeds the person's OK: always.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fromCategoryId":{"type":"string","description":"A category id exactly as given to you."},"intoCategoryId":{"type":"string","description":"A category id exactly as given to you."},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["fromCategoryId","intoCategoryId"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}},"x-destructive":true}},"/api/v1/actions/delete_category":{"post":{"operationId":"delete_category","summary":"Delete a SaveHQ category","description":"Delete one of the user's categories. Its saves are never deleted. With moveTo (another of their categories, by id or name) its saves move into that category first, as in a merge: none is doubled, and the deleted name still finds them in search. Without moveTo they stay on the board: any also in another category stay there, the rest become uncategorized. Needs the user's OK: the first call returns a preview, which says how many saves the category has and where they'll go, and a confirmToken. One undo_change brings the category back with its saves as they were.\n\nNeeds the person's OK: always.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"categoryId":{"type":"string","description":"A category id exactly as given to you."},"moveTo":{"type":"string","description":"Optional: the category to move its saves into before it's deleted, by id or by name (e.g. 'Recipes')."},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["categoryId"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}},"x-destructive":true}},"/api/v1/actions/move_saves":{"post":{"operationId":"move_saves","summary":"Move SaveHQ saves","description":"Move saves into one category (replacing the category they were in), or to Uncategorized with categoryId null. Moving 20 or more at once needs the user's OK.\n\nNeeds the person's OK: 20+ saves.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"itemIds":{"type":"array","items":{"type":"string"},"description":"Save ids exactly as given to you."},"categoryId":{"type":["string","null"],"description":"Target category id, or null for Uncategorized."},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["itemIds","categoryId"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}},"x-destructive":true}},"/api/v1/actions/edit_save":{"post":{"operationId":"edit_save","summary":"Edit a SaveHQ save","description":"Change a save's title, its note, or both. Pass only what should change; note \"\" clears it.\n\nNeeds the person's OK: never.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"itemId":{"type":"string"},"title":{"type":"string"},"note":{"type":"string"},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["itemId"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}},"x-destructive":true}},"/api/v1/actions/set_privacy":{"post":{"operationId":"set_privacy","summary":"Make SaveHQ saves private or public","description":"Make saves private (only the user sees them) or public (shown on their SaveHQ profile). Making any save public, or changing 20 or more at once, needs the user's OK. Saves from a group chat can't be made public.\n\nNeeds the person's OK: making saves public, or 20+ saves.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"itemIds":{"type":"array","items":{"type":"string"},"description":"Save ids exactly as given to you."},"private":{"type":"boolean"},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["itemIds","private"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}},"x-destructive":true}},"/api/v1/actions/delete_saves":{"post":{"operationId":"delete_saves","summary":"Delete SaveHQ saves","description":"Delete specific saves by id, up to 20 per call. Always needs the user's OK: a call without a valid confirmToken deletes nothing and returns a preview and a token; the same call with that token deletes. A deleted save can be restored for 7 days with the changeId the delete returns.\n\nNeeds the person's OK: always.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"itemIds":{"type":"array","items":{"type":"string"},"description":"Save ids exactly as given to you.","minItems":1,"maxItems":20},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["itemIds"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}},"x-destructive":true}},"/api/v1/actions/pin_save":{"post":{"operationId":"pin_save","summary":"Pin a SaveHQ save","description":"Pin a save to the front of the main board, or of one category's board when categoryId is given. A full board (10 on main, 3 per category) drops its oldest pin.\n\nNeeds the person's OK: never.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"itemId":{"type":"string"},"categoryId":{"type":"string"},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["itemId"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}},"x-destructive":true}},"/api/v1/actions/unpin_save":{"post":{"operationId":"unpin_save","summary":"Unpin a SaveHQ save","description":"Unpin a save from the main board, or from one category's board when categoryId is given.\n\nNeeds the person's OK: never.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"itemId":{"type":"string"},"categoryId":{"type":"string"},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["itemId"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}},"x-destructive":true}},"/api/v1/actions/create_view":{"post":{"operationId":"create_view","summary":"Create a SaveHQ view","description":"Make a view: the user's saves plus one or two people they follow (by person id), side by side.\n\nNeeds the person's OK: never.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"personIds":{"type":"array","items":{"type":"string"}},"name":{"type":"string"},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["personIds"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}}}},"/api/v1/actions/rename_view":{"post":{"operationId":"rename_view","summary":"Rename a SaveHQ view","description":"Rename one of the user's views.\n\nNeeds the person's OK: never.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"viewId":{"type":"string"},"name":{"type":"string"},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["viewId","name"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}},"x-destructive":true}},"/api/v1/actions/delete_view":{"post":{"operationId":"delete_view","summary":"Delete a SaveHQ view","description":"Delete one of the user's views. No saves are lost: a view only shows saves. Needs the user's OK: the first call returns a preview and a confirmToken.\n\nNeeds the person's OK: always.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"viewId":{"type":"string"},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["viewId"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}},"x-destructive":true}},"/api/v1/actions/rename_group":{"post":{"operationId":"rename_group","summary":"Rename a group chat board","description":"Rename a group chat's board. Everyone in that chat sees the new name.\n\nNeeds the person's OK: never.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"groupId":{"type":"string"},"name":{"type":"string"},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["groupId","name"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}},"x-destructive":true}},"/api/v1/actions/update_profile":{"post":{"operationId":"update_profile","summary":"Update SaveHQ profile and privacy settings","description":"Change the user's display name, @handle, bio, whether new saves start private (newSavesPrivate), whether new followers need their approval (approveFollowers), and, with approval on, whether people they haven't approved yet see only their pinned saves (pinnedOnlyUntilApproved). Pass only what should change. Always needs the user's OK: the first call returns a preview and a confirmToken.\n\nNeeds the person's OK: always.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"displayName":{"type":"string"},"handle":{"type":"string"},"bio":{"type":"string"},"newSavesPrivate":{"type":"boolean"},"approveFollowers":{"type":"boolean"},"pinnedOnlyUntilApproved":{"type":"boolean"},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":[]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}},"x-destructive":true}},"/api/v1/actions/set_notification_settings":{"post":{"operationId":"set_notification_settings","summary":"Change which SaveHQ emails the user gets","description":"Turn kinds of SaveHQ email on or off for the user: tags (someone tags them in a note), boards (people add to a custom board they're on), invites (board invites, requests to join their boards, and people joining them), followers (new followers and follow requests, and people joining their group chats; the first of each right away, then at most one round-up a day; things they and people they follow both saved ride along in those follower emails, never on their own), tips (tips and check-ins), or all. Pass only what should change. Replies to emails they send SaveHQ always come. get_board_overview shows the current settings.\n\nNeeds the person's OK: never.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"tags":{"type":"boolean"},"boards":{"type":"boolean"},"invites":{"type":"boolean"},"followers":{"type":"boolean"},"tips":{"type":"boolean"},"all":{"type":"boolean"},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":[]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}}}},"/api/v1/actions/set_appearance":{"post":{"operationId":"set_appearance","summary":"Switch SaveHQ between light and dark","description":"Set how SaveHQ looks for the user: \"dark\", \"light\", or \"system\" (match the device, light or dark as their phone or computer is set). It follows them to every device, from the next page they open in SaveHQ. Only they see it, so it needs no OK. get_board_overview shows the current choice.\n\nNeeds the person's OK: never.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"appearance":{"type":"string","enum":["system","light","dark"]},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["appearance"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}}}},"/api/v1/actions/add_comment":{"post":{"operationId":"add_comment","summary":"Add a comment to a SaveHQ save","description":"Add a note to one of the user's saves, or to any save on a custom board they're on. Notes start private (only the user sees them). public true shows it to everyone who can see the save; tag (person ids from get_save) lets those people read it and tells them in about 15 seconds. Either needs the user's OK: the first call returns a preview and a confirmToken.\n\nNeeds the person's OK: making it public.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"itemId":{"type":"string"},"text":{"type":"string"},"public":{"type":"boolean"},"tag":{"type":"array","items":{"type":"string"},"description":"Person ids from get_save's “can tag” list."},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["itemId","text"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}}}},"/api/v1/actions/edit_comment":{"post":{"operationId":"edit_comment","summary":"Edit a comment on a SaveHQ save","description":"Change a comment's text, or make it public or private. Pass only what should change. Making a comment public needs the user's OK.\n\nNeeds the person's OK: making it public.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"commentId":{"type":"string"},"text":{"type":"string"},"public":{"type":"boolean"},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["commentId"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}},"x-destructive":true}},"/api/v1/actions/delete_comment":{"post":{"operationId":"delete_comment","summary":"Delete a comment on a SaveHQ save","description":"Delete one comment, by its id. Always needs the user's OK: the first call returns a preview and a confirmToken.\n\nNeeds the person's OK: always.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"commentId":{"type":"string"},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["commentId"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}},"x-destructive":true}},"/api/v1/actions/add_links_to_save":{"post":{"operationId":"add_links_to_save","summary":"Add links to a SaveHQ save","description":"Attach up to 10 extra links to one save. Its main link stays as it is. Links already on the save are skipped.\n\nNeeds the person's OK: never.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"itemId":{"type":"string"},"urls":{"type":"array","items":{"type":"string"}},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["itemId","urls"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}}}},"/api/v1/actions/replace_save_link":{"post":{"operationId":"replace_save_link","summary":"Replace the link on a SaveHQ save","description":"Swap a save's link for another (itemId, url). On a link save its own link changes and the tile's picture, source and default title follow the new link; a title the user typed and a cover photo they chose stay. On a photo or note, the first extra link is swapped (or one is added). Refused if the new link is already saved on the board as another save. Undo with undo_change.\n\nNeeds the person's OK: never.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"itemId":{"type":"string"},"url":{"type":"string","description":"The new link, a full https:// address."},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["itemId","url"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}},"x-destructive":true}},"/api/v1/actions/remove_link_from_save":{"post":{"operationId":"remove_link_from_save","summary":"Remove a link from a SaveHQ save","description":"Take one extra link off a save, by the link id. Always needs the user's OK: the first call returns a preview and a confirmToken.\n\nNeeds the person's OK: always.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"itemId":{"type":"string"},"linkId":{"type":"string"},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["itemId","linkId"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}},"x-destructive":true}},"/api/v1/actions/look_at_file":{"post":{"operationId":"look_at_file","summary":"Read the files on SaveHQ saves","description":"Watch a video, listen to a voice note or look at a photo attached to the user's saves, or watch a public YouTube video the user saved or read an X post they saved (its video and photos) (itemId, or several as itemIds), and return what each shows and says, as text. With no ids, it reads the newest videos, voice notes and YouTube links that haven't been read yet, up to 5. Anything already read returns what was stored, free — videos, voice notes and YouTube links are read within minutes of being saved, so most are; reading a new one uses the user's SaveHQ AI credits. Changes nothing on the board, except that a save still wearing the name SaveHQ gave it (\"Video: IMG_0042\") is renamed to what its file shows. A link to an Instagram or TikTok post is not a file and can't be opened.\n\nNeeds the person's OK: never.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"itemId":{"type":"string","description":"One save's id exactly as given to you."},"itemIds":{"type":"array","items":{"type":"string"},"description":"Several saves' ids exactly as given to you."},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":[]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}}}},"/api/v1/actions/set_profile_photo":{"post":{"operationId":"set_profile_photo","summary":"Set the SaveHQ profile photo","description":"Set the user's profile photo from an image already on their board (fileId), a public https image link (fileUrl), or base64 data. JPEG, PNG, WebP or GIF, up to 10 MB. Always needs the user's OK: the first call returns a preview and a confirmToken.\n\nNeeds the person's OK: always.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fileId":{"type":"string"},"fileUrl":{"type":"string"},"data":{"type":"string"},"mimeType":{"type":"string"},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":[]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}},"x-destructive":true}},"/api/v1/actions/remove_profile_photo":{"post":{"operationId":"remove_profile_photo","summary":"Remove the SaveHQ profile photo","description":"Remove the user's profile photo. Always needs the user's OK: the first call returns a preview and a confirmToken.\n\nNeeds the person's OK: always.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":[]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}},"x-destructive":true}},"/api/v1/actions/set_group_saving":{"post":{"operationId":"set_group_saving","summary":"Turn group chat saving on or off","description":"Turn saving of the user's own links in one group chat on or off. Doesn't affect anyone else, and never deletes past saves.\n\nNeeds the person's OK: never.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"groupId":{"type":"string"},"on":{"type":"boolean"},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["groupId","on"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}},"x-destructive":true}},"/api/v1/actions/create_board":{"post":{"operationId":"create_board","summary":"Make a SaveHQ custom board","description":"Make a custom board, shared by a link: a name, an optional description (public: shown under the name to everyone who opens the link) and optional instructions (private: only the user sees them; SaveHQ suggests saves that fit them, e.g. \"anything tagged ✈️ To Travel, and places to stay in Bali\"). People who open the link can ask to join, and people on it add their own saves. Optional itemIds puts saves of the user's on it now (20 or more needs the user's OK). Returns the board id and join_url, the link to send.\n\nNeeds the person's OK: 20+ saves.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"e.g. 'Bali trip'."},"description":{"type":"string","description":"Public: shown under the name to everyone who opens the link, e.g. 'Where we're staying and eating in Bali'. Not what suggestions follow."},"instructions":{"type":"string","description":"Private, only they see them: what AI should suggest for it, e.g. 'places to stay and eat in Bali, and anything tagged ✈️ To Travel' (naming one of their tags pulls in that tag's saves). Left out, suggestions follow the name and description."},"itemIds":{"type":"array","items":{"type":"string"},"description":"Save ids exactly as given to you."},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["name"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}}}},"/api/v1/actions/update_board":{"post":{"operationId":"update_board","summary":"Change a SaveHQ custom board","description":"Change a custom board the user made: name, description (public: everyone with the link sees it), instructions (private, only the user sees them: what SaveHQ suggests saves for — for \"suggest cocktail bars on Date night\", change instructions, not description), who can see it (seePolicy: anyone = public, pinned = pinned saves only, approved = private; joining always needs an invite or the user's approval) and who can add (addPolicy: anyone, approval, owner). Pass only what should change. Opening it up (seePolicy anyone or pinned) needs the user's OK: the first call returns a preview and a confirmToken.\n\nNeeds the person's OK: never.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"boardId":{"type":"string","description":"A custom board's id exactly as given to you."},"name":{"type":"string"},"description":{"type":"string","description":"Public: shown under the name to everyone who opens the link."},"instructions":{"type":"string","description":"Private, only they see them: what AI suggests saves for, e.g. 'cocktail bars and late-night spots'. Naming one of their tags pulls in that tag's saves."},"seePolicy":{"type":"string","enum":["anyone","pinned","approved"]},"addPolicy":{"type":"string","enum":["anyone","approval","owner"]},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["boardId"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}},"x-destructive":true}},"/api/v1/actions/add_to_board":{"post":{"operationId":"add_to_board","summary":"Add saves to a SaveHQ custom board","description":"Put saves on a custom board the user is on. The user's own saves go on as they are, not copied, and stay on their own board. Someone else's save the user can see (from friends_saves or a group chat) is a link, so it is saved to the user's board first and then added; undo removes that copy too. Everyone on the board sees them, private ones included, so this always needs the user's OK: the first call returns a preview naming who will see them, and a confirmToken.\n\nNeeds the person's OK: always.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"boardId":{"type":"string","description":"A custom board's id exactly as given to you."},"itemIds":{"type":"array","items":{"type":"string"},"description":"Save ids exactly as given to you."},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["boardId","itemIds"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}}}},"/api/v1/actions/answer_board_requests":{"post":{"operationId":"answer_board_requests","summary":"Answer requests to join a SaveHQ custom board","description":"On a custom board the user made: let people who asked in (approve true; each is told, in SaveHQ and by email) or turn them down (approve false; block true also blocks them; nobody is told), by person id from get_custom_board. Always needs the user's OK: the first call returns a preview and a confirmToken.\n\nNeeds the person's OK: always.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"boardId":{"type":"string","description":"A custom board's id exactly as given to you."},"personIds":{"type":"array","items":{"type":"string"},"description":"Person ids exactly as get_custom_board gave them."},"approve":{"type":"boolean"},"block":{"type":"boolean","description":"With approve false: also block them."},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["boardId","personIds","approve"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}},"x-destructive":true}},"/api/v1/actions/invite_to_board":{"post":{"operationId":"invite_to_board","summary":"Invite people to a SaveHQ custom board","description":"Invite people who follow the user, or whom the user follows, onto a custom board the user made (get_custom_board lists them as can_invite). They get an invite to accept by email and in the app; nobody is added until they accept. Always needs the user's OK: the first call returns a preview and a confirmToken.\n\nNeeds the person's OK: always.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"boardId":{"type":"string","description":"A custom board's id exactly as given to you."},"personIds":{"type":"array","items":{"type":"string"},"description":"Person ids from get_custom_board's can_invite list."},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["boardId","personIds"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}}}},"/api/v1/actions/decline_board_invite":{"post":{"operationId":"decline_board_invite","summary":"Decline an invite to a SaveHQ custom board","description":"Say no thanks to an invite to someone's custom board, by its link (get_board_overview lists the user's invites). The maker isn't told.\n\nNeeds the person's OK: never.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"link":{"type":"string","description":"The board's link, savehq.app/b/…"},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["link"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}},"x-destructive":true}},"/api/v1/actions/review_board_saves":{"post":{"operationId":"review_board_saves","summary":"OK saves waiting on a SaveHQ custom board","description":"On a custom board the user made where each save waits for their OK: put saves people sent on it (approve true) or turn them down (approve false), by save id from get_custom_board. Turning down deletes nothing. Always needs the user's OK: the first call returns a preview and a confirmToken.\n\nNeeds the person's OK: always.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"boardId":{"type":"string","description":"A custom board's id exactly as given to you."},"itemIds":{"type":"array","items":{"type":"string"},"description":"Save ids exactly as given to you."},"approve":{"type":"boolean"},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["boardId","itemIds","approve"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}},"x-destructive":true}},"/api/v1/actions/pin_on_board":{"post":{"operationId":"pin_on_board","summary":"Pin a save on a SaveHQ custom board","description":"Pin a save to the top of a custom board the user made, or unpin it (pinned false). Only the maker pins.\n\nNeeds the person's OK: never.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"boardId":{"type":"string","description":"A custom board's id exactly as given to you."},"itemId":{"type":"string","description":"A save id on that board."},"pinned":{"type":"boolean"},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["boardId","itemId"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}}}},"/api/v1/actions/move_on_board":{"post":{"operationId":"move_on_board","summary":"Move a save on a SaveHQ custom board","description":"Move a save to a different place in a custom board's order, by save id: to \"top\" or \"bottom\", or right before (beforeItemId) or after (afterItemId) another save on the board; give exactly one. The board has one order that everyone on it sees. On a board where anyone on it adds straight on, anyone on it may rearrange it; otherwise only its maker. Pinned saves stay above the rest.\n\nNeeds the person's OK: never.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"boardId":{"type":"string","description":"A custom board's id exactly as given to you."},"itemId":{"type":"string","description":"The save to move, a save id on that board."},"to":{"type":"string","enum":["top","bottom"],"description":"To the top (under any pins) or the bottom."},"beforeItemId":{"type":"string","description":"Put it right before this save on the board."},"afterItemId":{"type":"string","description":"Put it right after this save on the board."},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["boardId","itemId"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}},"x-destructive":true}},"/api/v1/actions/take_off_board":{"post":{"operationId":"take_off_board","summary":"Take saves off a SaveHQ custom board","description":"Take saves off a custom board. No save is deleted. The board's maker can take off anything; anyone else only what they added. 20 or more at once needs the user's OK.\n\nNeeds the person's OK: 20+ saves.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"boardId":{"type":"string","description":"A custom board's id exactly as given to you."},"itemIds":{"type":"array","items":{"type":"string"},"description":"Save ids exactly as given to you."},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["boardId","itemIds"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}},"x-destructive":true}},"/api/v1/actions/skip_board_suggestions":{"post":{"operationId":"skip_board_suggestions","summary":"Skip suggestions for a SaveHQ custom board","description":"Skip saves suggested for a custom board, by save id: they won't be suggested for it again. Nothing is added or deleted.\n\nNeeds the person's OK: never.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"boardId":{"type":"string","description":"A custom board's id exactly as given to you."},"itemIds":{"type":"array","items":{"type":"string"},"description":"Save ids exactly as given to you."},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["boardId","itemIds"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}},"x-destructive":true}},"/api/v1/actions/join_board":{"post":{"operationId":"join_board","summary":"Join a SaveHQ custom board","description":"Ask to join a custom board by its link (savehq.app/b/…), or accept an invite to it. Without an invite it sends a request the maker approves; with one the user is on it at once. Nothing of the user's goes on it.\n\nNeeds the person's OK: never.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"link":{"type":"string","description":"The board's link, savehq.app/b/…"},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["link"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}}}},"/api/v1/actions/leave_board":{"post":{"operationId":"leave_board","summary":"Leave a SaveHQ custom board","description":"Leave a custom board someone else made. What the user added comes off it; no save is deleted. Always needs the user's OK: the first call returns a preview and a confirmToken.\n\nNeeds the person's OK: always.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"boardId":{"type":"string","description":"A custom board's id exactly as given to you."},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["boardId"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}},"x-destructive":true}},"/api/v1/actions/set_board_updates":{"post":{"operationId":"set_board_updates","summary":"Turn a SaveHQ custom board's emails on or off","description":"Stop (on: false) or start again (on: true) the emails the user gets when other people add to a custom board: the first add right away, then evening, daily and weekly summaries. They stay on the board either way.\n\nNeeds the person's OK: never.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"boardId":{"type":"string","description":"A custom board's id exactly as given to you."},"on":{"type":"boolean"},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["boardId","on"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}},"x-destructive":true}},"/api/v1/actions/delete_board":{"post":{"operationId":"delete_board","summary":"Delete a SaveHQ custom board","description":"Delete a custom board the user made. It goes for everyone on it; every save that was on it stays on each person's own board. Always needs the user's OK: the first call returns a preview and a confirmToken.\n\nNeeds the person's OK: always.","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"boardId":{"type":"string","description":"A custom board's id exactly as given to you."},"confirmToken":{"type":"string","description":"The confirmToken returned with this change's preview, once the user has agreed to it."}},"required":["boardId"]}}}},"responses":{"200":{"description":"Done (status \"done\", with summary and changeId), or nothing to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeDone"}}}},"202":{"description":"Not done yet: needs the person's OK. Send the same request again with confirmToken.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeedsConfirmation"}}}},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}},"x-destructive":true}},"/api/v1/changes":{"get":{"operationId":"recent_changes","summary":"Recent changes on the board, with the changeId to undo each","description":"Newest first: changes made on the board by hand, by SaveHQ's own AI, by its weekly tidy and by any app, not yet undone. For \"undo my last delete\", list with onlyDeletes=true and POST the first changeId to /api/v1/undo.","tags":["Change the board"],"parameters":[{"name":"onlyDeletes","in":"query","schema":{"type":"boolean"},"description":"Only changes that deleted or removed something."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":25},"description":"How many (default 10)."}],"responses":{"200":{"description":"changes: changeId, at, ago, changes (one line per step), removed, canUndo, why"},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}}}},"/api/v1/undo":{"post":{"operationId":"undo_change","summary":"Undo a change","tags":["Change the board"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"changeId":{"type":"string"}},"required":["changeId"]}}}},"responses":{"200":{"description":"undone, partly_undone or nothing_to_undo"},"400":{"description":"Something to fix in the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Missing, expired or revoked API key or token"},"429":{"description":"Over 60 requests a minute for this person; retry after 60 seconds"}}}}},"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","description":"A personal API key (shq_…, from SaveHQ Settings → AI & integrations) or an OAuth access token (see https://savehq.app/.well-known/oauth-protected-resource)."}},"schemas":{"ChangeDone":{"type":"object","properties":{"status":{"type":"string","enum":["done","no_change"]},"summary":{"type":"string"},"changeId":{"type":"string"},"message":{"type":"string"}}},"NeedsConfirmation":{"type":"object","properties":{"status":{"type":"string","enum":["needs_confirmation"]},"preview":{"type":"string"},"confirmToken":{"type":"string"},"expiresInSeconds":{"type":"integer"},"message":{"type":"string"}}}}}}