{"openapi":"3.1.0","info":{"title":"Sedimental API","version":"0.1.0","description":"The backend for Sedimental: accounts, multi-device sync of a personal library, and an anonymous aggregate of the most-saved public URLs.\n\nThis document is generated from the Zod schemas the routes validate and serialise with, and a test asserts that the served document and the committed `openapi.json` are byte-identical. It describes what the service does, not what it was once specified to do.\n\n**Authentication.** A `Bearer` access token, obtained from any of the `/v1/auth` endpoints and refreshed with `POST /v1/auth/refresh`. Access tokens are short-lived; refresh tokens rotate on every use and reusing a rotated one revokes the whole family. Each operation below declares its own requirement: an empty `security` array means the endpoint is public.\n\n**Errors.** Every error body carries a stable machine-readable `error` value — the auth endpoints repeat it as `code` — plus a human-readable `message`. Switch on the code, never on the message text. The `/v1/auth` endpoints share one error body schema, so their responses list every auth code the schema permits rather than the narrower set a particular status can produce.\n\n**Unknown fields.** A schema that declares `additionalProperties: false` — the sync bodies, the sync query, the discover controls, the account query — rejects an unknown field with `400 invalid_request` rather than ignoring it, so a client sending a field this API does not define is told at the boundary. The `/v1/auth` bodies instead strip what they do not declare, which is what stops a client library from delivering Apple's first-authorisation user object.\n\n**No path parameters.** No operation in this API is path-templated, deliberately: the access log records request paths, so identifiers travel in bodies and query strings instead.\n\n**Deletes are hard.** `DELETE /v1/account` and both outcomes of `POST /v1/auth/upgrade/resolve` remove rows permanently. There is no tombstone, no soft-delete and no recovery path.\n\n**What this API does not carry.** There is no email field in any schema, request or response — the Apple `sub` is the only identity key this service stores. The discover surface is text: a canonical URL, an optional title and counts of distinct accounts. No thumbnail, preview image, author, like count or comment count appears anywhere in this document, and none is coming."},"servers":[{"url":"https://api.sedimental-api.slonix.dev","description":"Production."},{"url":"https://sedimental-api.slonix.dev","description":"The same service on the host that also serves the status page."}],"tags":[{"name":"auth","description":"Accounts, tokens and the upgrade from anonymous to Apple."},{"name":"sync","description":"The personal library: pull a page of changes, push a batch."},{"name":"discover","description":"The anonymous save aggregate, and the personal controls over it. Every control takes its url_hash in a body, never in a path, so a hash never reaches an access log line."},{"name":"account","description":"The account record, the data export and the deletion."},{"name":"health","description":"Liveness."},{"name":"meta","description":"This document."}],"paths":{"/openapi.json":{"get":{"operationId":"getOpenapiJson","summary":"This document","description":"The OpenAPI 3.1 description of this service, generated from the same Zod schemas the routes validate with. The identical document is committed to the repository as openapi.json.","tags":["meta"],"security":[],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"openapi":{"type":"string","const":"3.1.0"}},"required":["openapi"],"additionalProperties":{}}}}}}}},"/v1/account":{"get":{"operationId":"getV1Account","summary":"The account, including the privacy policy version it accepted","description":"Returns the consent version and date exactly as recorded, alongside the version the service is on today so the client can compare them.","tags":["account"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"created_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"is_anonymous":{"type":"boolean"},"consent_version":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"consent_accepted_at":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},{"type":"null"}]},"current_policy_version":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","created_at","is_anonymous","consent_version","consent_accepted_at","current_policy_version"],"additionalProperties":false}}}},"400":{"description":"The request does not match the expected shape. `details` names the offending fields. Machine-readable `error` value: `invalid_request`.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","const":"invalid_request"},"message":{"type":"string","const":"The request does not match the expected shape."},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["error","message","details"],"additionalProperties":false}}}},"401":{"description":"The access token is missing, does not verify, or names an account that no longer exists. Machine-readable `error` value: `unauthorized`.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","const":"unauthorized"},"message":{"type":"string"}},"required":["error","message"],"additionalProperties":false}}}}}},"delete":{"operationId":"deleteV1Account","summary":"Delete the account and everything it holds, permanently","description":"Removes every row this account owns — the account, its identities, its refresh tokens, every topic and every saved reel — in one transaction, then brings the anonymous aggregate counters in line with what remains. THE DELETE IS HARD AND IRREVERSIBLE: this service keeps no tombstone, no backup copy and no recovery path, and there is no endpoint that undoes it. Answers 204 with no body. Access tokens already issued stop working immediately, because every endpoint looks the account up.","tags":["account"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Success. The response carries no body."},"400":{"description":"The request does not match the expected shape. `details` names the offending fields. Machine-readable `error` value: `invalid_request`.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","const":"invalid_request"},"message":{"type":"string","const":"The request does not match the expected shape."},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["error","message","details"],"additionalProperties":false}}}},"401":{"description":"The access token is missing, does not verify, or names an account that no longer exists. Machine-readable `error` value: `unauthorized`.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","const":"unauthorized"},"message":{"type":"string"}},"required":["error","message"],"additionalProperties":false}}}}}}},"/v1/account/export":{"get":{"operationId":"getV1AccountExport","summary":"Everything this backend holds about the account, as JSON","description":"The account row and every row of every table that carries its user id, each with every column it holds.","tags":["account"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"format_version":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"exported_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"account":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"created_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"seq_counter":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"consent_version":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"consent_accepted_at":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},{"type":"null"}]}},"required":["id","created_at","seq_counter","consent_version","consent_accepted_at"],"additionalProperties":false},"device_identities":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"device_key_hash":{"type":"string","minLength":64,"maxLength":64},"created_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"}},"required":["id","device_key_hash","created_at"],"additionalProperties":false}},"apple_identities":{"type":"array","items":{"type":"object","properties":{"apple_sub":{"type":"string"},"created_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"}},"required":["apple_sub","created_at"],"additionalProperties":false}},"refresh_tokens":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"token_hash":{"type":"string","minLength":64,"maxLength":64},"family_id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"issued_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"expires_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"revoked_at":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},{"type":"null"}]},"replaced_by":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]}},"required":["id","token_hash","family_id","issued_at","expires_at","revoked_at","replaced_by"],"additionalProperties":false}},"topics":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"name":{"type":"string"},"is_visible":{"type":"boolean"},"colour_index":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"created_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"updated_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"seq":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"deleted_at":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},{"type":"null"}]}},"required":["id","name","is_visible","colour_index","created_at","updated_at","seq","deleted_at"],"additionalProperties":false}},"reels":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"url":{"type":"string"},"platform":{"type":"string"},"topic_id":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"topic_is_confirmed":{"type":"boolean"},"is_favourite":{"type":"boolean"},"note":{"type":["string","null"]},"saved_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"open_count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"last_opened_at":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},{"type":"null"}]},"reminder_date":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},{"type":"null"}]},"url_hash":{"type":"string","minLength":64,"maxLength":64},"updated_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"seq":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"deleted_at":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},{"type":"null"}]}},"required":["id","url","platform","topic_id","topic_is_confirmed","is_favourite","note","saved_at","open_count","last_opened_at","reminder_date","url_hash","updated_at","seq","deleted_at"],"additionalProperties":false}},"discover_suppressions":{"type":"array","items":{"type":"object","properties":{"url_hash":{"type":"string","minLength":64,"maxLength":64},"created_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"}},"required":["url_hash","created_at"],"additionalProperties":false}}},"required":["format_version","exported_at","account","device_identities","apple_identities","refresh_tokens","topics","reels","discover_suppressions"],"additionalProperties":false}}}},"400":{"description":"The request does not match the expected shape. `details` names the offending fields. Machine-readable `error` value: `invalid_request`.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","const":"invalid_request"},"message":{"type":"string","const":"The request does not match the expected shape."},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["error","message","details"],"additionalProperties":false}}}},"401":{"description":"The access token is missing, does not verify, or names an account that no longer exists. Machine-readable `error` value: `unauthorized`.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","const":"unauthorized"},"message":{"type":"string"}},"required":["error","message"],"additionalProperties":false}}}}}}},"/v1/auth/anonymous":{"post":{"operationId":"postV1AuthAnonymous","summary":"Create or return the anonymous account for a device key","tags":["auth"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"device_key":{"type":"string","minLength":16,"maxLength":512}},"required":["device_key"]}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"user":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"is_anonymous":{"type":"boolean"},"created_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"}},"required":["id","is_anonymous","created_at"],"additionalProperties":false},"tokens":{"type":"object","properties":{"access_token":{"type":"string"},"refresh_token":{"type":"string"},"token_type":{"type":"string","const":"Bearer"},"expires_in":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"required":["access_token","refresh_token","token_type","expires_in"],"additionalProperties":false}},"required":["user","tokens"],"additionalProperties":false}}}},"400":{"description":"The request does not match the expected shape. `details` names the offending fields. Machine-readable `error` value: `invalid_request`.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","const":"invalid_request"},"message":{"type":"string","const":"The request does not match the expected shape."},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["error","message","details"],"additionalProperties":false}}}},"429":{"description":"Rate limited. Wait `retry_after_seconds` and retry. Machine-readable `error` values this response body may carry: `account_not_anonymous`, `apple_signin_unavailable`, `apple_token_invalid`, `rate_limited`, `refresh_token_expired`, `refresh_token_invalid`, `refresh_token_reused`, `resolution_token_expired`, `resolution_token_invalid`, `unauthorized`, `upgrade_conflict_stale`.","headers":{"retry-after":{"description":"Seconds to wait before retrying. Always equal to `retry_after_seconds`.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["rate_limited","apple_signin_unavailable","apple_token_invalid","refresh_token_invalid","refresh_token_expired","refresh_token_reused","unauthorized","account_not_anonymous","resolution_token_invalid","resolution_token_expired","upgrade_conflict_stale"]},"code":{"type":"string","enum":["rate_limited","apple_signin_unavailable","apple_token_invalid","refresh_token_invalid","refresh_token_expired","refresh_token_reused","unauthorized","account_not_anonymous","resolution_token_invalid","resolution_token_expired","upgrade_conflict_stale"]},"message":{"type":"string"},"retry_after_seconds":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"required":["error","code","message"],"additionalProperties":false}}}}}}},"/v1/auth/apple":{"post":{"operationId":"postV1AuthApple","summary":"Sign in with Apple: verify the identity token, create or return the account","tags":["auth"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"identity_token":{"type":"string","minLength":20,"maxLength":8192},"nonce":{"type":"string","minLength":1,"maxLength":512}},"required":["identity_token"]}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"user":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"is_anonymous":{"type":"boolean"},"created_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"}},"required":["id","is_anonymous","created_at"],"additionalProperties":false},"tokens":{"type":"object","properties":{"access_token":{"type":"string"},"refresh_token":{"type":"string"},"token_type":{"type":"string","const":"Bearer"},"expires_in":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"required":["access_token","refresh_token","token_type","expires_in"],"additionalProperties":false}},"required":["user","tokens"],"additionalProperties":false}}}},"400":{"description":"The request does not match the expected shape. `details` names the offending fields. Machine-readable `error` value: `invalid_request`.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","const":"invalid_request"},"message":{"type":"string","const":"The request does not match the expected shape."},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["error","message","details"],"additionalProperties":false}}}},"401":{"description":"The access token is missing, does not verify, or names an account that no longer exists. Machine-readable `error` values this response body may carry: `account_not_anonymous`, `apple_signin_unavailable`, `apple_token_invalid`, `rate_limited`, `refresh_token_expired`, `refresh_token_invalid`, `refresh_token_reused`, `resolution_token_expired`, `resolution_token_invalid`, `unauthorized`, `upgrade_conflict_stale`.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["rate_limited","apple_signin_unavailable","apple_token_invalid","refresh_token_invalid","refresh_token_expired","refresh_token_reused","unauthorized","account_not_anonymous","resolution_token_invalid","resolution_token_expired","upgrade_conflict_stale"]},"code":{"type":"string","enum":["rate_limited","apple_signin_unavailable","apple_token_invalid","refresh_token_invalid","refresh_token_expired","refresh_token_reused","unauthorized","account_not_anonymous","resolution_token_invalid","resolution_token_expired","upgrade_conflict_stale"]},"message":{"type":"string"},"retry_after_seconds":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"required":["error","code","message"],"additionalProperties":false}}}},"429":{"description":"Rate limited. Wait `retry_after_seconds` and retry. Machine-readable `error` values this response body may carry: `account_not_anonymous`, `apple_signin_unavailable`, `apple_token_invalid`, `rate_limited`, `refresh_token_expired`, `refresh_token_invalid`, `refresh_token_reused`, `resolution_token_expired`, `resolution_token_invalid`, `unauthorized`, `upgrade_conflict_stale`.","headers":{"retry-after":{"description":"Seconds to wait before retrying. Always equal to `retry_after_seconds`.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["rate_limited","apple_signin_unavailable","apple_token_invalid","refresh_token_invalid","refresh_token_expired","refresh_token_reused","unauthorized","account_not_anonymous","resolution_token_invalid","resolution_token_expired","upgrade_conflict_stale"]},"code":{"type":"string","enum":["rate_limited","apple_signin_unavailable","apple_token_invalid","refresh_token_invalid","refresh_token_expired","refresh_token_reused","unauthorized","account_not_anonymous","resolution_token_invalid","resolution_token_expired","upgrade_conflict_stale"]},"message":{"type":"string"},"retry_after_seconds":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"required":["error","code","message"],"additionalProperties":false}}}},"503":{"description":"A dependency this endpoint needs is unavailable right now. Nothing was written; retry later. Machine-readable `error` values this response body may carry: `account_not_anonymous`, `apple_signin_unavailable`, `apple_token_invalid`, `rate_limited`, `refresh_token_expired`, `refresh_token_invalid`, `refresh_token_reused`, `resolution_token_expired`, `resolution_token_invalid`, `unauthorized`, `upgrade_conflict_stale`.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["rate_limited","apple_signin_unavailable","apple_token_invalid","refresh_token_invalid","refresh_token_expired","refresh_token_reused","unauthorized","account_not_anonymous","resolution_token_invalid","resolution_token_expired","upgrade_conflict_stale"]},"code":{"type":"string","enum":["rate_limited","apple_signin_unavailable","apple_token_invalid","refresh_token_invalid","refresh_token_expired","refresh_token_reused","unauthorized","account_not_anonymous","resolution_token_invalid","resolution_token_expired","upgrade_conflict_stale"]},"message":{"type":"string"},"retry_after_seconds":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"required":["error","code","message"],"additionalProperties":false}}}}}}},"/v1/auth/logout":{"post":{"operationId":"postV1AuthLogout","summary":"Revoke the token family of the presented refresh token","tags":["auth"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"refresh_token":{"type":"string","minLength":16,"maxLength":512}},"required":["refresh_token"]}}}},"responses":{"204":{"description":"Success. The response carries no body."},"400":{"description":"The request does not match the expected shape. `details` names the offending fields. Machine-readable `error` value: `invalid_request`.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","const":"invalid_request"},"message":{"type":"string","const":"The request does not match the expected shape."},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["error","message","details"],"additionalProperties":false}}}},"429":{"description":"Rate limited. Wait `retry_after_seconds` and retry. Machine-readable `error` values this response body may carry: `account_not_anonymous`, `apple_signin_unavailable`, `apple_token_invalid`, `rate_limited`, `refresh_token_expired`, `refresh_token_invalid`, `refresh_token_reused`, `resolution_token_expired`, `resolution_token_invalid`, `unauthorized`, `upgrade_conflict_stale`.","headers":{"retry-after":{"description":"Seconds to wait before retrying. Always equal to `retry_after_seconds`.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["rate_limited","apple_signin_unavailable","apple_token_invalid","refresh_token_invalid","refresh_token_expired","refresh_token_reused","unauthorized","account_not_anonymous","resolution_token_invalid","resolution_token_expired","upgrade_conflict_stale"]},"code":{"type":"string","enum":["rate_limited","apple_signin_unavailable","apple_token_invalid","refresh_token_invalid","refresh_token_expired","refresh_token_reused","unauthorized","account_not_anonymous","resolution_token_invalid","resolution_token_expired","upgrade_conflict_stale"]},"message":{"type":"string"},"retry_after_seconds":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"required":["error","code","message"],"additionalProperties":false}}}}}}},"/v1/auth/refresh":{"post":{"operationId":"postV1AuthRefresh","summary":"Rotate a refresh token; reuse of a rotated token revokes its whole family","tags":["auth"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"refresh_token":{"type":"string","minLength":16,"maxLength":512}},"required":["refresh_token"]}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"tokens":{"type":"object","properties":{"access_token":{"type":"string"},"refresh_token":{"type":"string"},"token_type":{"type":"string","const":"Bearer"},"expires_in":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"required":["access_token","refresh_token","token_type","expires_in"],"additionalProperties":false}},"required":["tokens"],"additionalProperties":false}}}},"400":{"description":"The request does not match the expected shape. `details` names the offending fields. Machine-readable `error` value: `invalid_request`.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","const":"invalid_request"},"message":{"type":"string","const":"The request does not match the expected shape."},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["error","message","details"],"additionalProperties":false}}}},"401":{"description":"The access token is missing, does not verify, or names an account that no longer exists. Machine-readable `error` values this response body may carry: `account_not_anonymous`, `apple_signin_unavailable`, `apple_token_invalid`, `rate_limited`, `refresh_token_expired`, `refresh_token_invalid`, `refresh_token_reused`, `resolution_token_expired`, `resolution_token_invalid`, `unauthorized`, `upgrade_conflict_stale`.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["rate_limited","apple_signin_unavailable","apple_token_invalid","refresh_token_invalid","refresh_token_expired","refresh_token_reused","unauthorized","account_not_anonymous","resolution_token_invalid","resolution_token_expired","upgrade_conflict_stale"]},"code":{"type":"string","enum":["rate_limited","apple_signin_unavailable","apple_token_invalid","refresh_token_invalid","refresh_token_expired","refresh_token_reused","unauthorized","account_not_anonymous","resolution_token_invalid","resolution_token_expired","upgrade_conflict_stale"]},"message":{"type":"string"},"retry_after_seconds":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"required":["error","code","message"],"additionalProperties":false}}}},"429":{"description":"Rate limited. Wait `retry_after_seconds` and retry. Machine-readable `error` values this response body may carry: `account_not_anonymous`, `apple_signin_unavailable`, `apple_token_invalid`, `rate_limited`, `refresh_token_expired`, `refresh_token_invalid`, `refresh_token_reused`, `resolution_token_expired`, `resolution_token_invalid`, `unauthorized`, `upgrade_conflict_stale`.","headers":{"retry-after":{"description":"Seconds to wait before retrying. Always equal to `retry_after_seconds`.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["rate_limited","apple_signin_unavailable","apple_token_invalid","refresh_token_invalid","refresh_token_expired","refresh_token_reused","unauthorized","account_not_anonymous","resolution_token_invalid","resolution_token_expired","upgrade_conflict_stale"]},"code":{"type":"string","enum":["rate_limited","apple_signin_unavailable","apple_token_invalid","refresh_token_invalid","refresh_token_expired","refresh_token_reused","unauthorized","account_not_anonymous","resolution_token_invalid","resolution_token_expired","upgrade_conflict_stale"]},"message":{"type":"string"},"retry_after_seconds":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"required":["error","code","message"],"additionalProperties":false}}}}}}},"/v1/auth/upgrade":{"post":{"operationId":"postV1AuthUpgrade","summary":"Upgrade the authenticated anonymous account in place by binding an Apple identity","description":"The account in the Authorization header keeps its id and every row; an apple_identities row is added, all in one transaction. Idempotent: repeating the call with the same Apple identity succeeds again with the same single binding. When the Apple identity already owns ANOTHER account the answer is the typed 409 apple_identity_in_use with a resolution token and per-side counts — nothing is merged or discarded until the person confirms a choice on the resolve endpoint. The consent record is never touched: upgrading is the same person continuing, not a new agreement.","tags":["auth"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"identity_token":{"type":"string","minLength":20,"maxLength":8192},"nonce":{"type":"string","minLength":1,"maxLength":512}},"required":["identity_token"]}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"user":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"is_anonymous":{"type":"boolean"},"created_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"}},"required":["id","is_anonymous","created_at"],"additionalProperties":false},"tokens":{"type":"object","properties":{"access_token":{"type":"string"},"refresh_token":{"type":"string"},"token_type":{"type":"string","const":"Bearer"},"expires_in":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"required":["access_token","refresh_token","token_type","expires_in"],"additionalProperties":false}},"required":["user","tokens"],"additionalProperties":false}}}},"400":{"description":"The request does not match the expected shape. `details` names the offending fields. Machine-readable `error` value: `invalid_request`.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","const":"invalid_request"},"message":{"type":"string","const":"The request does not match the expected shape."},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["error","message","details"],"additionalProperties":false}}}},"401":{"description":"The access token is missing, does not verify, or names an account that no longer exists. Machine-readable `error` values this response body may carry: `account_not_anonymous`, `apple_signin_unavailable`, `apple_token_invalid`, `rate_limited`, `refresh_token_expired`, `refresh_token_invalid`, `refresh_token_reused`, `resolution_token_expired`, `resolution_token_invalid`, `unauthorized`, `upgrade_conflict_stale`.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["rate_limited","apple_signin_unavailable","apple_token_invalid","refresh_token_invalid","refresh_token_expired","refresh_token_reused","unauthorized","account_not_anonymous","resolution_token_invalid","resolution_token_expired","upgrade_conflict_stale"]},"code":{"type":"string","enum":["rate_limited","apple_signin_unavailable","apple_token_invalid","refresh_token_invalid","refresh_token_expired","refresh_token_reused","unauthorized","account_not_anonymous","resolution_token_invalid","resolution_token_expired","upgrade_conflict_stale"]},"message":{"type":"string"},"retry_after_seconds":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"required":["error","code","message"],"additionalProperties":false}}}},"409":{"description":"The request cannot be applied to the current state of the accounts. Machine-readable `error` values this response body may carry: `account_not_anonymous`, `apple_identity_in_use`, `apple_signin_unavailable`, `apple_token_invalid`, `rate_limited`, `refresh_token_expired`, `refresh_token_invalid`, `refresh_token_reused`, `resolution_token_expired`, `resolution_token_invalid`, `unauthorized`, `upgrade_conflict_stale`.","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"error":{"type":"string","const":"apple_identity_in_use"},"code":{"type":"string","const":"apple_identity_in_use"},"message":{"type":"string"},"conflict":{"type":"object","properties":{"resolution_token":{"type":"string"},"expires_in":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"choices":{"type":"array","items":{"type":"string","enum":["keep_apple_account","keep_anonymous_account"]}},"anonymous_account":{"type":"object","properties":{"reel_count":{"type":"integer","minimum":0,"maximum":9007199254740991},"topic_count":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["reel_count","topic_count"],"additionalProperties":false},"apple_account":{"type":"object","properties":{"reel_count":{"type":"integer","minimum":0,"maximum":9007199254740991},"topic_count":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["reel_count","topic_count"],"additionalProperties":false}},"required":["resolution_token","expires_in","choices","anonymous_account","apple_account"],"additionalProperties":false}},"required":["error","code","message","conflict"],"additionalProperties":false},{"type":"object","properties":{"error":{"type":"string","enum":["rate_limited","apple_signin_unavailable","apple_token_invalid","refresh_token_invalid","refresh_token_expired","refresh_token_reused","unauthorized","account_not_anonymous","resolution_token_invalid","resolution_token_expired","upgrade_conflict_stale"]},"code":{"type":"string","enum":["rate_limited","apple_signin_unavailable","apple_token_invalid","refresh_token_invalid","refresh_token_expired","refresh_token_reused","unauthorized","account_not_anonymous","resolution_token_invalid","resolution_token_expired","upgrade_conflict_stale"]},"message":{"type":"string"},"retry_after_seconds":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"required":["error","code","message"],"additionalProperties":false}]}}}},"429":{"description":"Rate limited. Wait `retry_after_seconds` and retry. Machine-readable `error` values this response body may carry: `account_not_anonymous`, `apple_signin_unavailable`, `apple_token_invalid`, `rate_limited`, `refresh_token_expired`, `refresh_token_invalid`, `refresh_token_reused`, `resolution_token_expired`, `resolution_token_invalid`, `unauthorized`, `upgrade_conflict_stale`.","headers":{"retry-after":{"description":"Seconds to wait before retrying. Always equal to `retry_after_seconds`.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["rate_limited","apple_signin_unavailable","apple_token_invalid","refresh_token_invalid","refresh_token_expired","refresh_token_reused","unauthorized","account_not_anonymous","resolution_token_invalid","resolution_token_expired","upgrade_conflict_stale"]},"code":{"type":"string","enum":["rate_limited","apple_signin_unavailable","apple_token_invalid","refresh_token_invalid","refresh_token_expired","refresh_token_reused","unauthorized","account_not_anonymous","resolution_token_invalid","resolution_token_expired","upgrade_conflict_stale"]},"message":{"type":"string"},"retry_after_seconds":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"required":["error","code","message"],"additionalProperties":false}}}},"503":{"description":"A dependency this endpoint needs is unavailable right now. Nothing was written; retry later. Machine-readable `error` values this response body may carry: `account_not_anonymous`, `apple_signin_unavailable`, `apple_token_invalid`, `rate_limited`, `refresh_token_expired`, `refresh_token_invalid`, `refresh_token_reused`, `resolution_token_expired`, `resolution_token_invalid`, `unauthorized`, `upgrade_conflict_stale`.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["rate_limited","apple_signin_unavailable","apple_token_invalid","refresh_token_invalid","refresh_token_expired","refresh_token_reused","unauthorized","account_not_anonymous","resolution_token_invalid","resolution_token_expired","upgrade_conflict_stale"]},"code":{"type":"string","enum":["rate_limited","apple_signin_unavailable","apple_token_invalid","refresh_token_invalid","refresh_token_expired","refresh_token_reused","unauthorized","account_not_anonymous","resolution_token_invalid","resolution_token_expired","upgrade_conflict_stale"]},"message":{"type":"string"},"retry_after_seconds":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"required":["error","code","message"],"additionalProperties":false}}}}}}},"/v1/auth/upgrade/resolve":{"post":{"operationId":"postV1AuthUpgradeResolve","summary":"Apply the confirmed outcome of an upgrade collision, idempotently","description":"Takes the opaque resolution token from the 409 conflict body plus the choice the person confirmed. THIS IS THE MOST DESTRUCTIVE ENDPOINT IN THIS SERVICE: BOTH choices permanently delete the losing account and, by database cascade, its ENTIRE COLLECTION — every topic and every saved reel it holds. keep_apple_account signs into the Apple-bound account and deletes the anonymous account with everything in it; keep_anonymous_account deletes the Apple-bound account with everything in it and binds the Apple identity to the anonymous account in place. The deletion is hard: no tombstone, no backup and no recovery path, and no endpoint undoes it. Present the counts from the 409 body to the person and let them choose; never choose for them. Applying is idempotent on replay of the same token — a replay returns the same sign-in without a second effect. The caller must present the access token of the anonymous account the conflict was issued to.","tags":["auth"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"resolution_token":{"type":"string","minLength":16,"maxLength":2048},"choice":{"type":"string","enum":["keep_apple_account","keep_anonymous_account"],"description":"The outcome the person explicitly confirmed. Each value permanently deletes one of the two accounts and, by cascade, its entire collection — every topic and every saved reel. keep_apple_account: keep the Apple-bound account and its collection, and permanently delete the anonymous account with everything in it. keep_anonymous_account: keep the anonymous account and its collection, bind the Apple identity to it, and permanently delete the Apple-bound account with everything in it. There is no tombstone and no recovery either way."}},"required":["resolution_token","choice"]}}}},"responses":{"200":{"description":"Success. The choice has been applied and the losing account is permanently gone. THE RETURNED `user.id` IS AUTHORITATIVE AND MAY DIFFER FROM THE CALLER'S: keep_apple_account signs you into the Apple-bound account, which has a different id and a different collection, while keep_anonymous_account returns the id you already had. The two outcomes are indistinguishable by shape, so compare the id. A client MUST discard its local sync cursor and its local library, adopt the returned tokens and user.id, and re-read the surviving collection with a full pull (GET /v1/sync with no `since`) before pushing anything. Pushing a retained local library after this call re-creates the abandoned collection inside the account the person chose to keep, silently undoing the choice they just confirmed.","content":{"application/json":{"schema":{"type":"object","properties":{"user":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"is_anonymous":{"type":"boolean"},"created_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"}},"required":["id","is_anonymous","created_at"],"additionalProperties":false},"tokens":{"type":"object","properties":{"access_token":{"type":"string"},"refresh_token":{"type":"string"},"token_type":{"type":"string","const":"Bearer"},"expires_in":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"required":["access_token","refresh_token","token_type","expires_in"],"additionalProperties":false}},"required":["user","tokens"],"additionalProperties":false}}}},"400":{"description":"The request does not match the expected shape. `details` names the offending fields. Machine-readable `error` value: `invalid_request`.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","const":"invalid_request"},"message":{"type":"string","const":"The request does not match the expected shape."},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["error","message","details"],"additionalProperties":false}}}},"401":{"description":"The access token is missing, does not verify, or names an account that no longer exists. Machine-readable `error` values this response body may carry: `account_not_anonymous`, `apple_signin_unavailable`, `apple_token_invalid`, `rate_limited`, `refresh_token_expired`, `refresh_token_invalid`, `refresh_token_reused`, `resolution_token_expired`, `resolution_token_invalid`, `unauthorized`, `upgrade_conflict_stale`.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["rate_limited","apple_signin_unavailable","apple_token_invalid","refresh_token_invalid","refresh_token_expired","refresh_token_reused","unauthorized","account_not_anonymous","resolution_token_invalid","resolution_token_expired","upgrade_conflict_stale"]},"code":{"type":"string","enum":["rate_limited","apple_signin_unavailable","apple_token_invalid","refresh_token_invalid","refresh_token_expired","refresh_token_reused","unauthorized","account_not_anonymous","resolution_token_invalid","resolution_token_expired","upgrade_conflict_stale"]},"message":{"type":"string"},"retry_after_seconds":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"required":["error","code","message"],"additionalProperties":false}}}},"409":{"description":"The request cannot be applied to the current state of the accounts. Machine-readable `error` values this response body may carry: `account_not_anonymous`, `apple_signin_unavailable`, `apple_token_invalid`, `rate_limited`, `refresh_token_expired`, `refresh_token_invalid`, `refresh_token_reused`, `resolution_token_expired`, `resolution_token_invalid`, `unauthorized`, `upgrade_conflict_stale`.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["rate_limited","apple_signin_unavailable","apple_token_invalid","refresh_token_invalid","refresh_token_expired","refresh_token_reused","unauthorized","account_not_anonymous","resolution_token_invalid","resolution_token_expired","upgrade_conflict_stale"]},"code":{"type":"string","enum":["rate_limited","apple_signin_unavailable","apple_token_invalid","refresh_token_invalid","refresh_token_expired","refresh_token_reused","unauthorized","account_not_anonymous","resolution_token_invalid","resolution_token_expired","upgrade_conflict_stale"]},"message":{"type":"string"},"retry_after_seconds":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"required":["error","code","message"],"additionalProperties":false}}}},"429":{"description":"Rate limited. Wait `retry_after_seconds` and retry. Machine-readable `error` values this response body may carry: `account_not_anonymous`, `apple_signin_unavailable`, `apple_token_invalid`, `rate_limited`, `refresh_token_expired`, `refresh_token_invalid`, `refresh_token_reused`, `resolution_token_expired`, `resolution_token_invalid`, `unauthorized`, `upgrade_conflict_stale`.","headers":{"retry-after":{"description":"Seconds to wait before retrying. Always equal to `retry_after_seconds`.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["rate_limited","apple_signin_unavailable","apple_token_invalid","refresh_token_invalid","refresh_token_expired","refresh_token_reused","unauthorized","account_not_anonymous","resolution_token_invalid","resolution_token_expired","upgrade_conflict_stale"]},"code":{"type":"string","enum":["rate_limited","apple_signin_unavailable","apple_token_invalid","refresh_token_invalid","refresh_token_expired","refresh_token_reused","unauthorized","account_not_anonymous","resolution_token_invalid","resolution_token_expired","upgrade_conflict_stale"]},"message":{"type":"string"},"retry_after_seconds":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"required":["error","code","message"],"additionalProperties":false}}}}}}},"/v1/discover/hidden":{"post":{"operationId":"postV1DiscoverHidden","summary":"Hide a discover entry from this account, permanently","description":"Idempotent: hiding the same url_hash twice stores one row and answers 200 both times. The entry is excluded from this account's GET /v1/discover/top from then on, and from nobody else's — a hide is a private preference, never a signal about the URL. Undo it with POST /v1/discover/unhidden.","tags":["discover"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url_hash":{"type":"string","pattern":"^[0-9a-fA-F]{64}$"}},"required":["url_hash"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"url_hash":{"type":"string","minLength":64,"maxLength":64},"hidden":{"type":"boolean"}},"required":["url_hash","hidden"],"additionalProperties":false}}}},"400":{"description":"The request does not match the expected shape. `details` names the offending fields. Machine-readable `error` value: `invalid_request`.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","const":"invalid_request"},"message":{"type":"string","const":"The request does not match the expected shape."},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["error","message","details"],"additionalProperties":false}}}},"401":{"description":"The access token is missing, does not verify, or names an account that no longer exists. Machine-readable `error` value: `unauthorized`.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","const":"unauthorized"},"message":{"type":"string"}},"required":["error","message"],"additionalProperties":false}}}},"429":{"description":"Rate limited. Wait `retry_after_seconds` and retry. Machine-readable `error` value: `rate_limited`.","headers":{"retry-after":{"description":"Seconds to wait before retrying. Always equal to `retry_after_seconds`.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","const":"rate_limited"},"message":{"type":"string"},"retry_after_seconds":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["error","message","retry_after_seconds"],"additionalProperties":false}}}}}}},"/v1/discover/report":{"post":{"operationId":"postV1DiscoverReport","summary":"Report a discover entry","description":"Stores the url_hash, an optional free-text reason and a timestamp, and nothing else — no reporter identity is recorded. There is no moderation queue and no admin endpoint here; acting on a report is a human setting reel_stats.is_removed out of band. Accepted for a url_hash the aggregate has never seen. Rate limited.","tags":["discover"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url_hash":{"type":"string","pattern":"^[0-9a-fA-F]{64}$"},"reason":{"anyOf":[{"type":"string","minLength":1,"maxLength":2000},{"type":"null"}]}},"required":["url_hash"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"url_hash":{"type":"string","minLength":64,"maxLength":64},"reported":{"type":"boolean","const":true}},"required":["url_hash","reported"],"additionalProperties":false}}}},"400":{"description":"The request does not match the expected shape. `details` names the offending fields. Machine-readable `error` value: `invalid_request`.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","const":"invalid_request"},"message":{"type":"string","const":"The request does not match the expected shape."},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["error","message","details"],"additionalProperties":false}}}},"401":{"description":"The access token is missing, does not verify, or names an account that no longer exists. Machine-readable `error` value: `unauthorized`.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","const":"unauthorized"},"message":{"type":"string"}},"required":["error","message"],"additionalProperties":false}}}},"429":{"description":"Rate limited. Wait `retry_after_seconds` and retry. Machine-readable `error` value: `rate_limited`.","headers":{"retry-after":{"description":"Seconds to wait before retrying. Always equal to `retry_after_seconds`.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","const":"rate_limited"},"message":{"type":"string"},"retry_after_seconds":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["error","message","retry_after_seconds"],"additionalProperties":false}}}}}}},"/v1/discover/top":{"get":{"operationId":"getV1DiscoverTop","summary":"The most-saved public URLs, as an anonymous aggregate","description":"Rows appear only once at least five distinct accounts hold the URL. No user identifier, note or per-user field is ever returned. Authentication is optional: send a Bearer token and the caller's own hidden entries are excluded; send none and the aggregate is returned whole. Rows flagged is_removed are excluded for everyone.","tags":["discover"],"security":[{},{"bearerAuth":[]}],"parameters":[{"name":"window","in":"query","required":false,"schema":{"default":"all","type":"string","enum":["7d","30d","all"]}},{"name":"limit","in":"query","required":false,"schema":{"default":20,"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"window":{"type":"string","enum":["7d","30d","all"]},"limit":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"entries":{"type":"array","items":{"type":"object","properties":{"url_hash":{"type":"string","minLength":64,"maxLength":64,"description":"sha256 of the canonical URL, lower-case hex. The stable handle for this entry: pass it back to the hide, un-hide and report endpoints. Clients take it from here and never compute one."},"canonical_url":{"type":"string","description":"The public URL, normalised. Nothing else is published about it."},"title":{"description":"The page title, when one could be retrieved. NULL is a normal value and not an error — render the URL alone. There is no thumbnail, preview image, author, like count or comment count for an entry, by design.","type":["string","null"]},"save_count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How many DISTINCT ACCOUNTS hold this URL — unique users, not save events. One account saving the same URL repeatedly contributes exactly 1."},"favourite_count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How many DISTINCT ACCOUNTS marked this URL a favourite. Unique users, not events."},"first_seen_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$","description":"When the aggregate first counted this URL."},"last_seen_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$","description":"When the aggregate last counted this URL."}},"required":["url_hash","canonical_url","title","save_count","favourite_count","first_seen_at","last_seen_at"],"additionalProperties":false}}},"required":["window","limit","entries"],"additionalProperties":false}}}},"400":{"description":"The request does not match the expected shape. `details` names the offending fields. Machine-readable `error` value: `invalid_request`.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","const":"invalid_request"},"message":{"type":"string","const":"The request does not match the expected shape."},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["error","message","details"],"additionalProperties":false}}}},"401":{"description":"The access token is missing, does not verify, or names an account that no longer exists. Machine-readable `error` value: `unauthorized`.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","const":"unauthorized"},"message":{"type":"string"}},"required":["error","message"],"additionalProperties":false}}}}}}},"/v1/discover/unhidden":{"post":{"operationId":"postV1DiscoverUnhidden","summary":"Un-hide a discover entry for this account","description":"Idempotent: un-hiding something that was never hidden is a 200, not a 404. A list a user cannot get out of is a trap, and the row is theirs. The url_hash travels in the body, not the path, so it never reaches an access log line.","tags":["discover"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url_hash":{"type":"string","pattern":"^[0-9a-fA-F]{64}$"}},"required":["url_hash"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"url_hash":{"type":"string","minLength":64,"maxLength":64},"hidden":{"type":"boolean"}},"required":["url_hash","hidden"],"additionalProperties":false}}}},"400":{"description":"The request does not match the expected shape. `details` names the offending fields. Machine-readable `error` value: `invalid_request`.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","const":"invalid_request"},"message":{"type":"string","const":"The request does not match the expected shape."},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["error","message","details"],"additionalProperties":false}}}},"401":{"description":"The access token is missing, does not verify, or names an account that no longer exists. Machine-readable `error` value: `unauthorized`.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","const":"unauthorized"},"message":{"type":"string"}},"required":["error","message"],"additionalProperties":false}}}},"429":{"description":"Rate limited. Wait `retry_after_seconds` and retry. Machine-readable `error` value: `rate_limited`.","headers":{"retry-after":{"description":"Seconds to wait before retrying. Always equal to `retry_after_seconds`.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","const":"rate_limited"},"message":{"type":"string"},"retry_after_seconds":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["error","message","retry_after_seconds"],"additionalProperties":false}}}}}}},"/v1/health":{"get":{"operationId":"getV1Health","summary":"Liveness and database connectivity","tags":["health"],"security":[],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["ok","degraded"]},"version":{"type":"string"},"database":{"type":"string","enum":["up","down"]}},"required":["status","version","database"],"additionalProperties":false}}}},"503":{"description":"A dependency this endpoint needs is unavailable right now. Nothing was written; retry later.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["ok","degraded"]},"version":{"type":"string"},"database":{"type":"string","enum":["up","down"]}},"required":["status","version","database"],"additionalProperties":false}}}}}}},"/v1/sync":{"get":{"operationId":"getV1Sync","summary":"Pull changes with seq > since, tombstones included","tags":["sync"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"since","in":"query","required":false,"schema":{"default":0,"type":"integer","minimum":0,"maximum":9007199254740991}},{"name":"limit","in":"query","required":false,"schema":{"default":500,"type":"integer","minimum":1,"maximum":500}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"reels":{"type":"array","items":{"oneOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"deleted":{"type":"boolean","const":false},"url":{"type":"string"},"platform":{"type":"string","description":"An OPEN string, exactly as it was pushed. Never a closed set."},"topic_id":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"topic_is_confirmed":{"type":"boolean"},"is_favourite":{"type":"boolean"},"note":{"type":["string","null"]},"saved_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"open_count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"last_opened_at":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},{"type":"null"}]},"reminder_date":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},{"type":"null"}]},"updated_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"seq":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","deleted","url","platform","topic_id","topic_is_confirmed","is_favourite","note","saved_at","open_count","last_opened_at","reminder_date","updated_at","seq"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"deleted":{"type":"boolean","const":true},"updated_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"seq":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","deleted","updated_at","seq"],"additionalProperties":false}]}},"topics":{"type":"array","items":{"oneOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"deleted":{"type":"boolean","const":false},"name":{"type":"string"},"is_visible":{"type":"boolean"},"colour_index":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"created_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"updated_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"seq":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","deleted","name","is_visible","colour_index","created_at","updated_at","seq"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"deleted":{"type":"boolean","const":true},"updated_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"seq":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","deleted","updated_at","seq"],"additionalProperties":false}]}},"cursor":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"The seq of the last row in THIS page, or `since` unchanged when the page is empty. Persist it only after applying the page, and pass it as `since` on the next pull. Never advance it from a push response."},"has_more":{"type":"boolean","description":"Repeat the pull with `since=cursor` while this is true."}},"required":["reels","topics","cursor","has_more"],"additionalProperties":false}}}},"400":{"description":"The request does not match the expected shape. `details` names the offending fields. Machine-readable `error` value: `invalid_request`.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","const":"invalid_request"},"message":{"type":"string","const":"The request does not match the expected shape."},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["error","message","details"],"additionalProperties":false}}}},"401":{"description":"The access token is missing, does not verify, or names an account that no longer exists. Machine-readable `error` value: `unauthorized`.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","const":"unauthorized"},"message":{"type":"string"}},"required":["error","message"],"additionalProperties":false}}}}}},"post":{"operationId":"postV1Sync","summary":"Push a batch of client changes; per-record last-write-wins verdicts","tags":["sync"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reels":{"maxItems":500,"type":"array","items":{"oneOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"deleted":{"type":"boolean","const":false},"url":{"type":"string","minLength":1,"maxLength":4096},"platform":{"default":"other","description":"An OPEN string, not a closed set: send whatever the source is and it is stored as sent. Defaults to 'other'. Do not generate a closed type from this field — a new platform must not require a client release.","type":"string","minLength":1,"maxLength":64},"topic_id":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"topic_is_confirmed":{"type":"boolean"},"is_favourite":{"type":"boolean"},"note":{"anyOf":[{"type":"string","maxLength":20000},{"type":"null"}]},"saved_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"open_count":{"type":"integer","minimum":0,"maximum":1000000000},"last_opened_at":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},{"type":"null"}]},"reminder_date":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},{"type":"null"}]},"updated_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"}},"required":["id","deleted","url","topic_id","topic_is_confirmed","is_favourite","note","saved_at","open_count","last_opened_at","reminder_date","updated_at"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"deleted":{"type":"boolean","const":true},"updated_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"}},"required":["id","deleted","updated_at"],"additionalProperties":false}]}},"topics":{"maxItems":500,"type":"array","items":{"oneOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"deleted":{"type":"boolean","const":false},"name":{"type":"string","maxLength":200},"is_visible":{"type":"boolean"},"colour_index":{"type":"integer","minimum":0,"maximum":1000},"created_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"updated_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"}},"required":["id","deleted","name","is_visible","colour_index","created_at","updated_at"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"deleted":{"type":"boolean","const":true},"updated_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"}},"required":["id","deleted","updated_at"],"additionalProperties":false}]}}},"additionalProperties":false}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"reels":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The id of the pushed record this verdict is about."},"result":{"type":"string","enum":["accepted","superseded","rejected"],"description":"accepted: the pushed version won, or was already applied. superseded: a later server write won — replace the local version with `row`. rejected: nothing was written; see `reason`."},"reason":{"description":"Present only on `rejected`. unknown_topic: the reel points at a topic that exists neither on the server nor in this batch — push the topic first, then this reel again.","type":"string","enum":["unknown_topic"]},"row":{"anyOf":[{"oneOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"deleted":{"type":"boolean","const":false},"url":{"type":"string"},"platform":{"type":"string","description":"An OPEN string, exactly as it was pushed. Never a closed set."},"topic_id":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},{"type":"null"}]},"topic_is_confirmed":{"type":"boolean"},"is_favourite":{"type":"boolean"},"note":{"type":["string","null"]},"saved_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"open_count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"last_opened_at":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},{"type":"null"}]},"reminder_date":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},{"type":"null"}]},"updated_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"seq":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","deleted","url","platform","topic_id","topic_is_confirmed","is_favourite","note","saved_at","open_count","last_opened_at","reminder_date","updated_at","seq"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"deleted":{"type":"boolean","const":true},"updated_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"seq":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","deleted","updated_at","seq"],"additionalProperties":false}]},{"type":"null"}],"description":"The current winning server row, or null when none exists (a rejected record)."}},"required":["id","result","row"],"additionalProperties":false}},"topics":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The id of the pushed record this verdict is about."},"result":{"type":"string","enum":["accepted","superseded","rejected"],"description":"accepted: the pushed version won, or was already applied. superseded: a later server write won — replace the local version with `row`. rejected: nothing was written."},"row":{"anyOf":[{"oneOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"deleted":{"type":"boolean","const":false},"name":{"type":"string"},"is_visible":{"type":"boolean"},"colour_index":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"created_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"updated_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"seq":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","deleted","name","is_visible","colour_index","created_at","updated_at","seq"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"deleted":{"type":"boolean","const":true},"updated_at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"seq":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","deleted","updated_at","seq"],"additionalProperties":false}]},{"type":"null"}],"description":"The current winning server row, or null when none exists."}},"required":["id","result","row"],"additionalProperties":false}}},"required":["reels","topics"],"additionalProperties":false}}}},"400":{"description":"The request does not match the expected shape. `details` names the offending fields. Machine-readable `error` value: `invalid_request`.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","const":"invalid_request"},"message":{"type":"string","const":"The request does not match the expected shape."},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["error","message","details"],"additionalProperties":false}}}},"401":{"description":"The access token is missing, does not verify, or names an account that no longer exists. Machine-readable `error` value: `unauthorized`.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","const":"unauthorized"},"message":{"type":"string"}},"required":["error","message"],"additionalProperties":false}}}},"429":{"description":"Rate limited. Wait `retry_after_seconds` and retry. Machine-readable `error` value: `rate_limited`.","headers":{"retry-after":{"description":"Seconds to wait before retrying. Always equal to `retry_after_seconds`.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","const":"rate_limited"},"message":{"type":"string"},"retry_after_seconds":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["error","message","retry_after_seconds"],"additionalProperties":false}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"The `access_token` from any /v1/auth response, as `Authorization: Bearer <token>`. It expires in `expires_in` seconds; rotate it with POST /v1/auth/refresh."}}}}