{"openapi":"3.1.0","info":{"title":"pixPLace API","version":"1.0.0","summary":"Public API v1 of pixPLace.","description":"REST API of pixPLace (https://pixplace.space) for publishing posts, stories and uploads, reading comments, statistics, followers and notifications on behalf of ONE account. Authenticate with `Authorization: Bearer ppk_live_…` (create a key in Settings → Developer). JSON in, JSON out. Send `Idempotency-Key` on create calls so retries are safe; on 429 and 503 wait `Retry-After` seconds. Everything the platform does not collect or support is listed under `x-unavailable` instead of being faked. Human guide: https://pixplace.space/developers.","contact":{"name":"pixPLace developers","url":"https://pixplace.space/developers"},"x-unavailable":["multiAccountKey","hideComment","editComment","changePostMedia","followActions","views","saves","deeplinkClicks","profileViews","dailyShares","mcpTools"]},"servers":[{"url":"https://pixplace.space","description":"Production"}],"externalDocs":{"description":"Developer guide: quick start, recipes, errors and limits","url":"https://pixplace.space/developers"},"security":[{"bearerAuth":[]}],"tags":[{"name":"Posts","description":"Publish, read, edit, delete and get statistics of your own posts."},{"name":"Uploads","description":"Put image and video files on the portal's storage; the result URL goes into posts and stories."},{"name":"Stories","description":"Stories live for 24 hours."},{"name":"Comments","description":"Read and write comments under your own posts; the inbox; moderation by deleting."},{"name":"Account","description":"Your own profile, growth statistics, followers and notifications."},{"name":"Taxonomy","description":"Public lists: categories and niches (no key needed)."}],"paths":{"/api/v1/posts":{"post":{"operationId":"createPost","tags":["Posts"],"summary":"Publish a post (image, video or carousel).","description":"Creates a post for the owner of the key. Media must already be on an allowed host: upload a file first with POST /api/v1/uploads/from-url (or /api/v1/uploads) and use the returned `publicUrl`. Send `Idempotency-Key` so a retry after a timeout or a 503 cannot create a duplicate. Limits: 5 posts per minute per account and 50 per day per key (resets at 00:00 UTC); a replay is free. The daily 429 body also carries `dailyUsage`.","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"description":"The post. Only `title` and one media item are required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostCreateRequest"},"examples":{"image":{"summary":"Image","description":"A single image post with size, alt text, category, tags and SEO keywords.","value":{"title":"Minimalist living room","attachments":[{"url":"https://cdn.pixplace.space/autopost/living-room.png","type":"IMAGE","width":1536,"height":1024,"altText":"Bright minimalist living room with an oak table"}],"description":"AI-generated interior concept","prompt":"minimalist living room, oak table, soft daylight, 35mm","categories":["architecture-interior-design"],"tags":["interior","minimal","ai"],"seoKeywords":["minimalist interior","ai interior design"]}},"video":{"summary":"Video","description":"A video post. thumbnailUrl is the poster frame (an image on an allowed image host).","value":{"title":"Neon city flythrough","attachments":[{"url":"https://cdn.pixplace.space/autopost/neon-city.mp4","type":"VIDEO","width":1080,"height":1920,"thumbnailUrl":"https://cdn.pixplace.space/autopost/neon-city.jpg","altText":"Camera flying through a neon-lit street at night"}],"description":"Vertical 9:16 clip","tags":["cyberpunk","video"]}},"carousel":{"summary":"Carousel","description":"Up to 10 slides, shown in array order (order 0..n-1). Images and videos can be mixed.","value":{"title":"Five ways to light a studio","attachments":[{"url":"https://cdn.pixplace.space/autopost/studio-1.png","type":"IMAGE","width":1080,"height":1350,"altText":"Softbox key light"},{"url":"https://cdn.pixplace.space/autopost/studio-2.png","type":"IMAGE","width":1080,"height":1350,"altText":"Rim light from behind"},{"url":"https://cdn.pixplace.space/autopost/studio-3.png","type":"IMAGE","width":1080,"height":1350,"altText":"Window light","prompt":"studio portrait, window light"},{"url":"https://cdn.pixplace.space/autopost/studio-demo.mp4","type":"VIDEO","width":1080,"height":1350,"thumbnailUrl":"https://cdn.pixplace.space/autopost/studio-demo.jpg","altText":"Light setup walkthrough"}],"description":"Swipe through the setups","categories":["architecture-interior-design"],"tags":["lighting","photography"]}},"links":{"summary":"Post with links","description":"Up to 5 deeplink buttons: https only, label up to 60 chars, iconType from a fixed list (default \"link\").","value":{"title":"Desk setup for creators","attachments":[{"url":"https://cdn.pixplace.space/autopost/desk.png","type":"IMAGE","width":1600,"height":900,"altText":"Wooden desk with a monitor and a lamp"}],"description":"Everything on the desk, with links","deeplinks":[{"url":"https://example.com/shop/desk","label":"Buy the desk","iconType":"shop"},{"url":"https://t.me/pixplace","label":"Discuss in Telegram","iconType":"telegram"},{"url":"https://example.com/guide","label":"Read the guide"}],"tags":["desk","setup"]}}}}}},"responses":{"200":{"description":"Replay: the same Idempotency-Key was already used; the ORIGINAL post is returned.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostCreated"},"example":{"success":true,"data":{"id":"0b6f0c1e-6f0a-4c8e-9a53-0d7a0f3c2b11","slug":"five-ways-to-light-a-studio-9f2c4a7e1b3d5a68","url":"https://pixplace.space/post/five-ways-to-light-a-studio-9f2c4a7e1b3d5a68","title":"Five ways to light a studio","description":"Swipe through the setups","isPublished":true,"createdAt":"2026-10-21T10:15:30.000Z","attachments":[{"id":"5d1c0f8e-2a64-4b8f-8f7e-1c2d3e4f5a6b","url":"https://cdn.pixplace.space/autopost/studio-1.png","type":"IMAGE","width":1080,"height":1350,"altText":"Softbox key light","thumbnailUrl":null,"order":0}],"deeplinks":[{"id":"7e8f9a0b-1c2d-4e3f-8a4b-5c6d7e8f9a0b","url":"https://example.com/shop/desk","label":"Buy the desk","iconType":"shop"}],"categories":["architecture-interior-design"],"tags":["lighting","photography"],"seoKeywords":["studio lighting"]},"post":{"id":"0b6f0c1e-6f0a-4c8e-9a53-0d7a0f3c2b11","slug":"five-ways-to-light-a-studio-9f2c4a7e1b3d5a68","title":"Five ways to light a studio","url":"https://pixplace.space/post/five-ways-to-light-a-studio-9f2c4a7e1b3d5a68","createdAt":"2026-10-21T10:15:30.000Z"},"usage":{"daily":1,"dailyUsage":1,"dailyLimit":50,"minuteLimit":5}}}},"headers":{"Idempotent-Replayed":{"$ref":"#/components/headers/IdempotentReplayed"}}},"201":{"description":"Created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostCreated"},"example":{"success":true,"data":{"id":"0b6f0c1e-6f0a-4c8e-9a53-0d7a0f3c2b11","slug":"five-ways-to-light-a-studio-9f2c4a7e1b3d5a68","url":"https://pixplace.space/post/five-ways-to-light-a-studio-9f2c4a7e1b3d5a68","title":"Five ways to light a studio","description":"Swipe through the setups","isPublished":true,"createdAt":"2026-10-21T10:15:30.000Z","attachments":[{"id":"5d1c0f8e-2a64-4b8f-8f7e-1c2d3e4f5a6b","url":"https://cdn.pixplace.space/autopost/studio-1.png","type":"IMAGE","width":1080,"height":1350,"altText":"Softbox key light","thumbnailUrl":null,"order":0}],"deeplinks":[{"id":"7e8f9a0b-1c2d-4e3f-8a4b-5c6d7e8f9a0b","url":"https://example.com/shop/desk","label":"Buy the desk","iconType":"shop"}],"categories":["architecture-interior-design"],"tags":["lighting","photography"],"seoKeywords":["studio lighting"]},"post":{"id":"0b6f0c1e-6f0a-4c8e-9a53-0d7a0f3c2b11","slug":"five-ways-to-light-a-studio-9f2c4a7e1b3d5a68","title":"Five ways to light a studio","url":"https://pixplace.space/post/five-ways-to-light-a-studio-9f2c4a7e1b3d5a68","createdAt":"2026-10-21T10:15:30.000Z"},"usage":{"daily":1,"dailyUsage":1,"dailyLimit":50,"minuteLimit":5}}}}},"400":{"description":"Validation error; the message names the field, or lists the unknown category slugs (`unknownCategories`). Nothing was written and no quota was spent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"title is required (min 3 chars)"}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid or missing API key","docs":"https://pixplace.space/settings#developer"}}}},"429":{"description":"Per-minute or per-day limit. Read `Retry-After`.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"},"example":{"error":"Rate limit of 5 posts per minute per account reached. Retry in 12s.","retryAfter":12,"minuteLimit":5}}}},"500":{"description":"Unexpected error. No details are exposed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Internal error"}}}},"503":{"description":"A dependency (database or storage) is momentarily unavailable. `Retry-After: 5`. Retry with the SAME Idempotency-Key.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Service temporarily unavailable. Please retry shortly."}}}}},"x-limits":{"perMinute":5,"perDay":50}},"get":{"operationId":"listPosts","tags":["Posts"],"summary":"List your own posts, newest first.","description":"Page-numbered list of the posts of the key owner (drafts included, posts hidden by moderation not). `limit` is capped at 50. Only the first media item of each post is returned; use GET /api/v1/posts/{id} for the full post.","security":[{"bearerAuth":[]}],"parameters":[{"name":"page","in":"query","required":false,"description":"Page number, from 1.","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","required":false,"description":"Page size, at most 50.","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}}],"responses":{"200":{"description":"A page of posts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostListResponse"},"example":{"posts":[{"id":"0b6f0c1e-6f0a-4c8e-9a53-0d7a0f3c2b11","title":"Five ways to light a studio","slug":"five-ways-to-light-a-studio-9f2c4a7e1b3d5a68","url":"https://pixplace.space/post/five-ways-to-light-a-studio-9f2c4a7e1b3d5a68","description":"Swipe through the setups","likes":42,"shares":5,"createdAt":"2026-10-21T10:15:30.000Z","isPublished":true,"attachments":[{"url":"https://cdn.pixplace.space/autopost/studio-1.png","type":"IMAGE"}],"categories":[{"name":"Architecture & Interior Design","slug":"architecture-interior-design"}]}],"page":1,"limit":20}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid or missing API key","docs":"https://pixplace.space/settings#developer"}}}}}}},"/api/v1/posts/{id}":{"get":{"operationId":"getPost","tags":["Posts"],"summary":"Read one of your own posts by id or slug.","description":"Returns the post as stored, with media, deeplinks, categories, tags and counters. `isPublished: false` is a draft: unlisted, not private. Someone else's post, a missing post and a post hidden by moderation are all 404.","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/PostRef"}],"responses":{"200":{"description":"The post.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostDetailResponse"},"example":{"success":true,"data":{"id":"3f1c2a9e-5b7d-4c11-9a7e-0b1c2d3e4f5a","slug":"neon-city-at-night-8f3a2c1d9e4b7a60","url":"https://pixplace.space/post/neon-city-at-night-8f3a2c1d9e4b7a60","title":"Neon city at night — v2","description":"Updated description with the final prompt settings.","prompt":"neon city, rain, cinematic, 35mm","isPublished":true,"categories":["ai-art","architecture"],"tags":["city","cyberpunk","neon"],"seoKeywords":["neon city","ai art"],"attachments":[{"id":"a1b2c3d4-0001-4000-8000-000000000001","url":"https://cdn.pixplace.space/content/cm9x2k4ab0001ld0h5q7w3e2z/2026-10/7b1d9c52.jpg","type":"IMAGE","width":1536,"height":1024,"altText":"Neon-lit street in the rain","thumbnailUrl":null,"order":0}],"deeplinks":[{"id":"d1e2f3a4-0001-4000-8000-000000000002","url":"https://example.com/prints/neon-city","label":"Buy a print","iconType":"shop"}],"counters":{"likes":42,"shares":5,"comments":3},"createdAt":"2026-10-20T09:00:00.000Z","updatedAt":"2026-10-24T08:30:12.000Z"}}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid or missing API key","docs":"https://pixplace.space/settings#developer"}}}},"404":{"description":"The post does not exist, is not yours or is hidden. Never 403: the API does not reveal which ids exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Post not found"}}}},"500":{"description":"Unexpected error. No details are exposed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Internal error"}}}},"503":{"description":"A dependency (database or storage) is momentarily unavailable. `Retry-After: 5`. Safe to retry.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Service temporarily unavailable. Please retry shortly."}}}}}},"patch":{"operationId":"updatePost","tags":["Posts"],"summary":"Change fields of one of your own posts. Send only what changes.","description":"A field you send REPLACES the stored value as a whole: for categories, tags, seoKeywords and deeplinks send the complete new list (`[]` empties it). Fields you do not send stay. `draft: true` unlists the post, `draft: false` publishes it. Media cannot be changed (`attachments` is a 400): delete the post and create a new one. The slug never changes. Repeating the same PATCH gives the same result. Validation and limits are the same as in POST /api/v1/posts.","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/PostRef"}],"requestBody":{"required":true,"description":"The fields to change.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostPatchRequest"},"examples":{"edit":{"summary":"Edit text, tags and links","description":"Rewrites the text, replaces the tag set and the deeplinks and publishes the post. Fields not listed (prompt, seoKeywords, categories) stay as they were.","value":{"title":"Neon city at night — v2","description":"Updated description with the final prompt settings.","tags":["neon","cyberpunk","city"],"deeplinks":[{"url":"https://example.com/prints/neon-city","label":"Buy a print","iconType":"shop"}],"draft":false}},"unlist":{"summary":"Unlist (back to draft)","description":"Hides the post from feeds, the sitemap and listings without deleting it. Send `{ \"draft\": false }` to publish it again.","value":{"draft":true}}}}}},"responses":{"200":{"description":"The updated post (same format as GET).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostDetailResponse"},"example":{"success":true,"data":{"id":"3f1c2a9e-5b7d-4c11-9a7e-0b1c2d3e4f5a","slug":"neon-city-at-night-8f3a2c1d9e4b7a60","url":"https://pixplace.space/post/neon-city-at-night-8f3a2c1d9e4b7a60","title":"Neon city at night — v2","description":"Updated description with the final prompt settings.","prompt":"neon city, rain, cinematic, 35mm","isPublished":true,"categories":["ai-art","architecture"],"tags":["city","cyberpunk","neon"],"seoKeywords":["neon city","ai art"],"attachments":[{"id":"a1b2c3d4-0001-4000-8000-000000000001","url":"https://cdn.pixplace.space/content/cm9x2k4ab0001ld0h5q7w3e2z/2026-10/7b1d9c52.jpg","type":"IMAGE","width":1536,"height":1024,"altText":"Neon-lit street in the rain","thumbnailUrl":null,"order":0}],"deeplinks":[{"id":"d1e2f3a4-0001-4000-8000-000000000002","url":"https://example.com/prints/neon-city","label":"Buy a print","iconType":"shop"}],"counters":{"likes":42,"shares":5,"comments":3},"createdAt":"2026-10-20T09:00:00.000Z","updatedAt":"2026-10-24T08:30:12.000Z"}}}}},"400":{"description":"Validation error, an empty body, `attachments`, or unknown category slugs. Nothing was written and no quota was spent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Unknown categories: ai-artt. See GET /api/v1/categories for valid slugs."}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid or missing API key","docs":"https://pixplace.space/settings#developer"}}}},"404":{"description":"The post does not exist, is not yours or is hidden. Never 403: the API does not reveal which ids exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Post not found"}}}},"429":{"description":"Write limit. Read `Retry-After`.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"},"example":{"error":"Rate limit of 30 write requests per minute per account reached. Retry in 12s.","scope":"minute","retryAfter":12,"minuteLimit":30,"dailyLimit":300}}}},"500":{"description":"Unexpected error. No details are exposed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Internal error"}}}},"503":{"description":"A dependency (database or storage) is momentarily unavailable. `Retry-After: 5`. Safe to retry.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Service temporarily unavailable. Please retry shortly."}}}}},"x-limits":{"perMinute":30,"perDay":300}},"delete":{"operationId":"deletePost","tags":["Posts"],"summary":"Delete one of your own posts.","description":"Removes the post with its attachments, deeplinks, likes and comments (replies included). Reposts stay and lose the link to the original. Only the database is touched: media files in storage are NOT deleted. Deleting again is a 404 — in an automation treat 404 as \"already gone\".","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/PostRef"}],"responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResult"},"example":{"success":true,"deleted":"3f1c2a9e-5b7d-4c11-9a7e-0b1c2d3e4f5a"}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid or missing API key","docs":"https://pixplace.space/settings#developer"}}}},"404":{"description":"The post does not exist, is not yours or is already deleted. Never 403: the API does not reveal which ids exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Post not found"}}}},"429":{"description":"Write limit. Read `Retry-After`.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"},"example":{"error":"Rate limit of 30 write requests per minute per account reached. Retry in 12s.","scope":"minute","retryAfter":12,"minuteLimit":30,"dailyLimit":300}}}},"500":{"description":"Unexpected error. No details are exposed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Internal error"}}}},"503":{"description":"A dependency (database or storage) is momentarily unavailable. `Retry-After: 5`. Safe to retry (a repeat may answer 404).","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Service temporarily unavailable. Please retry shortly."}}}}},"x-limits":{"perMinute":30,"perDay":300}}},"/api/v1/posts/{id}/stats":{"get":{"operationId":"getPostStats","tags":["Posts"],"summary":"Likes and comments of one of your own posts per UTC day.","description":"`series` has one entry per UTC day of the range, zeros included. Default range: the last 30 days ending today; at most 90 days, otherwise 400. `totals` are the all-time counters, `period` the sums of the range. Shares have no timestamp, so there is no per-day series for them. views, saves, deeplinkClicks are not collected by the platform: they are absent from the answer, not zero.","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/PostRef"},{"name":"from","in":"query","required":false,"description":"First UTC day, inclusive (`2026-10-01`; a full timestamp is taken as its UTC day). Default: 30 days before `to`.","schema":{"type":"string","format":"date"},"example":"2026-10-18"},{"name":"to","in":"query","required":false,"description":"Last UTC day, inclusive. Default: today (UTC).","schema":{"type":"string","format":"date"},"example":"2026-10-24"}],"responses":{"200":{"description":"Daily series.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostStats"},"example":{"success":true,"data":{"postId":"3f1c2a9e-5b7d-4c11-9a7e-0b1c2d3e4f5a","from":"2026-10-18","to":"2026-10-24","totals":{"likes":42,"comments":3,"shares":5},"period":{"likes":9,"comments":2},"series":[{"date":"2026-10-18","likes":0,"comments":0},{"date":"2026-10-19","likes":1,"comments":0},{"date":"2026-10-20","likes":4,"comments":1},{"date":"2026-10-21","likes":2,"comments":0},{"date":"2026-10-22","likes":0,"comments":0},{"date":"2026-10-23","likes":1,"comments":1},{"date":"2026-10-24","likes":1,"comments":0}],"unavailable":["views","saves","deeplinkClicks"],"unavailableNote":"Views, saves and deeplink clicks are not collected on the platform, so there is no data for them (not zero — absent)."}}}}},"400":{"description":"Invalid dates, `from` after `to`, or a range longer than the maximum. Nothing was written and no quota was spent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"The range must be at most 90 days (from and to inclusive)"}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid or missing API key","docs":"https://pixplace.space/settings#developer"}}}},"404":{"description":"The post does not exist, is not yours or is hidden. Never 403: the API does not reveal which ids exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Post not found"}}}},"500":{"description":"Unexpected error. No details are exposed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Internal error"}}}},"503":{"description":"A dependency (database or storage) is momentarily unavailable. `Retry-After: 5`. Safe to retry.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Service temporarily unavailable. Please retry shortly."}}}}},"x-unavailable":["views","saves","deeplinkClicks"]}},"/api/v1/uploads/from-url":{"post":{"operationId":"uploadFromUrl","tags":["Uploads"],"summary":"Have the server download a public image or video and store it.","description":"The server downloads the URL (https only, no credentials, public hosts only, at most 3 redirects, 25 s in total) and stores it in the portal's bucket. The file type is decided by its CONTENT, not by headers or the extension: JPEG, PNG, WebP, MP4 and WebM are accepted; SVG, HTML, GIF and everything else is 415. Images up to 20 MB, videos up to 100 MB (larger videos: POST /api/v1/uploads). Use `publicUrl` as `attachments[].url` in POST /api/v1/posts or `url` in POST /api/v1/stories. Limits: 20/min and 200/day per account, both upload endpoints together. Uploaded files are public and cached as immutable.","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"description":"The source URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadFromUrlRequest"},"examples":{"image":{"summary":"Image by URL","value":{"url":"https://example.com/photos/living-room.jpg"}}}}}},"responses":{"200":{"description":"Replay: same Idempotency-Key, same `publicUrl`, nothing downloaded again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadFromUrlResponse"},"example":{"success":true,"data":{"publicUrl":"https://cdn.pixplace.space/content/cm9x2k4ab0001ld0h5q7w3e2z/2026-10/3f1c2a9e-5b7d-4c11-9a7e-0b1c2d3e4f5a.jpg","type":"IMAGE","contentType":"image/jpeg","size":482113,"expiresAt":null}}}},"headers":{"Idempotent-Replayed":{"$ref":"#/components/headers/IdempotentReplayed"}}},"201":{"description":"Stored.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadFromUrlResponse"},"example":{"success":true,"data":{"publicUrl":"https://cdn.pixplace.space/content/cm9x2k4ab0001ld0h5q7w3e2z/2026-10/3f1c2a9e-5b7d-4c11-9a7e-0b1c2d3e4f5a.jpg","type":"IMAGE","contentType":"image/jpeg","size":482113,"expiresAt":null}}}}},"400":{"description":"Bad body, a URL that is not https or has credentials/port, or a non-public address. Nothing was written and no quota was spent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"url must use https"}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid or missing API key","docs":"https://pixplace.space/settings#developer"}}}},"413":{"description":"The file is larger than the limit for its type, or the JSON body is over 16 KB.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"The file is larger than the allowed size (20 MB for images, 100 MB for videos). For bigger videos use POST /api/v1/uploads (presigned upload, up to 200 MB)."}}}},"415":{"description":"The content is not JPEG, PNG, WebP, MP4 or WebM.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"SVG is not allowed. Allowed formats: JPEG, PNG, WebP (images) and MP4, WebM (video)."}}}},"429":{"description":"Upload limit. Read `Retry-After`.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"},"example":{"error":"Rate limit of 20 uploads per minute per account reached. Retry in 9s.","scope":"minute","retryAfter":9,"minuteLimit":20,"dailyLimit":200}}}},"500":{"description":"Unexpected error. No details are exposed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Internal error"}}}},"502":{"description":"The source could not be downloaded: HTTP 4xx/5xx, unresolvable host, too many redirects, compressed response or a broken connection.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Could not download the file from the source URL: the source responded with HTTP 404."}}}},"503":{"description":"A dependency (database or storage) is momentarily unavailable. `Retry-After: 5`. Safe to retry with the same Idempotency-Key.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Service temporarily unavailable. Please retry shortly."}}}},"504":{"description":"The source did not respond in time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"The source URL did not respond within 25 seconds."}}}}},"x-limits":{"perMinute":20,"perDay":200,"maxImageBytes":20971520,"maxVideoBytes":104857600}}},"/api/v1/uploads":{"post":{"operationId":"createUploadUrl","tags":["Uploads"],"summary":"Get a presigned URL to PUT a large file (up to 200 MB video) straight to storage.","description":"Two steps: (1) call this endpoint with the exact file name, content type and size; (2) PUT the file to `uploadUrl` with exactly the returned headers and a body of exactly `size` bytes within 15 minutes. Never send your API key to `uploadUrl`. Then use `publicUrl` in a post or story. Images up to 20 MB, videos up to 200 MB. Same 20/min and 200/day counter as from-url.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"description":"The file you are going to upload.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PresignRequest"},"examples":{"video":{"summary":"Large video","value":{"fileName":"neon-city.mp4","contentType":"video/mp4","size":48211300}}}}}},"responses":{"201":{"description":"Presigned URL created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PresignResponse"},"example":{"success":true,"data":{"uploadUrl":"https://pixplace-portal-users.0123456789abcdef0123456789abcdef.r2.cloudflarestorage.com/content/cm9x2k4ab0001ld0h5q7w3e2z/2026-10/7b1d9c52-0e4a-4f6b-8a35-2d6f1e9c4b70.mp4?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=900&X-Amz-SignedHeaders=content-length%3Bcontent-type%3Bhost&X-Amz-Signature=…","publicUrl":"https://cdn.pixplace.space/content/cm9x2k4ab0001ld0h5q7w3e2z/2026-10/7b1d9c52-0e4a-4f6b-8a35-2d6f1e9c4b70.mp4","expiresAt":"2026-10-21T10:30:00.000Z","method":"PUT","headers":{"Content-Type":"video/mp4"},"key":"content/cm9x2k4ab0001ld0h5q7w3e2z/2026-10/7b1d9c52-0e4a-4f6b-8a35-2d6f1e9c4b70.mp4"}}}}},"400":{"description":"Invalid fileName, contentType or size. Nothing was written and no quota was spent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"contentType must be one of: image/jpeg, image/png, image/webp, video/mp4, video/webm"}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid or missing API key","docs":"https://pixplace.space/settings#developer"}}}},"413":{"description":"The declared size is over the limit for the type, or the JSON body is over 16 KB.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Request body must be at most 16 KB"}}}},"429":{"description":"Upload limit. Read `Retry-After`.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"},"example":{"error":"Rate limit of 20 uploads per minute per account reached. Retry in 9s.","scope":"minute","retryAfter":9,"minuteLimit":20,"dailyLimit":200}}}},"500":{"description":"Unexpected error. No details are exposed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Internal error"}}}},"503":{"description":"A dependency (database or storage) is momentarily unavailable. `Retry-After: 5`. Safe to retry.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Service temporarily unavailable. Please retry shortly."}}}}},"x-limits":{"perMinute":20,"perDay":200,"maxImageBytes":20971520,"maxVideoBytes":209715200}}},"/api/v1/stories":{"post":{"operationId":"createStory","tags":["Stories"],"summary":"Publish a story (visible for 24 hours).","description":"Publishes an image or video story for the key owner. The file is not downloaded or inspected: only the host allow-list is checked, so upload first and pass the `publicUrl`. IMAGE hosts: cdn.pixplace.space, *.supabase.co, *.supabase.in, pub-7ca8823a8abf4319b8c347e72d913fd7.r2.dev. VIDEO hosts: cdn.pixplace.space, videos.pexels.com, pub-*.r2.dev (`*` matches exactly one DNS label). Anything else is a 400 that lists the allowed hosts. Upload the file with POST /api/v1/uploads/from-url or POST /api/v1/uploads to get a URL on cdn.pixplace.space. Recommended: vertical 9:16, video up to 60 s (not enforced). Limits: 5/min and 30/day per account, counted in the database over every key; a replay is free. A repeat with the same Idempotency-Key but a different url or type is a 409.","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"description":"The media of the story.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoryCreateRequest"},"examples":{"image":{"summary":"Image story","description":"A vertical image. The url is a file you uploaded (or any other URL on an allowed image host).","value":{"url":"https://cdn.pixplace.space/content/cm9x2k4ab0001ld0h5q7w3e2z/2026-10/3f1c2a9e-5b7d-4c11-9a7e-0b1c2d3e4f5a.jpg","type":"IMAGE"}},"video":{"summary":"Video story","description":"A vertical video. VIDEO urls are accepted only from the VIDEO host list.","value":{"url":"https://cdn.pixplace.space/content/cm9x2k4ab0001ld0h5q7w3e2z/2026-10/7b1d9c52-0e4a-4f6b-8a35-2d6f1e9c4b70.mp4","type":"VIDEO"}}}}}},"responses":{"200":{"description":"Replay: the ORIGINAL story is returned.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoryResponse"},"example":{"success":true,"data":{"id":"5d1b6f0e-2c8a-5e43-9b17-6a0f4c2e8d91","url":"https://cdn.pixplace.space/content/cm9x2k4ab0001ld0h5q7w3e2z/2026-10/3f1c2a9e-5b7d-4c11-9a7e-0b1c2d3e4f5a.jpg","type":"IMAGE","createdAt":"2026-10-21T10:15:30.000Z","expiresAt":"2026-10-22T10:15:30.000Z"}}}},"headers":{"Idempotent-Replayed":{"$ref":"#/components/headers/IdempotentReplayed"}}},"201":{"description":"Published.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoryResponse"},"example":{"success":true,"data":{"id":"5d1b6f0e-2c8a-5e43-9b17-6a0f4c2e8d91","url":"https://cdn.pixplace.space/content/cm9x2k4ab0001ld0h5q7w3e2z/2026-10/3f1c2a9e-5b7d-4c11-9a7e-0b1c2d3e4f5a.jpg","type":"IMAGE","createdAt":"2026-10-21T10:15:30.000Z","expiresAt":"2026-10-22T10:15:30.000Z"}}}}},"400":{"description":"Invalid url, type or Idempotency-Key; the message names the allowed hosts. Nothing was written and no quota was spent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"url must be an https URL on an allowed host for IMAGE (cdn.pixplace.space, *.supabase.co, *.supabase.in, pub-7ca8823a8abf4319b8c347e72d913fd7.r2.dev)"}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid or missing API key","docs":"https://pixplace.space/settings#developer"}}}},"409":{"description":"This Idempotency-Key was already used for a story with a different url or type.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"This Idempotency-Key was already used for a story with a different url or type. Send a new Idempotency-Key to publish a different story, or repeat the original request unchanged."}}}},"429":{"description":"Per-minute or per-day stories limit. Read `Retry-After`.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"},"example":{"error":"Rate limit of 5 stories per minute per account reached. Retry in 20s.","scope":"minute","retryAfter":20,"minuteLimit":5,"dailyLimit":30}}}},"500":{"description":"Unexpected error. No details are exposed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Internal error"}}}},"503":{"description":"A dependency (database or storage) is momentarily unavailable. `Retry-After: 5`. Retry with the SAME Idempotency-Key.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Service temporarily unavailable. Please retry shortly."}}}}},"x-limits":{"perMinute":5,"perDay":30}},"get":{"operationId":"listStories","tags":["Stories"],"summary":"List your own active stories (the last 24 hours), newest first.","description":"Only the key owner's own active stories are returned; other accounts' stories never are.","security":[{"bearerAuth":[]}],"parameters":[{"name":"limit","in":"query","required":false,"description":"How many stories to return.","schema":{"type":"integer","minimum":1,"maximum":50,"default":50}}],"responses":{"200":{"description":"Active stories.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoryListResponse"},"example":{"success":true,"data":[{"id":"9a3e7c15-4b2d-5f08-8c61-1d7e0a5b3f24","url":"https://cdn.pixplace.space/content/cm9x2k4ab0001ld0h5q7w3e2z/2026-10/7b1d9c52-0e4a-4f6b-8a35-2d6f1e9c4b70.mp4","type":"VIDEO","createdAt":"2026-10-21T12:40:02.000Z","expiresAt":"2026-10-22T12:40:02.000Z"},{"id":"5d1b6f0e-2c8a-5e43-9b17-6a0f4c2e8d91","url":"https://cdn.pixplace.space/content/cm9x2k4ab0001ld0h5q7w3e2z/2026-10/3f1c2a9e-5b7d-4c11-9a7e-0b1c2d3e4f5a.jpg","type":"IMAGE","createdAt":"2026-10-21T10:15:30.000Z","expiresAt":"2026-10-22T10:15:30.000Z"}]}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid or missing API key","docs":"https://pixplace.space/settings#developer"}}}},"500":{"description":"Unexpected error. No details are exposed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Internal error"}}}},"503":{"description":"A dependency (database or storage) is momentarily unavailable. `Retry-After: 5`. Safe to retry.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Service temporarily unavailable. Please retry shortly."}}}}}}},"/api/v1/stories/{id}":{"delete":{"operationId":"deleteStory","tags":["Stories"],"summary":"Delete one of your own active stories.","description":"A story is addressable while GET /api/v1/stories lists it (created within the last 24 h). Someone else's, expired, already deleted and non-existent stories are all 404. Only the database row is removed; the media file stays.","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/StoryId"}],"responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResult"},"example":{"success":true,"deleted":"5d1b6f0e-2c8a-5e43-9b17-6a0f4c2e8d91"}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid or missing API key","docs":"https://pixplace.space/settings#developer"}}}},"404":{"description":"The story does not exist, is not yours, or has expired. Never 403: the API does not reveal which ids exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Story not found"}}}},"429":{"description":"Write limit. Read `Retry-After`.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"},"example":{"error":"Rate limit of 30 write requests per minute per account reached. Retry in 12s.","scope":"minute","retryAfter":12,"minuteLimit":30,"dailyLimit":300}}}},"500":{"description":"Unexpected error. No details are exposed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Internal error"}}}},"503":{"description":"A dependency (database or storage) is momentarily unavailable. `Retry-After: 5`. Safe to retry (a repeat may answer 404).","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Service temporarily unavailable. Please retry shortly."}}}}},"x-limits":{"perMinute":30,"perDay":300}}},"/api/v1/posts/{id}/comments":{"get":{"operationId":"listPostComments","tags":["Comments"],"summary":"Read the comments under one of your own posts, page by page.","description":"A flat list, oldest first, replies included (`parentId` is null for top-level comments), so a reply always comes after its parent. Cursor pagination: pass `nextCursor` back as `cursor` until `hasMore` is false. Page size 50 by default, 100 at most.","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/PostRef"},{"$ref":"#/components/parameters/PageLimit"},{"$ref":"#/components/parameters/PageCursor"}],"responses":{"200":{"description":"A page of comments.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentListResponse"},"example":{"success":true,"data":[{"id":"8a4f1d27-6c3b-4e90-b5a8-2d7e9f01c346","content":"Love the colors! Which model did you use?","parentId":null,"createdAt":"2026-10-20T10:00:00.000Z","author":{"id":"cm9x7k2ab0002ld0h8f1q4r6t","username":"jane_art","name":"Jane","avatar":"https://cdn.pixplace.space/avatars/jane.jpg"},"reactionsCount":2},{"id":"9b2e5c18-3d7a-4f06-a1c4-5e8d0b7f2a93","content":"Thank you! The full prompt is in the description.","parentId":"8a4f1d27-6c3b-4e90-b5a8-2d7e9f01c346","createdAt":"2026-10-20T11:00:00.000Z","author":{"id":"cm9x2k4ab0001ld0h5q7w3e2z","username":"neon_lab","name":"Neon Lab","avatar":null},"reactionsCount":0}],"nextCursor":"MTc5MjQ5NDAwMDAwMF85YjJlNWMxOC0zZDdhLTRmMDYtYTFjNC01ZThkMGI3ZjJhOTM","hasMore":true}}}},"400":{"description":"Invalid `limit` or `cursor`. Nothing was written and no quota was spent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"limit must be an integer from 1 to 100"}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid or missing API key","docs":"https://pixplace.space/settings#developer"}}}},"404":{"description":"The post does not exist, is not yours or is hidden. Never 403: the API does not reveal which ids exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Post not found"}}}},"500":{"description":"Unexpected error. No details are exposed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Internal error"}}}},"503":{"description":"A dependency (database or storage) is momentarily unavailable. `Retry-After: 5`. Safe to retry.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Service temporarily unavailable. Please retry shortly."}}}}}},"post":{"operationId":"createComment","tags":["Comments"],"summary":"Write a comment, or a reply to a comment, under one of your own posts — as your account.","description":"The author is always the owner of the key. `parentId` must be a comment of the same post. Limit: 20/min and 200/day per account, its own counter; a request that ends in 400 or 404 also counts. There is NO Idempotency-Key: repeating the request creates a DUPLICATE comment. After a timeout or a 5xx read GET /posts/{id}/comments before retrying.","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/PostRef"}],"requestBody":{"required":true,"description":"The comment.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentCreateRequest"},"examples":{"reply":{"summary":"Reply to a comment","value":{"content":"Thank you! The full prompt is in the description.","parentId":"8a4f1d27-6c3b-4e90-b5a8-2d7e9f01c346"}}}}}},"responses":{"201":{"description":"Created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentResponse"},"example":{"success":true,"data":{"id":"9b2e5c18-3d7a-4f06-a1c4-5e8d0b7f2a93","content":"Thank you! The full prompt is in the description.","parentId":"8a4f1d27-6c3b-4e90-b5a8-2d7e9f01c346","createdAt":"2026-10-20T11:00:00.000Z","author":{"id":"cm9x2k4ab0001ld0h5q7w3e2z","username":"neon_lab","name":"Neon Lab","avatar":null},"reactionsCount":0}}}}},"400":{"description":"Empty or too long `content`, or a `parentId` that is not a comment of this post. Nothing was written and no quota was spent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"content is required and must not be blank"}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid or missing API key","docs":"https://pixplace.space/settings#developer"}}}},"404":{"description":"The post does not exist, is not yours or is hidden. Never 403: the API does not reveal which ids exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Post not found"}}}},"429":{"description":"Comment limit. Read `Retry-After`.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"},"example":{"error":"Rate limit of 20 write requests per minute per account reached. Retry in 7s.","scope":"minute","retryAfter":7,"minuteLimit":20,"dailyLimit":200}}}},"500":{"description":"Unexpected error. No details are exposed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Internal error"}}}},"503":{"description":"A dependency (database or storage) is momentarily unavailable. `Retry-After: 5`. Do NOT blindly retry: it may have created a duplicate. Read the list first.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Service temporarily unavailable. Please retry shortly."}}}}},"x-limits":{"perMinute":20,"perDay":200}}},"/api/v1/comments":{"get":{"operationId":"listCommentsInbox","tags":["Comments"],"summary":"The inbox: what other people wrote under any of your posts, newest first.","description":"Comments (replies included) under ALL your visible posts. Your own comments and comments under other people's posts are not in it. To poll for news, remember the `createdAt` of the newest comment you processed and send it as `since`; a comment with exactly that timestamp is returned again, so de-duplicate by `id`.","security":[{"bearerAuth":[]}],"parameters":[{"name":"since","in":"query","required":false,"description":"ISO date or timestamp (no zone = UTC). Default: 7 days ago; at most 90 days back, otherwise 400.","schema":{"type":"string","format":"date-time"},"example":"2026-10-23T00:00:00Z"},{"$ref":"#/components/parameters/PageLimit"},{"$ref":"#/components/parameters/PageCursor"}],"responses":{"200":{"description":"A page of comments.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboxResponse"},"example":{"success":true,"data":[{"id":"c3d4e5f6-0003-4000-8000-000000000003","content":"Can I use this as a phone wallpaper?","parentId":null,"postId":"3f1c2a9e-5b7d-4c11-9a7e-0b1c2d3e4f5a","post":{"id":"3f1c2a9e-5b7d-4c11-9a7e-0b1c2d3e4f5a","slug":"neon-city-at-night-8f3a2c1d9e4b7a60","title":"Neon city at night — v2"},"createdAt":"2026-10-24T08:15:00.000Z","author":{"id":"cm9x7k2ab0002ld0h8f1q4r6t","username":"jane_art","name":"Jane","avatar":"https://cdn.pixplace.space/avatars/jane.jpg"},"reactionsCount":0},{"id":"b2c3d4e5-0002-4000-8000-000000000002","content":"Looks great!","parentId":null,"postId":"3f1c2a9e-5b7d-4c11-9a7e-0b1c2d3e4f5a","post":{"id":"3f1c2a9e-5b7d-4c11-9a7e-0b1c2d3e4f5a","slug":"neon-city-at-night-8f3a2c1d9e4b7a60","title":"Neon city at night — v2"},"createdAt":"2026-10-23T17:40:00.000Z","author":{"id":"cm9x9p1ab0003ld0h2k5m7n8v","username":"bob","name":"Bob","avatar":null},"reactionsCount":1}],"nextCursor":null,"hasMore":false}}}},"400":{"description":"Invalid `since`, `limit` or `cursor`. Nothing was written and no quota was spent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"since must be at most 90 days in the past"}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid or missing API key","docs":"https://pixplace.space/settings#developer"}}}},"500":{"description":"Unexpected error. No details are exposed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Internal error"}}}},"503":{"description":"A dependency (database or storage) is momentarily unavailable. `Retry-After: 5`. Safe to retry.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Service temporarily unavailable. Please retry shortly."}}}}}}},"/api/v1/comments/{id}":{"delete":{"operationId":"deleteComment","tags":["Comments"],"summary":"Delete a comment — moderation of your own posts.","description":"You can delete any comment of your own, and any comment under one of your own posts, whoever wrote it. Anything else is a 404. The comment goes together with ALL its replies and their reactions; `repliesDeleted` says how many. There is no \"hide\": deleting is the only moderation. Treat 404 as \"already gone\".","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/CommentId"}],"responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentDeleteResult"},"example":{"success":true,"deleted":"8a4f1d27-6c3b-4e90-b5a8-2d7e9f01c346","repliesDeleted":1}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid or missing API key","docs":"https://pixplace.space/settings#developer"}}}},"404":{"description":"The comment does not exist, is not yours and not under your post, or is already gone. Never 403: the API does not reveal which ids exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Comment not found"}}}},"429":{"description":"Write limit. Read `Retry-After`.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"},"example":{"error":"Rate limit of 30 write requests per minute per account reached. Retry in 12s.","scope":"minute","retryAfter":12,"minuteLimit":30,"dailyLimit":300}}}},"500":{"description":"Unexpected error. No details are exposed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Internal error"}}}},"503":{"description":"A dependency (database or storage) is momentarily unavailable. `Retry-After: 5`. Safe to retry (a repeat may answer 404).","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Service temporarily unavailable. Please retry shortly."}}}}},"x-limits":{"perMinute":30,"perDay":300},"x-unavailable":["hideComment"]}},"/api/v1/account":{"get":{"operationId":"getAccount","tags":["Account"],"summary":"The profile and counters of the account that owns the key.","description":"Public profile fields only (no e-mail, flags or settings) and `counters` { posts, followers, following, storiesActive }. It is always the account of the key; there is no way to ask for another one.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"The account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountResponse"},"example":{"success":true,"data":{"id":"cm9x2k4ab0001ld0h5q7w3e2z","username":"neon_lab","name":"Neon Lab","avatar":null,"bio":"AI art: neon cities, cyberpunk, long exposure.","niche":"photography","category":"ai-art","createdAt":"2026-03-02T10:15:00.000Z","counters":{"posts":128,"followers":3412,"following":57,"storiesActive":2}}}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid or missing API key","docs":"https://pixplace.space/settings#developer"}}}},"500":{"description":"Unexpected error. No details are exposed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Internal error"}}}},"503":{"description":"A dependency (database or storage) is momentarily unavailable. `Retry-After: 5`. Safe to retry.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Service temporarily unavailable. Please retry shortly."}}}}}}},"/api/v1/account/stats":{"get":{"operationId":"getAccountStats","tags":["Account"],"summary":"Growth of the account per UTC day: posts, likes, comments and new followers.","description":"`series` has one entry per UTC day of the range, zeros included. Default range: the last 30 days ending today; at most 90 days, otherwise 400. `granularity` accepts only `day`. views, saves, deeplinkClicks, profileViews are not collected by the platform: they are listed in `unavailable` and have no numbers.","security":[{"bearerAuth":[]}],"parameters":[{"name":"from","in":"query","required":false,"description":"First UTC day, inclusive.","schema":{"type":"string","format":"date"},"example":"2026-10-18"},{"name":"to","in":"query","required":false,"description":"Last UTC day, inclusive.","schema":{"type":"string","format":"date"},"example":"2026-10-24"},{"name":"granularity","in":"query","required":false,"description":"Only `day` is supported.","schema":{"type":"string","enum":["day"],"default":"day"}}],"responses":{"200":{"description":"Daily series.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountStats"},"example":{"success":true,"data":{"granularity":"day","from":"2026-10-18","to":"2026-10-24","totals":{"posts":128,"followers":3412,"following":57,"likes":5120,"comments":410},"period":{"postsCreated":5,"likesReceived":45,"commentsReceived":9,"newFollowers":16},"series":[{"date":"2026-10-18","postsCreated":0,"likesReceived":3,"commentsReceived":0,"newFollowers":1},{"date":"2026-10-19","postsCreated":1,"likesReceived":5,"commentsReceived":1,"newFollowers":2},{"date":"2026-10-20","postsCreated":2,"likesReceived":11,"commentsReceived":3,"newFollowers":4},{"date":"2026-10-21","postsCreated":0,"likesReceived":6,"commentsReceived":2,"newFollowers":1},{"date":"2026-10-22","postsCreated":1,"likesReceived":4,"commentsReceived":0,"newFollowers":0},{"date":"2026-10-23","postsCreated":0,"likesReceived":7,"commentsReceived":1,"newFollowers":3},{"date":"2026-10-24","postsCreated":1,"likesReceived":9,"commentsReceived":2,"newFollowers":5}],"unavailable":["views","saves","deeplinkClicks","profileViews"],"unavailableNote":"Views, saves, deeplink clicks and profile views are not collected on the platform, so there is no data for them (not zero — absent)."}}}}},"400":{"description":"Invalid dates, `from` after `to`, a range over the maximum, or an unsupported granularity. Nothing was written and no quota was spent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"granularity must be \"day\" (the only supported value)"}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid or missing API key","docs":"https://pixplace.space/settings#developer"}}}},"500":{"description":"Unexpected error. No details are exposed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Internal error"}}}},"503":{"description":"A dependency (database or storage) is momentarily unavailable. `Retry-After: 5`. Safe to retry.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Service temporarily unavailable. Please retry shortly."}}}}},"x-unavailable":["views","saves","deeplinkClicks","profileViews"]}},"/api/v1/followers":{"get":{"operationId":"listFollowers","tags":["Account"],"summary":"The people who follow your account, newest first.","description":"Public profile fields and `followedAt`. Cursor pagination by (followedAt, id): a new follower arriving while you page never shifts the next page. Page size 50 by default, 100 at most. Followers are read-only: there is no follow, unfollow or block through the API.","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/PageLimit"},{"$ref":"#/components/parameters/PageCursor"}],"responses":{"200":{"description":"A page of followers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowListResponse"},"example":{"success":true,"data":[{"id":"cm9x7k2ab0002ld0h8f1q4r6t","username":"jane_art","name":"Jane","avatar":"https://cdn.pixplace.space/avatars/jane.jpg","followedAt":"2026-10-24T08:12:00.000Z"},{"id":"cm9x9p1ab0003ld0h2k5m7n8v","username":"bob","name":"Bob","avatar":null,"followedAt":"2026-10-23T17:40:00.000Z"},{"id":"cm9xa1bc0007ld0h3u6v8w9x1","username":"pixel_fan","name":null,"avatar":null,"followedAt":"2026-10-21T09:30:00.000Z"}],"nextCursor":"MTc5MjU3NTAwMDAwMF9jbTl4YTFiYzAwMDdsZDBoM3U2djh3OXgx","hasMore":true}}}},"400":{"description":"Invalid `limit` or `cursor`. Nothing was written and no quota was spent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"limit must be an integer from 1 to 100"}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid or missing API key","docs":"https://pixplace.space/settings#developer"}}}},"500":{"description":"Unexpected error. No details are exposed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Internal error"}}}},"503":{"description":"A dependency (database or storage) is momentarily unavailable. `Retry-After: 5`. Safe to retry.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Service temporarily unavailable. Please retry shortly."}}}}}}},"/api/v1/following":{"get":{"operationId":"listFollowing","tags":["Account"],"summary":"The people your account follows, newest first.","description":"Same format, limits and paging as GET /api/v1/followers; `followedAt` is when your account started following that person.","security":[{"bearerAuth":[]}],"parameters":[{"$ref":"#/components/parameters/PageLimit"},{"$ref":"#/components/parameters/PageCursor"}],"responses":{"200":{"description":"A page of followed accounts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FollowListResponse"},"example":{"success":true,"data":[{"id":"cm9xc3de0010ld0h5w8x0y2z3","username":"studio_lumen","name":"Studio Lumen","avatar":null,"followedAt":"2026-10-23T12:00:00.000Z"},{"id":"cm9xb2cd0009ld0h4v7w9x1y2","username":"prompt_lab","name":"Prompt Lab","avatar":null,"followedAt":"2026-10-20T07:45:00.000Z"}],"nextCursor":"MTc5MjQ4MjMwMDAwMF9jbTl4YjJjZDAwMDlsZDBoNHY3dzl4MXky","hasMore":true}}}},"400":{"description":"Invalid `limit` or `cursor`. Nothing was written and no quota was spent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"limit must be an integer from 1 to 100"}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid or missing API key","docs":"https://pixplace.space/settings#developer"}}}},"500":{"description":"Unexpected error. No details are exposed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Internal error"}}}},"503":{"description":"A dependency (database or storage) is momentarily unavailable. `Retry-After: 5`. Safe to retry.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Service temporarily unavailable. Please retry shortly."}}}}}}},"/api/v1/notifications":{"get":{"operationId":"listNotifications","tags":["Account"],"summary":"The notifications of your account (likes, comments, follows, system), newest first.","description":"`unreadCount` is the number of ALL unread notifications whatever the filter and the page: a cheap way to see whether there is anything new. To poll, call with `unread=1`, process the items, then mark them with POST /api/v1/notifications/read.","security":[{"bearerAuth":[]}],"parameters":[{"name":"unread","in":"query","required":false,"description":"`1` or `true` returns only unread notifications; `0`, `false` or no parameter returns all. Anything else is a 400.","schema":{"type":"string","enum":["1","true","0","false"]},"example":"1"},{"$ref":"#/components/parameters/PageLimit"},{"$ref":"#/components/parameters/PageCursor"}],"responses":{"200":{"description":"A page of notifications.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationListResponse"},"example":{"success":true,"data":[{"id":"e5f6a7b8-0003-4000-8000-000000000003","type":"comment","title":"Jane commented on your post","body":"Love the colors! Which model did you use?","link":"/post/neon-city-at-night-8f3a2c1d9e4b7a60","isRead":false,"actorId":"cm9x7k2ab0002ld0h8f1q4r6t","postId":"3f1c2a9e-5b7d-4c11-9a7e-0b1c2d3e4f5a","createdAt":"2026-10-24T08:15:00.000Z"},{"id":"e5f6a7b8-0002-4000-8000-000000000002","type":"follow","title":"Bob started following you","body":null,"link":"/user/cm9x9p1ab0003ld0h2k5m7n8v","isRead":false,"actorId":"cm9x9p1ab0003ld0h2k5m7n8v","postId":null,"createdAt":"2026-10-23T17:40:00.000Z"},{"id":"e5f6a7b8-0001-4000-8000-000000000001","type":"like","title":"Jane liked your post","body":null,"link":"/post/neon-city-at-night-8f3a2c1d9e4b7a60","isRead":false,"actorId":"cm9x7k2ab0002ld0h8f1q4r6t","postId":"3f1c2a9e-5b7d-4c11-9a7e-0b1c2d3e4f5a","createdAt":"2026-10-22T09:00:00.000Z"}],"nextCursor":null,"hasMore":false,"unreadCount":3}}}},"400":{"description":"Invalid `unread`, `limit` or `cursor`. Nothing was written and no quota was spent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"limit must be an integer from 1 to 100"}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid or missing API key","docs":"https://pixplace.space/settings#developer"}}}},"500":{"description":"Unexpected error. No details are exposed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Internal error"}}}},"503":{"description":"A dependency (database or storage) is momentarily unavailable. `Retry-After: 5`. Safe to retry.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Service temporarily unavailable. Please retry shortly."}}}}}}},"/api/v1/notifications/read":{"post":{"operationId":"markNotificationsRead","tags":["Account"],"summary":"Mark notifications as read.","description":"Send either `{ \"ids\": [...] }` (1–100 ids) or `{ \"all\": true }`. Both, neither or anything else is a 400 and nothing changes. Only your own notifications are touched; a foreign or unknown id is ignored without an error. Repeating is safe and answers `marked: 0`. Limit: 60/min and 5000/day per account, its own counter.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"description":"Which notifications to mark.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationsReadRequest"},"examples":{"ids":{"summary":"Specific notifications","value":{"ids":["e5f6a7b8-0003-4000-8000-000000000003","e5f6a7b8-0002-4000-8000-000000000002"]}},"all":{"summary":"Every unread notification","value":{"all":true}}}}}},"responses":{"200":{"description":"Marked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationsReadResponse"},"example":{"success":true,"marked":2}}}},"400":{"description":"Neither or both of `ids` and `all`, too many ids, or a bad body. Nothing was written and no quota was spent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Send ids (a list of notification ids) or all: true"}}}},"401":{"description":"Missing, malformed or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid or missing API key","docs":"https://pixplace.space/settings#developer"}}}},"429":{"description":"Notification-read limit. Read `Retry-After`.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"},"example":{"error":"Rate limit of 60 write requests per minute per account reached. Retry in 4s.","scope":"minute","retryAfter":4,"minuteLimit":60,"dailyLimit":5000}}}},"500":{"description":"Unexpected error. No details are exposed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Internal error"}}}},"503":{"description":"A dependency (database or storage) is momentarily unavailable. `Retry-After: 5`. Safe to retry.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Service temporarily unavailable. Please retry shortly."}}}}},"x-limits":{"perMinute":60,"perDay":5000}}},"/api/v1/categories":{"get":{"operationId":"listCategories","tags":["Taxonomy"],"summary":"All category slugs accepted by `categories` in POST /api/v1/posts.","description":"Public: no API key needed. Use the `slug` values. An unknown slug in a post is a 400.","security":[],"responses":{"200":{"description":"Categories sorted by name.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoriesResponse"},"example":{"categories":[{"name":"AI Art & Assets","slug":"ai-art"},{"name":"Architecture & Interior Design","slug":"architecture-interior-design"}]}}}}}}},"/api/v1/niches":{"get":{"operationId":"listNiches","tags":["Taxonomy"],"summary":"The niche taxonomy with live post counts.","description":"Public: no API key needed. Niches group content accounts; a content account that omits `categories` in POST /api/v1/posts gets the category of its niche when that exists. Cached for 5 minutes (`Cache-Control: public, max-age=300`).","security":[],"responses":{"200":{"description":"Niches and their groups.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NichesResponse"},"example":{"niches":[{"slug":"interior","name":"Interior design","parent":"home","parentName":"Home & Interior","accountSlug":"interior-ai","postCount":45}],"groups":[{"slug":"home","name":"Home & Interior"}]}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"ppk_live_…","description":"API key created in Settings → Developer on https://pixplace.space. Send it as `Authorization: Bearer ppk_live_…`. A key acts for its ONE owner account (up to 3 keys per account). A missing, malformed or revoked key is 401. Never put the key in a URL or send it to a third-party host.","x-unavailable":["multiAccountKey"]}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string","description":"Human-readable message. Stable enough to log, not to parse — branch on the HTTP status."},"docs":{"type":"string","description":"Only on 401: where to get a key.","format":"uri"}},"required":["error"]},"RateLimitError":{"type":"object","properties":{"error":{"type":"string","description":"Message with the limit and the seconds to wait."},"scope":{"type":"string","description":"Which window was exceeded.","enum":["minute","day"]},"retryAfter":{"type":"integer","description":"Seconds to wait (the same number as the Retry-After header)."},"minuteLimit":{"type":"integer","description":"The per-minute limit that applies to this endpoint."},"dailyLimit":{"type":"integer","description":"The per-day limit that applies to this endpoint."},"dailyUsage":{"type":"integer","description":"Posts only: how many posts this key has created today (UTC)."}},"required":["error"]},"AttachmentInput":{"type":"object","properties":{"url":{"type":"string","description":"https URL on an allowed host, no credentials or custom port.","format":"uri","maxLength":2048},"type":{"type":"string","description":"IMAGE or VIDEO. Decides which host list applies to `url`.","enum":["IMAGE","VIDEO"]},"width":{"type":"integer","description":"Pixels.","minimum":1,"maximum":16384},"height":{"type":"integer","description":"Pixels.","minimum":1,"maximum":16384},"altText":{"type":"string","description":"Alternative text.","maxLength":500},"prompt":{"type":"string","description":"Prompt of this item; defaults to the post-level `prompt`.","maxLength":2000},"thumbnailUrl":{"type":"string","description":"Poster frame: https image URL on an allowed IMAGE host. Useful for VIDEO.","format":"uri","maxLength":2048}},"required":["url","type"],"x-allowedHosts":{"IMAGE":["cdn.pixplace.space","*.supabase.co","*.supabase.in","pub-7ca8823a8abf4319b8c347e72d913fd7.r2.dev"],"VIDEO":["cdn.pixplace.space","videos.pexels.com","pub-*.r2.dev"]},"description":"IMAGE hosts: cdn.pixplace.space, *.supabase.co, *.supabase.in, pub-7ca8823a8abf4319b8c347e72d913fd7.r2.dev. VIDEO hosts: cdn.pixplace.space, videos.pexels.com, pub-*.r2.dev (`*` matches exactly one DNS label). Anything else is a 400 that lists the allowed hosts. Upload the file with POST /api/v1/uploads/from-url or POST /api/v1/uploads to get a URL on cdn.pixplace.space."},"DeeplinkInput":{"type":"object","properties":{"url":{"type":"string","description":"https only (javascript:, data:, http:, //host are refused), no credentials, no spaces.","format":"uri","maxLength":2048},"label":{"type":"string","description":"Button text. `disable_image` and `disable_prompt` are reserved.","maxLength":60},"iconType":{"type":"string","description":"Icon of the button. Default `link`.","enum":["link","website","image","video","prompt","download","shop","github","telegram","youtube","instagram","twitter","tiktok","discord"],"default":"link"}},"required":["url"]},"PostCreateRequest":{"type":"object","properties":{"title":{"type":"string","description":"Post title.","minLength":3,"maxLength":200},"attachments":{"type":"array","items":{"$ref":"#/components/schemas/AttachmentInput"},"minItems":1,"maxItems":10,"description":"Media of the post; the array order is the carousel order. Send this OR the legacy `attachment`, never both."},"attachment":{"$ref":"#/components/schemas/AttachmentInput","deprecated":true,"description":"Legacy single-media field (`type` defaults to VIDEO). Use `attachments`."},"description":{"type":"string","description":"Post text.","maxLength":2000},"prompt":{"type":"string","description":"The generation prompt, shown on the post.","maxLength":2000},"deeplinks":{"type":"array","items":{"$ref":"#/components/schemas/DeeplinkInput"},"maxItems":5,"description":"Link buttons under the post."},"seoKeywords":{"type":"array","items":{"type":"string","maxLength":100},"maxItems":20,"description":"Trimmed and de-duplicated (case-insensitive)."},"categories":{"type":"array","items":{"type":"string"},"maxItems":20,"description":"Category slugs from GET /api/v1/categories. An unknown slug is a 400 that names it. If omitted, a content account gets the category of its niche (GET /api/v1/niches) when that exists."},"tags":{"type":"array","items":{"type":"string","maxLength":100},"maxItems":10,"description":"Tag names; created automatically."},"draft":{"type":"boolean","description":"true creates the post UNLISTED (isPublished=false): hidden from feeds, the sitemap and listings, but reachable by URL for a logged-in user. It still counts against the limits."}},"required":["title"]},"PostPatchRequest":{"type":"object","properties":{"title":{"type":"string","description":"New title.","minLength":3,"maxLength":200},"description":{"type":["string","null"],"description":"New text; null or \"\" clears it.","maxLength":2000},"prompt":{"type":["string","null"],"description":"New prompt; null or \"\" clears it.","maxLength":2000},"categories":{"type":"array","items":{"type":"string"},"maxItems":20,"description":"The COMPLETE new list (it replaces the stored one); [] empties it."},"tags":{"type":"array","items":{"type":"string","maxLength":100},"maxItems":10,"description":"The COMPLETE new list; [] empties it."},"seoKeywords":{"type":"array","items":{"type":"string","maxLength":100},"maxItems":20,"description":"The COMPLETE new list; [] empties it."},"deeplinks":{"type":"array","items":{"$ref":"#/components/schemas/DeeplinkInput"},"maxItems":5,"description":"The COMPLETE new list; [] empties it."},"draft":{"type":"boolean","description":"true unlists the post (isPublished=false), false publishes it."},"isPublished":{"type":"boolean","description":"Mirror image of `draft`. Both with contradicting values is a 400."}},"minProperties":1,"description":"Send only what changes. `attachments` is a 400: media cannot be changed (delete the post and create a new one). The slug never changes."},"AttachmentOut":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string","format":"uri"},"type":{"type":"string","description":"IMAGE or VIDEO. Decides which host list applies to `url`.","enum":["IMAGE","VIDEO"]},"width":{"type":["integer","null"]},"height":{"type":["integer","null"]},"altText":{"type":["string","null"]},"thumbnailUrl":{"type":["string","null"]},"order":{"type":"integer","description":"Position in the carousel, from 0."}},"required":["id","url","type"]},"DeeplinkOut":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string","format":"uri"},"label":{"type":["string","null"]},"iconType":{"type":"string"}},"required":["id","url"]},"PostCreated":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string","description":"Public URL of the post.","format":"uri"},"title":{"type":"string"},"description":{"type":["string","null"]},"isPublished":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"attachments":{"type":"array","items":{"$ref":"#/components/schemas/AttachmentOut"}},"deeplinks":{"type":"array","items":{"$ref":"#/components/schemas/DeeplinkOut"}},"categories":{"type":"array","items":{"type":"string"},"description":"Category slugs."},"tags":{"type":"array","items":{"type":"string"}},"seoKeywords":{"type":"array","items":{"type":"string"}}},"required":["id","slug","url","title"]},"post":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"title":{"type":"string"},"url":{"type":"string","format":"uri"},"createdAt":{"type":"string","format":"date-time"}},"deprecated":true,"description":"Legacy copy of the main fields, kept for old clients. Use `data`."},"usage":{"type":"object","properties":{"daily":{"type":"integer","description":"Legacy alias of dailyUsage."},"dailyUsage":{"type":"integer","description":"Posts created by this key today (UTC)."},"dailyLimit":{"type":"integer"},"minuteLimit":{"type":"integer"}},"description":"Quota of the key after this request."}},"required":["success","data"]},"PostDetail":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string","format":"uri"},"title":{"type":"string"},"description":{"type":["string","null"]},"prompt":{"type":["string","null"]},"isPublished":{"type":"boolean","description":"false is a draft: unlisted, not private."},"categories":{"type":"array","items":{"type":"string"},"description":"Category slugs."},"tags":{"type":"array","items":{"type":"string"}},"seoKeywords":{"type":"array","items":{"type":"string"}},"attachments":{"type":"array","items":{"$ref":"#/components/schemas/AttachmentOut"}},"deeplinks":{"type":"array","items":{"$ref":"#/components/schemas/DeeplinkOut"}},"counters":{"type":"object","properties":{"likes":{"type":"integer"},"shares":{"type":"integer"},"comments":{"type":"integer"}},"required":["likes","shares","comments"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","slug","url","title","isPublished","counters"]},"PostDetailResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/PostDetail"}},"required":["success","data"]},"PostListItem":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string","format":"uri"},"description":{"type":["string","null"]},"likes":{"type":"integer"},"shares":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"isPublished":{"type":"boolean"},"attachments":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"type":{"type":"string","description":"IMAGE or VIDEO. Decides which host list applies to `url`.","enum":["IMAGE","VIDEO"]}},"required":["url","type"]},"description":"Only the first media item."},"categories":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"slug":{"type":"string"}},"required":["name","slug"]}}},"required":["id","title","slug","url"]},"PostListResponse":{"type":"object","properties":{"posts":{"type":"array","items":{"$ref":"#/components/schemas/PostListItem"}},"page":{"type":"integer"},"limit":{"type":"integer"}},"required":["posts","page","limit"]},"DeleteResult":{"type":"object","properties":{"success":{"type":"boolean"},"deleted":{"type":"string","description":"Id of the deleted object."}},"required":["success","deleted"]},"CommentDeleteResult":{"type":"object","properties":{"success":{"type":"boolean"},"deleted":{"type":"string","description":"Id of the deleted comment."},"repliesDeleted":{"type":"integer","description":"How many replies (every level) went with it."}},"required":["success","deleted","repliesDeleted"]},"PostStats":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"postId":{"type":"string"},"from":{"type":"string","description":"First UTC day, inclusive.","format":"date"},"to":{"type":"string","description":"Last UTC day, inclusive.","format":"date"},"totals":{"type":"object","properties":{"likes":{"type":"integer"},"comments":{"type":"integer"},"shares":{"type":"integer"}},"description":"All-time counters of the post."},"period":{"type":"object","properties":{"likes":{"type":"integer"},"comments":{"type":"integer"}},"description":"Sums of `series`."},"series":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","format":"date"},"likes":{"type":"integer"},"comments":{"type":"integer"}},"required":["date","likes","comments"]},"description":"One entry per UTC day of the range, zeros included."},"unavailable":{"type":"array","items":{"type":"string"},"description":"Metrics the platform does not collect. They are absent from the answer, not zero."},"unavailableNote":{"type":"string"}},"required":["postId","from","to","series"]}},"required":["success","data"]},"UploadFromUrlRequest":{"type":"object","properties":{"url":{"type":"string","description":"Public https URL of an image or video. The server downloads it. No credentials, no custom port; the host must resolve to a public address.","format":"uri","maxLength":2048}},"required":["url"]},"UploadFromUrlResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"publicUrl":{"type":"string","description":"Use it as `attachments[].url` in POST /api/v1/posts.","format":"uri"},"type":{"type":"string","description":"IMAGE or VIDEO. Decides which host list applies to `url`.","enum":["IMAGE","VIDEO"]},"contentType":{"type":"string","enum":["image/jpeg","image/png","image/webp","video/mp4","video/webm"]},"size":{"type":"integer","description":"Bytes."},"expiresAt":{"type":"null","description":"Always null: uploaded files do not expire."}},"required":["publicUrl","type","contentType","size"]}},"required":["success","data"]},"PresignRequest":{"type":"object","properties":{"fileName":{"type":"string","description":"Used for its extension only, to catch a contradiction with contentType.","minLength":1,"maxLength":255},"contentType":{"type":"string","description":"Exact MIME type of the file.","enum":["image/jpeg","image/png","image/webp","video/mp4","video/webm"]},"size":{"type":"integer","description":"Exact size of the file in bytes. Images up to 20 MB, videos up to 200 MB.","minimum":1,"maximum":209715200}},"required":["fileName","contentType","size"]},"PresignResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"uploadUrl":{"type":"string","description":"PUT the file here within 15 minutes. Never send your API key to this URL."},"publicUrl":{"type":"string","description":"Use it as `attachments[].url` once the PUT succeeded.","format":"uri"},"expiresAt":{"type":"string","description":"When `uploadUrl` stops working.","format":"date-time"},"method":{"type":"string","enum":["PUT"]},"headers":{"type":"object","properties":{"Content-Type":{"type":"string"}},"description":"Send exactly these headers with the PUT, and a body of exactly `size` bytes."},"key":{"type":"string","description":"Object key in the bucket."}},"required":["uploadUrl","publicUrl","expiresAt","method","headers"]}},"required":["success","data"]},"StoryCreateRequest":{"type":"object","properties":{"url":{"type":"string","description":"https URL on an allowed host for `type`, no credentials or custom port. The file is NOT downloaded or inspected.","format":"uri","maxLength":2048},"type":{"type":"string","description":"IMAGE or VIDEO. Decides which host list applies to `url`.","enum":["IMAGE","VIDEO"]}},"required":["url","type"],"x-allowedHosts":{"IMAGE":["cdn.pixplace.space","*.supabase.co","*.supabase.in","pub-7ca8823a8abf4319b8c347e72d913fd7.r2.dev"],"VIDEO":["cdn.pixplace.space","videos.pexels.com","pub-*.r2.dev"]},"description":"IMAGE hosts: cdn.pixplace.space, *.supabase.co, *.supabase.in, pub-7ca8823a8abf4319b8c347e72d913fd7.r2.dev. VIDEO hosts: cdn.pixplace.space, videos.pexels.com, pub-*.r2.dev (`*` matches exactly one DNS label). Anything else is a 400 that lists the allowed hosts. Upload the file with POST /api/v1/uploads/from-url or POST /api/v1/uploads to get a URL on cdn.pixplace.space."},"Story":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string","format":"uri"},"type":{"type":"string","description":"IMAGE or VIDEO. Decides which host list applies to `url`.","enum":["IMAGE","VIDEO"]},"createdAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","description":"createdAt + 24 h.","format":"date-time"}},"required":["id","url","type","createdAt","expiresAt"]},"StoryResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Story"}},"required":["success","data"]},"StoryListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Story"}}},"required":["success","data"]},"CommentAuthor":{"type":"object","properties":{"id":{"type":"string","description":"Account id."},"username":{"type":["string","null"],"description":"Public handle."},"name":{"type":["string","null"],"description":"Display name."},"avatar":{"type":["string","null"],"description":"Avatar URL."}},"required":["id"]},"Comment":{"type":"object","properties":{"id":{"type":"string"},"content":{"type":"string"},"parentId":{"type":["string","null"],"description":"The comment this one answers; null for a top-level comment."},"createdAt":{"type":"string","format":"date-time"},"author":{"$ref":"#/components/schemas/CommentAuthor"},"reactionsCount":{"type":"integer","description":"All reactions together; the kinds are not broken down."}},"required":["id","content","parentId","createdAt","author","reactionsCount"]},"InboxComment":{"allOf":[{"$ref":"#/components/schemas/Comment"},{"type":"object","properties":{"postId":{"type":"string"},"post":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"title":{"type":"string"}},"required":["id","slug","title"]}},"required":["postId","post"]}]},"CommentCreateRequest":{"type":"object","properties":{"content":{"type":"string","description":"Trimmed text.","minLength":1,"maxLength":2000},"parentId":{"type":["string","null"],"description":"Id of a comment of the SAME post (a reply to a reply is fine). null, \"\" or absent = top-level.","maxLength":100}},"required":["content"],"description":"`authorId`, `postId` and other fields are ignored: the author is always the owner of the key."},"CommentListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Comment"}},"nextCursor":{"type":["string","null"],"description":"Pass it back unchanged as `cursor` to get the next page. null on the last page."},"hasMore":{"type":"boolean","description":"false on the last page."}},"required":["success","data","nextCursor","hasMore"]},"InboxResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/InboxComment"}},"nextCursor":{"type":["string","null"],"description":"Pass it back unchanged as `cursor` to get the next page. null on the last page."},"hasMore":{"type":"boolean","description":"false on the last page."}},"required":["success","data","nextCursor","hasMore"]},"CommentResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Comment"}},"required":["success","data"]},"Account":{"type":"object","properties":{"id":{"type":"string"},"username":{"type":["string","null"]},"name":{"type":["string","null"]},"avatar":{"type":["string","null"]},"bio":{"type":["string","null"]},"niche":{"type":["string","null"],"description":"Niche of a content account; null for an ordinary account."},"category":{"type":["string","null"],"description":"Category of a content account; null for an ordinary account."},"createdAt":{"type":"string","format":"date-time"},"counters":{"type":"object","properties":{"posts":{"type":"integer","description":"Posts GET /api/v1/posts lists (drafts included)."},"followers":{"type":"integer"},"following":{"type":"integer"},"storiesActive":{"type":"integer","description":"Stories of the last 24 hours."}},"required":["posts","followers","following","storiesActive"]}},"required":["id","counters"]},"AccountResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/Account"}},"required":["success","data"]},"AccountStats":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"granularity":{"type":"string","enum":["day"]},"from":{"type":"string","format":"date"},"to":{"type":"string","format":"date"},"totals":{"type":"object","properties":{"posts":{"type":"integer"},"followers":{"type":"integer"},"following":{"type":"integer"},"likes":{"type":"integer"},"comments":{"type":"integer"}},"description":"Current numbers of the account."},"period":{"type":"object","properties":{"postsCreated":{"type":"integer"},"likesReceived":{"type":"integer"},"commentsReceived":{"type":"integer"},"newFollowers":{"type":"integer"}},"description":"Sums of `series`."},"series":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","format":"date"},"postsCreated":{"type":"integer"},"likesReceived":{"type":"integer"},"commentsReceived":{"type":"integer"},"newFollowers":{"type":"integer"}},"required":["date","postsCreated","likesReceived","commentsReceived","newFollowers"]},"description":"One entry per UTC day of the range, zeros included."},"unavailable":{"type":"array","items":{"type":"string"},"description":"Metrics the platform does not collect. Absent from the answer, not zero."},"unavailableNote":{"type":"string"}},"required":["from","to","series"]}},"required":["success","data"]},"FollowPerson":{"type":"object","properties":{"id":{"type":"string","description":"Account id."},"username":{"type":["string","null"],"description":"Public handle."},"name":{"type":["string","null"],"description":"Display name."},"avatar":{"type":["string","null"],"description":"Avatar URL."},"followedAt":{"type":"string","description":"When the follow happened.","format":"date-time"}},"required":["id","followedAt"]},"FollowListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/FollowPerson"}},"nextCursor":{"type":["string","null"],"description":"Pass it back unchanged as `cursor` to get the next page. null on the last page."},"hasMore":{"type":"boolean","description":"false on the last page."}},"required":["success","data","nextCursor","hasMore"]},"Notification":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["like","comment","follow","mention","system"]},"title":{"type":"string"},"body":{"type":["string","null"]},"link":{"type":["string","null"],"description":"A path on pixplace.space."},"isRead":{"type":"boolean"},"actorId":{"type":["string","null"]},"postId":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"}},"required":["id","type","title","isRead","createdAt"]},"NotificationListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Notification"}},"nextCursor":{"type":["string","null"],"description":"Pass it back unchanged as `cursor` to get the next page. null on the last page."},"hasMore":{"type":"boolean","description":"false on the last page."},"unreadCount":{"type":"integer","description":"ALL unread notifications of the account, whatever the filter and the page."}},"required":["success","data","nextCursor","hasMore","unreadCount"]},"NotificationsReadRequest":{"oneOf":[{"type":"object","properties":{"ids":{"type":"array","items":{"type":"string","maxLength":100},"minItems":1,"maxItems":100}},"required":["ids"],"additionalProperties":false},{"type":"object","properties":{"all":{"const":true,"type":"boolean"}},"required":["all"],"additionalProperties":false}],"description":"Exactly one of `ids` and `all: true`.","properties":{"ids":{"type":"array","items":{"type":"string","maxLength":100},"minItems":1,"maxItems":100,"description":"Notification ids to mark as read."},"all":{"type":"boolean","description":"true marks every unread notification of the account."}}},"NotificationsReadResponse":{"type":"object","properties":{"success":{"type":"boolean"},"marked":{"type":"integer","description":"How many went from unread to read in this call. A repeat answers 0."}},"required":["success","marked"]},"CategoriesResponse":{"type":"object","properties":{"categories":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"slug":{"type":"string","description":"Use it in `categories` of POST /api/v1/posts."}},"required":["name","slug"]}}},"required":["categories"]},"NichesResponse":{"type":"object","properties":{"niches":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"parent":{"type":["string","null"],"description":"Slug of the group the niche belongs to."},"parentName":{"type":["string","null"]},"accountSlug":{"type":"string","description":"Slug of the content account that publishes this niche."},"postCount":{"type":"integer","description":"Live (published, not hidden) posts in the niche."}},"required":["slug","name","postCount"]}},"groups":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"}},"required":["slug","name"]}}},"required":["niches","groups"]}},"parameters":{"IdempotencyKey":{"name":"Idempotency-Key","in":"header","required":false,"description":"Makes the request safe to retry. 1–128 characters from A–Z a–z 0–9 . _ : - ; anything else is a 400. A repeat from the same account returns the ORIGINAL result with HTTP 200 and `Idempotent-Replayed: true`, and spends no quota. After a 503 or a timeout retry with the SAME key. Keys are scoped to the account.","schema":{"type":"string","pattern":"^[A-Za-z0-9._:-]{1,128}$"},"example":"exec-1001-item-0"},"PostRef":{"name":"id","in":"path","required":true,"description":"The `id` or the `slug` of one of YOUR OWN posts. Someone else's post, a missing one and a post hidden by moderation are all 404 (never 403).","schema":{"type":"string","maxLength":300}},"StoryId":{"name":"id","in":"path","required":true,"description":"Id of one of your own ACTIVE stories (created within the last 24 h).","schema":{"type":"string"}},"CommentId":{"name":"id","in":"path","required":true,"description":"Id of a comment: your own, or one under your own post.","schema":{"type":"string","maxLength":100}},"PageLimit":{"name":"limit","in":"query","required":false,"description":"Page size, 1–100. Anything else is a 400.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},"PageCursor":{"name":"cursor","in":"query","required":false,"description":"The `nextCursor` of the previous page, passed back unchanged. Pagination is by (time, id), not by page number: new items never shift the next page.","schema":{"type":"string"}}},"headers":{"RetryAfter":{"description":"Seconds to wait before retrying. On 429 the time until a slot frees up (posts: until 00:00 UTC for the daily limit); on 503 always 5.","schema":{"type":"integer","minimum":1}},"IdempotentReplayed":{"description":"Always `true`: this answer replays the result of an earlier request with the same Idempotency-Key. Nothing new was created and no quota was spent.","schema":{"type":"string","enum":["true"]}}}}}