{"openapi":"3.1.0","info":{"title":"eksis API","version":"1.0.0","description":"Schedule and publish social posts, read your connected channels, upload media, and answer\ncomments — from your own code.\n\n## Authenticating\n\nEvery request carries an API key in the `Authorization` header:\n\n```\nAuthorization: Bearer eksis_sk_...\n```\n\nCreate a key in **Settings → API** inside the workspace it should reach. A key belongs to one\nworkspace and cannot be pointed at another, so the workspace is never part of a request.\n\nKeys are shown once, at creation. eksis stores only a hash, so a key that is lost is replaced,\nnot recovered. Treat one like a password: server-side only, never in a browser, an app bundle, or\na repository.\n\n## Roles\n\nA key carries a role — `viewer`, `contributor`, `editor`, or `admin` — and can never be\ngiven more access than the person who created it has. Pick the smallest one that does the job: a\nkey that only reads analytics has no business being able to publish.\n\n## Rate limits\n\nQuotas are counted per workspace per day, shared by every key it has.\n\n| Plan | Keys | Requests / day |\n|---|---|---|\n| Free | — | no API access |\n| Starter | 3 | 1,000 |\n| Premium | 10 | 10,000 |\n| Agency | 30 | 50,000 |\n\nEvery response carries `x-ratelimit-limit` and `x-ratelimit-remaining`. Once the quota is gone\nthe API answers `429` with a `retry-after` header in seconds.\n\n## Errors\n\nFailures are always JSON, always under an `error` key, and always carry a stable `code`.\nBranch on `code`, never on `message` — messages are written for people and get reworded.\n\n## Pagination\n\nCollections return `data` and `nextCursor`. Pass `nextCursor` back as `cursor` to get the\nnext page; `null` means you have reached the end. Cursors are timestamps of the last row, so a\npage never skips or repeats a row when new ones arrive mid-walk.\n\n## Versioning\n\nThe version is in the path. Breaking changes arrive as `/v2`; `v1` keeps working.\nNew optional fields can appear in a response at any time, so parse tolerantly.","contact":{"name":"eksis support","email":"admin@eksis.io"}},"servers":[{"url":"https://api.eksis.io","description":"Production"}],"security":[{"apiKey":[]}],"tags":[{"name":"Account","description":"What this key can reach."},{"name":"Channels","description":"The social accounts connected to the workspace."},{"name":"Posts","description":"Draft, schedule, publish, and inspect posts."},{"name":"Media","description":"Upload images and video for posts to use."},{"name":"Comments","description":"Read and answer comments from the inbox."}],"paths":{"/v1/me":{"get":{"tags":["Account"],"summary":"Describe the key and its workspace","description":"The cheapest call that proves a key is alive and shows what it points at.","responses":{"200":{"description":"The workspace, the key, and its quota.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"workspace":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"timezone":{"type":"string","description":"IANA name. Queue slots resolve against it."},"plan":{"type":"string","enum":["free","starter","pro","agency"]}}},"key":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"prefix":{"type":"string"},"role":{"type":"string","enum":["viewer","contributor","editor","admin"]}}},"limits":{"type":"object","properties":{"requestsPerDay":{"type":"integer"}}}}}}}}}},"401":{"description":"The API key is missing, revoked, expired, or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"The workspace moved to a plan that does not include the API.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key’s role does not allow this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The body did not validate.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"The workspace used up its daily quota. See `retry-after`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/channels":{"get":{"tags":["Channels"],"summary":"List connected channels","description":"Every connected social account, with the health of its connection. A channel whose `status` is not `active` will hold anything scheduled to it until it is reconnected in the app.","parameters":[{"name":"includeDisconnected","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]},"description":"Include channels that were disconnected. Off by default."}],"responses":{"200":{"description":"The channels of this workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"platform":{"type":"string","enum":["instagram","facebook","youtube","threads","tiktok","linkedin","x","bluesky","pinterest","google_business","shopee"]},"username":{"type":"string"},"displayName":{"type":"string"},"avatarUrl":{"type":["string","null"]},"status":{"type":"string","enum":["active","needs_reconnect","disconnected","error"]},"statusReason":{"type":["string","null"]},"followerCount":{"type":["integer","null"]},"connectedAt":{"type":["string","null"],"format":"date-time"}}}}}}}}},"401":{"description":"The API key is missing, revoked, expired, or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"The workspace moved to a plan that does not include the API.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key’s role does not allow this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The body did not validate.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"The workspace used up its daily quota. See `retry-after`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/posts":{"get":{"tags":["Posts"],"summary":"List posts","description":"Newest first, by creation time.","parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["all","draft","pending_approval","scheduled","publishing","published","failed","partial"]},"description":"Keep only posts in this state."},{"name":"channels","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated channel ids. Keeps posts aimed at any of them."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Rows per page. Values above 100 are clamped to 100."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"The `nextCursor` from the previous page, unchanged."}],"responses":{"200":{"description":"One page of posts.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":["string","null"],"description":"Internal label. Never published."},"status":{"type":"string","enum":["draft","pending_approval","scheduled","publishing","published","failed","partial"]},"caption":{"type":"string","description":"Base caption. A target may override it with its own."},"scheduledAt":{"type":["string","null"],"format":"date-time"},"publishedAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"channels":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"platform":{"type":"string"},"username":{"type":"string"}}}}}}},"nextCursor":{"type":["string","null"],"format":"date-time","description":"Pass back as `cursor` for the next page. `null` means this was the last page."}}}}}},"401":{"description":"The API key is missing, revoked, expired, or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"The workspace moved to a plan that does not include the API.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key’s role does not allow this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The body did not validate.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"The workspace used up its daily quota. See `retry-after`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Posts"],"summary":"Create a post","description":"One endpoint covers drafts, schedules, the queue, and publishing now — `mode` is what differs. Anything but `draft` is refused while a target still has a blocking validation error, and the offending checks come back in `error.details.validations`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["targets"],"properties":{"title":{"type":["string","null"],"maxLength":120,"description":"Internal label, never published."},"baseCaption":{"type":"string","maxLength":63206,"description":"Used by every target that has no caption of its own."},"baseMediaIds":{"type":"array","maxItems":10,"items":{"type":"string"},"description":"Media ids from `POST /v1/media/uploads`. Used by targets with an empty `mediaIds`."},"targets":{"type":"array","minItems":1,"description":"One entry per destination channel. A post always has at least one.","items":{"type":"object","required":["socialAccountId","contentType"],"properties":{"socialAccountId":{"type":"string","description":"Channel id from `GET /v1/channels`."},"contentType":{"type":"string","enum":["feed","photo","post","text","carousel","reels","video","short","story"]},"caption":{"type":["string","null"],"description":"Overrides `baseCaption` for this channel only."},"mediaIds":{"type":"array","maxItems":10,"items":{"type":"string"}},"firstComment":{"type":["string","null"],"maxLength":2200},"settings":{"type":"object","description":"Platform-specific settings, e.g. YouTube privacy or TikTok disclosure."}}}},"scheduledAt":{"type":["string","null"],"format":"date-time","description":"Required when `mode` is `schedule`. Interpreted as an absolute instant, so send an offset."},"mode":{"type":"string","enum":["draft","schedule","now","queue"],"default":"draft","description":"`draft` saves without publishing. `schedule` needs `scheduledAt`. `queue` takes the next free slot from the channel queue. `now` publishes immediately."}}}}}},"responses":{"201":{"description":"The post was created.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"},"scheduledAt":{"type":["string","null"],"format":"date-time"}}}}}}}},"401":{"description":"The API key is missing, revoked, expired, or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"The workspace moved to a plan that does not include the API.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key’s role does not allow this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The body did not validate.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"The workspace used up its daily quota. See `retry-after`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/posts/{postId}":{"parameters":[{"name":"postId","in":"path","required":true,"schema":{"type":"string"}}],"get":{"tags":["Posts"],"summary":"Read one post","description":"Includes every target with its own status, permalink, and failure — this is how you learn whether publishing worked.","responses":{"200":{"description":"The post and its targets.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":["string","null"]},"status":{"type":"string"},"caption":{"type":"string"},"mediaIds":{"type":"array","items":{"type":"string"}},"scheduledAt":{"type":["string","null"],"format":"date-time"},"publishedAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"targets":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"channelId":{"type":"string"},"platform":{"type":"string"},"username":{"type":"string"},"contentType":{"type":"string","enum":["feed","photo","post","text","carousel","reels","video","short","story"]},"caption":{"type":["string","null"],"description":"`null` means the base caption is used."},"mediaIds":{"type":"array","items":{"type":"string"}},"firstComment":{"type":["string","null"]},"settings":{"type":"object","description":"Platform-specific settings. See the per-platform notes."},"status":{"type":"string","enum":["pending","queued","publishing","published","failed","held","skipped"]},"externalPostId":{"type":["string","null"]},"permalink":{"type":["string","null"]},"error":{"type":["object","null"],"properties":{"code":{"type":"string"},"message":{"type":["string","null"]}}},"publishedAt":{"type":["string","null"],"format":"date-time"}}}}}}}}}}},"401":{"description":"The API key is missing, revoked, expired, or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"The workspace moved to a plan that does not include the API.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key’s role does not allow this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such row in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The body did not validate.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"The workspace used up its daily quota. See `retry-after`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Posts"],"summary":"Replace a post","description":"The body is the whole post, not a partial patch: targets you leave out are removed.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["targets"],"properties":{"title":{"type":["string","null"],"maxLength":120,"description":"Internal label, never published."},"baseCaption":{"type":"string","maxLength":63206,"description":"Used by every target that has no caption of its own."},"baseMediaIds":{"type":"array","maxItems":10,"items":{"type":"string"},"description":"Media ids from `POST /v1/media/uploads`. Used by targets with an empty `mediaIds`."},"targets":{"type":"array","minItems":1,"description":"One entry per destination channel. A post always has at least one.","items":{"type":"object","required":["socialAccountId","contentType"],"properties":{"socialAccountId":{"type":"string","description":"Channel id from `GET /v1/channels`."},"contentType":{"type":"string","enum":["feed","photo","post","text","carousel","reels","video","short","story"]},"caption":{"type":["string","null"],"description":"Overrides `baseCaption` for this channel only."},"mediaIds":{"type":"array","maxItems":10,"items":{"type":"string"}},"firstComment":{"type":["string","null"],"maxLength":2200},"settings":{"type":"object","description":"Platform-specific settings, e.g. YouTube privacy or TikTok disclosure."}}}},"scheduledAt":{"type":["string","null"],"format":"date-time","description":"Required when `mode` is `schedule`. Interpreted as an absolute instant, so send an offset."},"mode":{"type":"string","enum":["draft","schedule","now","queue"],"default":"draft","description":"`draft` saves without publishing. `schedule` needs `scheduledAt`. `queue` takes the next free slot from the channel queue. `now` publishes immediately."}}}}}},"responses":{"200":{"description":"The post was replaced.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"},"scheduledAt":{"type":["string","null"],"format":"date-time"}}}}}}}},"401":{"description":"The API key is missing, revoked, expired, or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"The workspace moved to a plan that does not include the API.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key’s role does not allow this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such row in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The body did not validate.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"The workspace used up its daily quota. See `retry-after`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Posts"],"summary":"Delete a post","description":"Only before it goes out. A published post lives on the platform, and eksis will not pretend otherwise.","responses":{"200":{"description":"The post was deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"deleted":{"type":"boolean"}}}}}}}},"401":{"description":"The API key is missing, revoked, expired, or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"The workspace moved to a plan that does not include the API.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key’s role does not allow this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such row in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The post is already published.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The body did not validate.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"The workspace used up its daily quota. See `retry-after`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/posts/{postId}/publish":{"parameters":[{"name":"postId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"tags":["Posts"],"summary":"Publish now","description":"Queues every target that has not gone out yet and returns immediately — it does not wait for the platforms. Poll `GET /v1/posts/{postId}` to see how each target ended up.","responses":{"200":{"description":"Publishing was queued.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"}}}}}}}},"401":{"description":"The API key is missing, revoked, expired, or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"The workspace moved to a plan that does not include the API.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key’s role does not allow this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such row in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The post is already published.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The body did not validate.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"The workspace used up its daily quota. See `retry-after`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/media":{"get":{"tags":["Media"],"summary":"List media","parameters":[{"name":"type","in":"query","required":false,"schema":{"type":"string","enum":["image","video"]}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Rows per page. Values above 100 are clamped to 100."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"The `nextCursor` from the previous page, unchanged."}],"responses":{"200":{"description":"One page of media.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Media"}},"nextCursor":{"type":["string","null"],"format":"date-time","description":"Pass back as `cursor` for the next page. `null` means this was the last page."}}}}}},"401":{"description":"The API key is missing, revoked, expired, or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"The workspace moved to a plan that does not include the API.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key’s role does not allow this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The body did not validate.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"The workspace used up its daily quota. See `retry-after`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/media/uploads":{"post":{"tags":["Media"],"summary":"Start an upload","description":"Uploading takes two steps. This one reserves the media id and hands back a pre-signed URL; you then PUT the bytes straight to storage and call `complete`. The file never passes through the API, so a large video does not sit in an API instance’s memory.\n\nAccepted types: JPEG, PNG, WebP, HEIC, MP4, QuickTime, WebM.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["filename","mime","size"],"properties":{"filename":{"type":"string","maxLength":255},"mime":{"type":"string","example":"image/jpeg"},"size":{"type":"integer","minimum":1,"description":"Bytes. Checked against the plan’s storage quota."},"folderId":{"type":["string","null"]}}}}}},"responses":{"201":{"description":"Upload where `uploadUrl` says, with the headers given, then call `complete`.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"mediaId":{"type":"string"},"uploadUrl":{"type":"string","format":"uri"},"method":{"type":"string","enum":["PUT","POST"]},"headers":{"type":"object","additionalProperties":{"type":"string"}},"url":{"type":"string","format":"uri","description":"Where the file will be publicly readable."}}}}}}}},"401":{"description":"The API key is missing, revoked, expired, or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"The workspace moved to a plan that does not include the API.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key’s role does not allow this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The body did not validate.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"The workspace used up its daily quota. See `retry-after`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/media/{mediaId}/complete":{"parameters":[{"name":"mediaId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"tags":["Media"],"summary":"Finish an upload","description":"Marks the media ready so a post may use it. Send the dimensions if you know them — several platforms reject media whose aspect ratio they cannot check ahead of time.","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"width":{"type":"integer","minimum":1},"height":{"type":"integer","minimum":1},"durationMs":{"type":"integer","minimum":0,"description":"Video only."}}}}}},"responses":{"200":{"description":"The media is ready.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Media"}}}}}},"401":{"description":"The API key is missing, revoked, expired, or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"The workspace moved to a plan that does not include the API.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key’s role does not allow this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such row in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The body did not validate.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"The workspace used up its daily quota. See `retry-after`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/comments":{"get":{"tags":["Comments"],"summary":"List comments","description":"Comments left by other people on your posts, newest first. Your own comments are not included.","parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["all","open","assigned","done"]}},{"name":"channels","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated channel ids."},{"name":"q","in":"query","required":false,"schema":{"type":"string"},"description":"Case-insensitive substring of the comment text."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Rows per page. Values above 100 are clamped to 100."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"The `nextCursor` from the previous page, unchanged."}],"responses":{"200":{"description":"One page of comments.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"text":{"type":"string"},"status":{"type":"string","enum":["open","assigned","done"]},"isHidden":{"type":"boolean"},"channelId":{"type":"string"},"platform":{"type":"string"},"externalPostId":{"type":["string","null"],"description":"The post id on the platform, not an eksis id."},"authorUsername":{"type":["string","null"]},"authorName":{"type":["string","null"]},"createdAt":{"type":["string","null"],"format":"date-time"}}}},"nextCursor":{"type":["string","null"],"format":"date-time","description":"Pass back as `cursor` for the next page. `null` means this was the last page."}}}}}},"401":{"description":"The API key is missing, revoked, expired, or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"The workspace moved to a plan that does not include the API.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key’s role does not allow this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The body did not validate.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"The workspace used up its daily quota. See `retry-after`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/comments/{commentId}/reply":{"parameters":[{"name":"commentId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"tags":["Comments"],"summary":"Reply to a comment","description":"Sends the reply to the platform right away and marks the comment done. Unlike publishing, this one does wait: a failure here comes back as a `platform` error rather than as a status to poll for.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["text"],"properties":{"text":{"type":"string","minLength":1,"maxLength":2200}}}}}},"responses":{"200":{"description":"The reply was sent.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"}}}}}}}},"401":{"description":"The API key is missing, revoked, expired, or unknown.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"The workspace moved to a plan that does not include the API.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key’s role does not allow this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such row in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The body did not validate.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"The workspace used up its daily quota. See `retry-after`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"The platform rejected the reply.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","description":"Send your key as `Authorization: Bearer eksis_sk_...`."}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","kind","message"],"properties":{"code":{"type":"string","description":"Stable machine-readable code, e.g. `post.not_found`."},"kind":{"type":"string","enum":["validation","permission","not_found","conflict","limit","platform","internal"],"description":"Broad family of the failure. Use it to decide whether retrying can help."},"message":{"type":"string","description":"One sentence describing what happened."},"hint":{"type":"string","description":"What to do next, when there is something useful to say."},"details":{"description":"Extra context. Shape depends on `code`."}}}}},"Channel":{"type":"object","properties":{"id":{"type":"string"},"platform":{"type":"string","enum":["instagram","facebook","youtube","threads","tiktok","linkedin","x","bluesky","pinterest","google_business","shopee"]},"username":{"type":"string"},"displayName":{"type":"string"},"avatarUrl":{"type":["string","null"]},"status":{"type":"string","enum":["active","needs_reconnect","disconnected","error"]},"statusReason":{"type":["string","null"]},"followerCount":{"type":["integer","null"]},"connectedAt":{"type":["string","null"],"format":"date-time"}}},"Post":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":["string","null"],"description":"Internal label. Never published."},"status":{"type":"string","enum":["draft","pending_approval","scheduled","publishing","published","failed","partial"]},"caption":{"type":"string","description":"Base caption. A target may override it with its own."},"scheduledAt":{"type":["string","null"],"format":"date-time"},"publishedAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"channels":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"platform":{"type":"string"},"username":{"type":"string"}}}}}},"PostTarget":{"type":"object","properties":{"id":{"type":"string"},"channelId":{"type":"string"},"platform":{"type":"string"},"username":{"type":"string"},"contentType":{"type":"string","enum":["feed","photo","post","text","carousel","reels","video","short","story"]},"caption":{"type":["string","null"],"description":"`null` means the base caption is used."},"mediaIds":{"type":"array","items":{"type":"string"}},"firstComment":{"type":["string","null"]},"settings":{"type":"object","description":"Platform-specific settings. See the per-platform notes."},"status":{"type":"string","enum":["pending","queued","publishing","published","failed","held","skipped"]},"externalPostId":{"type":["string","null"]},"permalink":{"type":["string","null"]},"error":{"type":["object","null"],"properties":{"code":{"type":"string"},"message":{"type":["string","null"]}}},"publishedAt":{"type":["string","null"],"format":"date-time"}}},"Media":{"type":"object","properties":{"id":{"type":"string"},"filename":{"type":"string"},"url":{"type":"string","format":"uri"},"kind":{"type":"string","enum":["image","video"]},"mime":{"type":"string"},"size":{"type":"integer"},"width":{"type":["integer","null"]},"height":{"type":["integer","null"]},"durationMs":{"type":["integer","null"]},"status":{"type":"string","enum":["uploading","ready","failed"]},"createdAt":{"type":["string","null"],"format":"date-time"}}}}}}