Posts

Publish precheck

Dry-run a piece of copy + media per platform and per account, without writing or publishing: text length, media specs, account authorization, 24-hour rate caps, TikTok / YouTube required fields. Same rules as a real publish; only ok=true is worth sending. Manual channels warn but never block.

POST/api/v1/posts/precheck
posts:readread tierread-only

Authorization & guardrails

  • Send Authorization: Bearer <credential>; credentials are issued under Settings → Integrations → Long-lived credentials, see Authentication.
  • The credential needs scope posts:read; the issuer's workspace role must also allow the action.
  • Rate limit: read tier, 60/min per credential; over the cap returns 429 with Retry-After.
  • Idempotency: read endpoint, no Idempotency-Key needed.
  • Read-only: writes nothing and sends nothing out.

Request body (application/json)

platformsstring[] (enum: x · youtube · instagram · tiktok · facebook · threads · douyin · xiaohongshu · wechat_mp)required

Target platforms, at least one.

contentstringrequired

Main copy; may be empty when every platform has a variant.

titlestringoptional

Title (required for YouTube).

variantsobject[] { platform, content?, title? }optional

Per-platform overrides; the check measures override ?? main copy.

targetAccountIdsstring[]optional

Target accounts; omit = all usable accounts per platform, max 20.

mediaobject[] { kind, url, bytes?, durationSec? }optional

kind is image / video; url must be a popkit storage URL.

tiktokOptionsobject { privacyLevel? }optional

privacyLevel must be chosen by a person for TikTok.

threadsOptionsobject { linkAttachment? }optional

A text-only Threads post's link card counts toward the 5-link limit.

Responses

Success is HTTP 200 with a { data, meta } envelope; examples per status are on the right (at the end of the page on narrow screens). Every error is { error: { code, message, params }, meta } — branch on the code, not the message; see Errors.

StatusPossible codes
400invalid_input
401unauthenticated
403forbidden / workspace_not_found
404not_found
429rate_limited
500internal

Examples

Request
curl -X POST "https://popkit.loxily.com/api/v1/posts/precheck" \
  -H "Authorization: Bearer popkit_it_••••••••" \
  -H "Content-Type: application/json" \
  -d '{
  "platforms": [
    "x",
    "youtube"
  ],
  "content": "本周更新速览",
  "title": "本周更新速览",
  "media": [
    {
      "kind": "video",
      "url": "https://storage.googleapis.com/…/weekly.mp4",
      "bytes": 48213000,
      "durationSec": 62
    }
  ]
}'
Response
OK (with a blocker)
{
  "data": {
    "ok": false,
    "platforms": [
      {
        "platform": "x",
        "blocker": null,
        "accounts": [
          {
            "accountId": "acc_01J8XQ5M9V2R",
            "handle": "@popkit",
            "textMax": 280,
            "ok": true,
            "error": null,
            "warning": null
          }
        ],
        "expiredAccounts": []
      },
      {
        "platform": "youtube",
        "blocker": "needs_reauth",
        "accounts": [],
        "expiredAccounts": [
          {
            "accountId": "acc_01J8Z…",
            "handle": "popkit 频道"
          }
        ]
      }
    ]
  },
  "meta": {
    "requestId": "6a1d0c9e-2b7f-4e3a-8c5d-1f0e9b8a7c66"
  }
}