{"openapi":"3.1.0","info":{"title":"Skimbly API","version":"1.0.0","description":"Schedule posts to your connected accounts. Every POST takes an Idempotency-Key header, so retries are safe. Every request needs an API key from Settings, sent as Authorization: Bearer skm_.... A key acts as you, with your plan's limits. 60 requests a minute per key. Docs: https://skimbly.com/api"},"servers":[{"url":"https://skimbly.com/api/v1"}],"security":[{"apiKey":[]}],"paths":{"/me":{"get":{"summary":"Your plan, timezone and this month's usage","operationId":"getMe","responses":{"200":{"description":"You","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"}}}},"401":{"$ref":"#/components/responses/E401"},"429":{"$ref":"#/components/responses/E429"}}}},"/tags":{"get":{"summary":"List your tags","operationId":"listTags","responses":{"200":{"description":"Tags","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"color":{"type":"string"}}}}}}}}},"401":{"$ref":"#/components/responses/E401"},"429":{"$ref":"#/components/responses/E429"}}}},"/accounts":{"get":{"summary":"List connected accounts","operationId":"listAccounts","responses":{"200":{"description":"Accounts","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Account"}}}}}}},"401":{"$ref":"#/components/responses/E401"},"429":{"$ref":"#/components/responses/E429"}}}},"/posts":{"get":{"summary":"List posts","description":"Scheduled posts come soonest first; everything else newest first.","operationId":"listPosts","parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["draft","scheduled","posted","failed"]},"description":"failed includes posts that partly went out."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"next_cursor from the page before."}],"responses":{"200":{"description":"A page of posts","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Post"}},"next_cursor":{"type":["string","null"]}}}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"429":{"$ref":"#/components/responses/E429"}}},"post":{"summary":"Create a post (draft, scheduled, queued or published now)","operationId":"createPost","parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string","maxLength":255},"description":"Any unique string, like a UUID. Sending the request again with the same key returns the first answer (with Idempotent-Replayed: true) instead of doing it twice. Kept for 24 hours."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"text":{"type":"string","description":"The post's text, used on every network that has no network_text."},"account_ids":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Accounts to post to, from GET /accounts."},"mode":{"type":"string","enum":["draft","schedule","queue","publish"],"description":"draft: save without posting. schedule: post at scheduled_at. queue: post at the next free posting time all these accounts share. publish: post now; the answer's sent says posted, failed or sending (still going, read the post again).","default":"draft"},"scheduled_at":{"type":["string","null"],"format":"date-time","description":"When to post (with a UTC offset), at least 2 minutes ahead. Rounded down to the minute. Required for schedule; a draft may keep a time too."},"network_text":{"type":"object","propertyNames":{"enum":["bluesky","linkedin","threads","facebook","instagram","x"]},"additionalProperties":{"type":"string"},"description":"Own text per network, like { \"x\": \"...\" }."},"media":{"type":"array","maxItems":10,"items":{"type":"object","required":["id"],"properties":{"id":{"type":"string","format":"uuid"},"alt":{"type":"string","maxLength":1000}}},"description":"Images (up to 10, by network limits) or one video, from POST /media or /media/uploads."},"tag_ids":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Your tags, from GET /tags."},"repeat":{"type":["string","null"],"enum":["day","2days","3days","week","2weeks","month",null],"description":"Post again on this rhythm (schedule or queue only). null stops it."},"network_settings":{"type":"object","description":"Options per network, like { \"threads\": { \"replies\": \"following\" } }.","properties":{"bluesky":{"type":"object","additionalProperties":false,"properties":{"replies":{"enum":["everyone","following","mentioned","nobody"],"default":"everyone","description":"Who can reply"}}},"linkedin":{"type":"object","additionalProperties":false,"properties":{"visibility":{"enum":["anyone","connections"],"default":"anyone","description":"Who can see it"}}},"threads":{"type":"object","additionalProperties":false,"properties":{"replies":{"enum":["everyone","following","mentioned"],"default":"everyone","description":"Who can reply"}}},"x":{"type":"object","additionalProperties":false,"properties":{"replies":{"enum":["everyone","following","mentioned"],"default":"everyone","description":"Who can reply"}}}},"additionalProperties":false},"follow_ups":{"type":"array","maxItems":10,"items":{"type":"object","required":["text","delay_minutes"],"properties":{"text":{"type":"string"},"delay_minutes":{"type":"integer","enum":[0,1,5,15,60]}}},"description":"Replies posted under the post (not on LinkedIn or Facebook)."}}}}}},"responses":{"201":{"description":"The post","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Post"}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"409":{"$ref":"#/components/responses/E409"},"413":{"$ref":"#/components/responses/E413"},"415":{"$ref":"#/components/responses/E415"},"422":{"$ref":"#/components/responses/E422"},"429":{"$ref":"#/components/responses/E429"}}}},"/posts/{id}":{"parameters":[{"name":"id","in":"path","required":true,"description":"The post id.","schema":{"type":"string","format":"uuid"}}],"get":{"summary":"Get a post, with each destination's status, link and stats","operationId":"getPost","responses":{"200":{"description":"The post","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Post"}}}},"401":{"$ref":"#/components/responses/E401"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"}}},"patch":{"summary":"Change or reschedule a post","description":"Send only what changes; the rest stays. Drafts, scheduled and failed posts can change. To reschedule, send scheduled_at; to queue again, send mode: queue.","operationId":"updatePost","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"text":{"type":"string","description":"The post's text, used on every network that has no network_text."},"account_ids":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Accounts to post to, from GET /accounts."},"mode":{"type":"string","enum":["draft","schedule","queue","publish"],"description":"draft: save without posting. schedule: post at scheduled_at. queue: post at the next free posting time all these accounts share. publish: post now; the answer's sent says posted, failed or sending (still going, read the post again)."},"scheduled_at":{"type":["string","null"],"format":"date-time","description":"When to post (with a UTC offset), at least 2 minutes ahead. Rounded down to the minute. Required for schedule; a draft may keep a time too."},"network_text":{"type":"object","propertyNames":{"enum":["bluesky","linkedin","threads","facebook","instagram","x"]},"additionalProperties":{"type":"string"},"description":"Own text per network, like { \"x\": \"...\" }."},"media":{"type":"array","maxItems":10,"items":{"type":"object","required":["id"],"properties":{"id":{"type":"string","format":"uuid"},"alt":{"type":"string","maxLength":1000}}},"description":"Images (up to 10, by network limits) or one video, from POST /media or /media/uploads."},"tag_ids":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Your tags, from GET /tags."},"repeat":{"type":["string","null"],"enum":["day","2days","3days","week","2weeks","month",null],"description":"Post again on this rhythm (schedule or queue only). null stops it."},"network_settings":{"type":"object","description":"Options per network, like { \"threads\": { \"replies\": \"following\" } }.","properties":{"bluesky":{"type":"object","additionalProperties":false,"properties":{"replies":{"enum":["everyone","following","mentioned","nobody"],"default":"everyone","description":"Who can reply"}}},"linkedin":{"type":"object","additionalProperties":false,"properties":{"visibility":{"enum":["anyone","connections"],"default":"anyone","description":"Who can see it"}}},"threads":{"type":"object","additionalProperties":false,"properties":{"replies":{"enum":["everyone","following","mentioned"],"default":"everyone","description":"Who can reply"}}},"x":{"type":"object","additionalProperties":false,"properties":{"replies":{"enum":["everyone","following","mentioned"],"default":"everyone","description":"Who can reply"}}}},"additionalProperties":false},"follow_ups":{"type":"array","maxItems":10,"items":{"type":"object","required":["text","delay_minutes"],"properties":{"text":{"type":"string"},"delay_minutes":{"type":"integer","enum":[0,1,5,15,60]}}},"description":"Replies posted under the post (not on LinkedIn or Facebook)."}}}}}},"responses":{"200":{"description":"The post","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Post"}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"404":{"$ref":"#/components/responses/E404"},"409":{"$ref":"#/components/responses/E409"},"413":{"$ref":"#/components/responses/E413"},"415":{"$ref":"#/components/responses/E415"},"429":{"$ref":"#/components/responses/E429"}}},"delete":{"summary":"Delete a post","description":"Posts already published stay on the networks.","operationId":"deletePost","responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"deleted":{"type":"boolean"}}}}}},"401":{"$ref":"#/components/responses/E401"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"}}}},"/media":{"post":{"summary":"Add an image from a link","description":"Skimbly downloads the image (JPEG, PNG, WebP or GIF, up to 10 MB). Media not used in a post within a day is removed.","operationId":"addMediaFromUrl","parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string","maxLength":255},"description":"Any unique string, like a UUID. Sending the request again with the same key returns the first answer (with Idempotent-Replayed: true) instead of doing it twice. Kept for 24 hours."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri"}}}}}},"responses":{"201":{"description":"The image","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Media"}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"413":{"$ref":"#/components/responses/E413"},"415":{"$ref":"#/components/responses/E415"},"429":{"$ref":"#/components/responses/E429"}}}},"/media/uploads":{"post":{"summary":"Start an upload of an image or video file","description":"Returns presigned links valid for an hour. Image: PUT the file to upload_url. Video: PUT each part_size slice to its part_urls entry (in order) and keep each answer's ETag header; optionally PUT a JPEG frame under 1 MB to thumbnail_url. Then call /media/{id}/complete. Images up to 10 MB, videos up to 200 MB.","operationId":"startUpload","parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string","maxLength":255},"description":"Any unique string, like a UUID. Sending the request again with the same key returns the first answer (with Idempotent-Replayed: true) instead of doing it twice. Kept for 24 hours."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"type":"object","required":["kind","name","type","size"],"properties":{"kind":{"const":"image"},"name":{"type":"string"},"type":{"enum":["image/png","image/jpeg","image/webp","image/gif"]},"size":{"type":"integer","description":"Bytes"},"width":{"type":"integer"},"height":{"type":"integer"}}},{"type":"object","required":["kind","name","type","size","width","height","duration"],"properties":{"kind":{"const":"video"},"name":{"type":"string"},"type":{"enum":["video/mp4","video/quicktime"]},"size":{"type":"integer","description":"Bytes"},"width":{"type":"integer"},"height":{"type":"integer"},"duration":{"type":"number","description":"Seconds"}}}]}}}},"responses":{"201":{"description":"Where to upload","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string"},"upload_url":{"type":"string"},"part_size":{"type":"integer"},"part_urls":{"type":"array","items":{"type":"string"}},"thumbnail_url":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"413":{"$ref":"#/components/responses/E413"},"415":{"$ref":"#/components/responses/E415"},"429":{"$ref":"#/components/responses/E429"}}}},"/media/{id}/complete":{"parameters":[{"name":"id","in":"path","required":true,"description":"The upload id.","schema":{"type":"string","format":"uuid"}}],"post":{"summary":"Finish an upload","operationId":"completeUpload","parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string","maxLength":255},"description":"Any unique string, like a UUID. Sending the request again with the same key returns the first answer (with Idempotent-Replayed: true) instead of doing it twice. Kept for 24 hours."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"parts":{"type":"array","description":"Video only.","items":{"type":"object","required":["part_number","etag"],"properties":{"part_number":{"type":"integer","minimum":1},"etag":{"type":"string"}}}}}}}}},"responses":{"200":{"description":"The media, ready to use","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Media"}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"404":{"$ref":"#/components/responses/E404"},"409":{"$ref":"#/components/responses/E409"},"413":{"$ref":"#/components/responses/E413"},"415":{"$ref":"#/components/responses/E415"},"429":{"$ref":"#/components/responses/E429"}}}}},"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","description":"An API key from Settings, API keys."}},"responses":{"E400":{"description":"The request or the post is not valid. `details` names each field and what is wrong.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E401":{"description":"No API key, or the key is not valid (it may have been revoked).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E404":{"description":"Nothing with this id, or it is not yours.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E409":{"description":"The post has started going out, or is already out, so it cannot change; or a request with the same Idempotency-Key is still running.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E413":{"description":"The body is over 256 KB.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E415":{"description":"The body is not sent as application/json.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E422":{"description":"This Idempotency-Key was used for a different request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"E429":{"description":"Over 60 requests a minute for this key. Wait and try again (see Retry-After).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"object","additionalProperties":{"type":"string"}}}}}},"Me":{"type":"object","properties":{"plan":{"type":"string"},"time_zone":{"type":"string"},"usage":{"type":"object","additionalProperties":{"type":"object","properties":{"used":{"type":"integer"},"limit":{"type":"integer"}}}},"rate_limit_per_minute":{"type":"integer"}}},"Account":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"network":{"enum":["bluesky","linkedin","threads","facebook","instagram","x"]},"handle":{"type":"string"},"name":{"type":"string"},"avatar_url":{"type":["string","null"]},"needs_reconnect":{"type":"boolean","description":"True when its access expired; posts to it fail until it is reconnected in Skimbly."}}},"Media":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"enum":["image","video"]},"name":{"type":"string"},"type":{"type":"string"},"size":{"type":"integer"},"width":{"type":["integer","null"]},"height":{"type":["integer","null"]},"duration":{"type":["number","null"]},"status":{"enum":["pending","ready"]}}},"Post":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"enum":["draft","scheduled","publishing","posted","partial","failed"]},"text":{"type":"string"},"network_text":{"type":"object","additionalProperties":{"type":"string"}},"scheduled_at":{"type":["string","null"],"format":"date-time"},"repeat":{"type":["string","null"]},"tag_ids":{"type":"array","items":{"type":"string"}},"network_settings":{"type":"object"},"sent":{"enum":["posted","failed","sending"],"description":"Only after mode publish."},"sent_errors":{"type":"array","items":{"type":"string"},"description":"Only after mode publish: why a network did not take it."},"media":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string"},"url":{"type":"string","description":"A link valid for an hour."},"alt":{"type":"string"}}}},"follow_ups":{"type":"array","items":{"type":"object","properties":{"text":{"type":"string"},"delay_minutes":{"type":"integer"}}}},"destinations":{"type":"array","items":{"type":"object","properties":{"account_id":{"type":["string","null"]},"network":{"enum":["bluesky","linkedin","threads","facebook","instagram","x"]},"status":{"type":"string"},"error":{"type":["string","null"]},"url":{"type":["string","null"],"description":"The live post, once published."},"stats":{"type":["object","null"],"description":"Likes, replies and the rest, where the network gives them."}}}},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"app_url":{"type":"string","description":"The post in Skimbly."}}}}}}