REST API
Base URL: https://<your-host>/public/v1 (locally, http://localhost:5000/public/v1).
The paths and bodies follow Postiz’s public API, so most clients written for it only need a new base URL and key. The CLI and MCP server go through the same code, so behaviour is identical everywhere.
Authentication
Send the organization API key on every request, in either form:
Authorization: Bearer <api-key>
Authorization: <api-key>
Keys never go in URLs. Create and rotate them with rustiz org create and
rustiz org rotate-key <org-id> (see CLI).
Rate limits
| Route | Default per hour | Setting |
|---|---|---|
POST /public/v1/posts | 90 per organization | API_LIMIT |
/mcp and every other /public/v1 route | 10,000 per organization | REQUEST_LIMIT |
POST /oauth/authorize, /oauth/register | 30 per client address | fixed |
POST /oauth/token | 120 per client address | fixed |
0 turns a limit off. Counts are kept per process.
Errors
Errors are JSON with an error message. Status codes: 400 bad request, 401
missing or invalid key, 404 not found, 409 the post is being published
right now (retry later), 429 rate limited.
Posts
| Method | Path | Notes |
|---|---|---|
GET | /posts?startDate=&endDate=&customer= | ISO 8601 window; returns { posts: [...] } |
POST | /posts | Create posts (body below). Uses API_LIMIT |
GET | /posts/{id} | One post with its channel |
PUT | /posts/{id} | Edit in place; omitted fields keep their value |
PUT | /posts/{id}/date | { date, publish?, republish? } |
DELETE | /posts/{id} | Deletes the post and the rest of its group |
DELETE | /posts/group/{group} | Deletes a whole group |
GET | /posts/{id}/missing | Recent platform posts, for linking a post whose release id is missing |
PUT | /posts/{id}/release-id | Set the platform post id manually |
GET | /find-slot/{channelId} | Next free posting slot |
Create a scheduled post with a reply:
curl -sS -X POST "$RUSTIZ_URL/public/v1/posts" \
-H "Authorization: Bearer $RUSTIZ_API_KEY" \
-H 'content-type: application/json' \
-d '{
"type": "schedule",
"date": "2030-01-01T09:00:00Z",
"shortLink": false,
"tags": [],
"posts": [{
"integration": { "id": "<channel id>" },
"value": [
{ "content": "<p>We just shipped.</p>", "image": [] },
{ "content": "<p>Docs: https://example.com/docs</p>", "image": [] }
],
"settings": {}
}]
}'
type is draft, schedule or now. value[0] is the post and the other
entries are replies. inter (a number of days) repeats the post. The response
lists { postId, integration, group } for each created post.
Published posts can’t be edited, because platforms keep the original. Use
republish with a date to publish one again. A post in ERROR may already be
live, so check the platform before you retry with publish. Deleting a post
here does not remove it from the platform.
Channels (integrations)
| Method | Path | Notes |
|---|---|---|
GET | /integrations | Connected channels |
DELETE | /integrations/{id} | Disconnect |
GET | /is-connected | Checks the API key |
GET | /providers | Every provider with its connection mode |
GET | /providers/status | Readiness: configured, missing env var names |
POST | /integrations/{provider}/connect | Start a headless connection: { externalUrl?, customFields?, name?, description? } |
GET | /integrations/connect/{connectionId} | Poll a pending connection |
GET | /social/{provider} | Raw OAuth start URL (what Postiz returns) |
GET | /integration-settings/{id} | The channel’s settings schema and rules |
POST | /integrations/{id}/time | Replace posting times |
POST | /integrations/{id}/mentions | Look up mentionable accounts |
A connection either returns { connected: true, ... } or
{ connected: false, pending: true, connectionId, url, message }. Hand the
url to a human, then poll. See the provider overview
for each connection mode.
Media
| Method | Path | Notes |
|---|---|---|
POST | /upload | Multipart, field file (png, jpg, gif, webp, mp4, mov, webm, pdf) |
POST | /upload-from-url | { "url": "https://..." } |
GET | /media?page= | Media library |
GET | /media/{id}/status | Processing state |
DELETE | /media/{id} | Removes it from the library |
The size limit is MAX_UPLOAD_MB (default 1024). The upload rules are in
Self-hosting §5.5.
Analytics and notifications
| Method | Path | Notes |
|---|---|---|
GET | /analytics/{channelId}?date=<days> | Channel analytics |
GET | /analytics/post/{postId}?date=<days> | Post analytics |
GET | /notifications | Recent notifications |
Workspace
| Method | Path |
|---|---|
GET POST PUT | /webhooks |
DELETE | /webhooks/{id} |
POST | /webhooks/send |
GET POST | /tags · PUT DELETE /tags/{id} |
GET POST PUT | /sets · DELETE /sets/{id} |
GET POST | /signatures · GET /signatures/default · PUT DELETE /signatures/{id} |
GET | /customers · PUT /customers/{id} |
Debugging
| Method | Path |
|---|---|
GET | /debug/posts/{id} (timeline of one post) |
GET | /debug/account |
GET | /debug/channels |
GET | /debug/activity |
Outside /public/v1
| Path | Purpose |
|---|---|
GET /health | Returns ok |
/mcp | MCP endpoint (MCP setup) |
GET /integrations/social/{provider} | OAuth callback that platforms redirect to |
/.well-known/oauth-*, /oauth/* | MCP OAuth |
/uploads/* | Local media, when UPLOAD_DIRECTORY is set |