Skip to content

Public API

The Public API provides programmatic access for third-party integrations and automation. It is split into two groups:

  • Public API v1/public/v1/*, authenticated with an API key or OAuth token.
  • Compatibility public routes/public/* outside /public/v1, kept for n8n/Zapier/Make compatibility where noted.

All v1 routes are org-scoped. Mutating routes support idempotency keys, and reads are rate-limited per org.

OpenAPI specification

The full machine-readable spec is committed at openapi.yml in the repository root, and a running instance serves the same document as browsable Swagger UI at /docs.

It is generated from the controllers — request and response schemas are inferred from the TypeScript types — so it tracks the code rather than drifting from it. CI fails the build if the committed file stops matching (.github/workflows/boot-guard.yml).

If you are contributing, do not hand-edit openapi.yml. Change the controllers or DTOs, then:

bash
pnpm run build:backend
pnpm run openapi:generate

Generating constructs the Nest application, so it needs DATABASE_URL, REDIS_URL, and JWT_SECRET in the environment. To improve a route's documentation, add @ApiOperation / @Api*Response decorators or JSDoc to the controller and regenerate.

Authentication

Pass the credential in the Authorization header as a raw string (no Bearer prefix):

http
Authorization: pm_live_xxxxxxxx...

Two credential types are accepted:

TypePrefixWhere to create
API keypm_live_Settings → API Keys
OAuth access tokenpos_OAuth app authorization flow

API keys are per-user, per-org. The resolved org and user's role are attached to the request, so RBAC and billing gates still apply. OAuth tokens are constrained to the scopes the user approved (mcp:read, mcp:posts:write).

On hosted instances with Stripe configured, the org must have an active subscription; otherwise the request returns 401.

Rate limiting

Public v1 routes are rate-limited by API_LIMIT (default 600 requests/hour per org). Sensitive endpoints carry tighter @Throttle overrides, for example:

  • POST /oauth/token — 20/min
  • GET /public/v1/analytics/overview — 60/min
  • POST /public/t — 60/min

Pagination

GET /public/v1/posts returns at most 100 posts per call (also the default page size). The response is always the paged shape { posts, cursor }; use the cursor offset for paging. cursor is null on the last page.

ParamDescription
?limit=1–100; defaults to 100, hard-capped at 100.
?cursor=Opaque offset returned by the previous page.

Idempotency

Mutating v1 endpoints accept an optional Idempotency-Key header. Repeating the same key within 24 hours replays the first response instead of re-running the mutation. Keys are scoped per-org, so the same string from a different org is independent. Supported on:

  • POST /public/v1/posts
  • POST /public/v1/upload
  • POST /public/v1/upload-from-url
  • DELETE /public/v1/posts/:id
  • DELETE /public/v1/posts/group/:group
  • DELETE /public/v1/integrations/:id

If Redis is unavailable the header is ignored and the request proceeds normally. A concurrent duplicate returns 409.

Posts

Base: /public/v1

MethodPathPurpose
POST/public/v1/postsCreate a post
GET/public/v1/postsList posts
DELETE/public/v1/posts/:idDelete a post by post ID (resolves group)
DELETE/public/v1/posts/group/:groupDelete a post by group ID
PUT/public/v1/posts/:id/statusChange post status
PUT/public/v1/posts/:id/release-idUpdate external release ID
GET/public/v1/posts/:id/missingGet missing content to fill for a post
GET/public/v1/find-slot/:idFind next free posting time slot

Creating or scheduling a post validates that every referenced channel is connected and does not need reauthentication. Drafts are allowed on disabled channels so they can be reconnected before promotion.

POST /public/v1/posts is gated on api:create and posts_per_month:create billing policies.

Media

Base: /public/v1

MethodPathPurpose
POST/public/v1/uploadUpload a media file (multipart/form-data, field file)
POST/public/v1/upload-from-urlImport media from a URL
POST/public/v1/generate-videoGenerate AI video
GET/public/v1/generate-video/:idPoll an async video generation job
POST/public/v1/video/functionCall a provider tool, currently only loadVoices

POST /public/v1/generate-video accepts type (text-to-video, image-to-video, video-to-video) and provider params in customParams. Both the POST and the polling GET return the same shape: { id, status, artifactUrl, provider, error }.

  • If the artifact is returned synchronously, id is null, status is completed, and artifactUrl is the URL.
  • If a job is queued, id is the job id and status is pending; poll GET /public/v1/generate-video/:id with it. The poll normalizes any non-terminal provider status to pending.
  • Terminal statuses are completed (with artifactUrl) and failed (with error set to the failure reason).

Integrations

Base: /public/v1

MethodPathPurpose
GET/public/v1/integrationsList connected integrations (filterable by ?group=)
DELETE/public/v1/integrations/:idDelete a channel integration
GET/public/v1/integration-settings/:idGet integration rules, max length, settings schema, tools
GET/public/v1/social/:integrationGet OAuth authorization URL for a provider
POST/public/v1/integration-trigger/:idTrigger a dynamic provider tool
GET/public/v1/groupsList customer groups
GET/public/v1/is-connectedCheck whether the org has any active integration

GET /public/v1/social/:integration requires an explicit provider version:

  • Pass providerId@version as the path param (e.g. x@v1).
  • Or pass ?version=v1 with a bare provider id.
  • A bare id without a version is rejected.
  • An unknown or retired version returns 404 or 410.

Analytics

Base: /public/v1/analytics

The full analytics surface is public — the same routes serve API-key/OAuth clients (throttled 60/min per route, no RBAC/entitlement gate) and the dashboard (session cookie, RBAC + entitlement enforced, x-csrf-token required on mutations). See Analytics API for parameters and response details.

MethodPathPurpose
GET/public/v1/analytics/overviewOrg overview with optional date range
GET/public/v1/analytics/channel/:integrationIdSingle channel analytics
GET/public/v1/analytics/channel/:integrationId/metric/:metricSpecific metric for a channel
GET/public/v1/analytics/campaign/:idCampaign-scoped analytics
GET/public/v1/analytics/postsPaginated post list with metrics
GET/public/v1/analytics/post/:postIdSingle post detail
GET/public/v1/analytics/metric/:metricMetric detail across date range
GET/public/v1/analytics/dayDay-level detail
GET/public/v1/analytics/best-timeBest-time-to-post heatmap
GET/public/v1/analytics/recommendationsAI-powered recommendations
GET/public/v1/analytics/healthData-health panel
POST/public/v1/analytics/refresh/:integrationIdOn-demand live channel refresh (6/hour)
GET/public/v1/analytics/content-insightsContent-attribute intelligence
POST/public/v1/analytics/narrateLLM-narrated summary
GET/public/v1/analytics/exportCSV/JSON export
GET/public/v1/analytics/anomaliesDetected anomalies for the org
POST/public/v1/analytics/anomalies/:id/dismissDismiss an anomaly
GET/POST/PUT/DELETE/public/v1/analytics/alert-rules*User-defined alert rules CRUD
GET/POST/DELETE/public/v1/analytics/shareOrg public share-link management
GET/POST/PUT/DELETE/public/v1/analytics/watchlist*Watched accounts CRUD + /:id/series
GET/public/v1/analytics/shortlinksShort-link aggregate stats
GET/public/v1/analytics/shortlinks/timeseriesShort-link click time series

GET /public/v1/analytics/overview validates from/to, requires to >= from, and caps the window at 400 days.

Notifications

Base: /public/v1

MethodPathPurpose
GET/public/v1/notificationsGet paginated org notifications

Compatibility public routes

Base: /public

MethodPathAuthPurpose
POST/public/tNoneTrack analytics/behaviour event
POST/public/modify-subscriptionJWTModify subscription billing
GET/public/streamNoneProxy-stream an external MP4 (SSRF-safe)

Internal integrations API

These routes sit under /integrations and are authenticated via cookie session. Mutating routes require CSRF protection and the appropriate RBAC permission.

Integration management

MethodPathPermissionPurpose
POST/integrations/provider/:id/connectchannels:createSave a provider page after two-step auth
GET/integrations/:identifier/internal-plugsGet internal plug definitions for a provider
GET/integrations/customersList customer groups
PUT/integrations/:id/groupchannels:updateUpdate integration group assignment
PUT/integrations/:id/customer-namechannels:updateUpdate integration customer name
GET/integrations/listFull integration list with capabilities
POST/integrations/:id/settingschannels:updateUpdate provider additional settings
POST/integrations/:id/nicknamechannels:updateSet nickname and/or avatar
GET/integrations/social/:integrationchannels:createGenerate OAuth authorization URL
POST/integrations/:id/timechannels:updateConfigure posting time slots
POST/integrations/mentionschannels:updateSearch @mentions across providers
POST/integrations/functionchannels:updateCall a dynamic provider function
POST/integrations/disablechannels:updateDisable a channel
POST/integrations/enablechannels:updateEnable a channel
DELETE/integrations/channels:deleteDelete a channel

GET /integrations/social/:integration accepts ?campaign=<uuid> to auto-tag a newly connected channel onto that campaign.

Plugs

MethodPathPermissionPurpose
GET/integrations/plug/listList all available plug definitions
GET/integrations/:id/plugsGet plugs configured for an integration
POST/integrations/:id/plugschannels:createCreate or update plug configuration
PUT/integrations/plugs/:id/activatechannels:updateToggle plug active/inactive

Provider-specific

MethodPathPurpose
GET/integrations/telegram/updatesPoll Telegram bot for connect message
POST/integrations/moltbook/registerRegister a Moltbook agent
GET/integrations/moltbook/statusCheck Moltbook agent claim status

No-auth integration endpoints

Base: /integrations

Used during OAuth callbacks and public provider-page connection.

MethodPathPurpose
GET/integrations/All integration definitions (provider registry)
POST/integrations/social-connect/:integrationOAuth callback handler
POST/integrations/public/provider/:id/connectSave provider page (public, state-gated)
POST/integrations/extension-refreshRefresh Chrome extension cookies

Errors

Common status codes:

  • 400 — Validation error, missing fields, or malformed dates.
  • 401 — Missing or invalid API key/OAuth token, or no active subscription.
  • 403 — Insufficient OAuth scope or RBAC permission.
  • 404 — Unknown resource.
  • 409 — Idempotency conflict.
  • 410 — Requested provider version has been retired.
  • 429 — Rate limit exceeded.

Verified against v1.0.0

The AI-native social media management platform — postmill.ai