Post Engineer API ================================================================================ Base URL: https://post-engineer.com Development URL: http://localhost:3434 OpenAPI spec: https://post-engineer.com/openapi.json MCP server: npx -y post-engineer-mcp@latest (env POST_ENGINEER_API_KEY) The OpenAPI spec lists every endpoint below. It is generated from the MCP parity mapping (apps/mcp/src/__tests__/parity-endpoint-tools.json) by `node apps/web/scripts/generate-openapi.mjs`, with request and response schemas from apps/web/scripts/openapi-schemas.mjs. Some nested items (social accounts, metrics rows, generation lists) are typed as free-form objects. ================================================================================ AUTHENTICATION ================================================================================ Create an API key in the dashboard (https://post-engineer.com/recipes) or through POST /api/api-keys (web session only). Keys start with `pe_live_` and are shown once. Send the key on every request, either way: Authorization: Bearer pe_live_xxxxxxxx X-API-Key: pe_live_xxxxxxxx A key can be limited to specific personas. A missing key returns 401 "Authentication required."; an invalid key returns 401 "Invalid API key.". ================================================================================ RESPONSES AND ERRORS ================================================================================ - JSON bodies. Failures carry success:false and an error message. - Most routes return a flat { "success", ... } payload. Only the two engine proxies, GET /api/persona/video-status/{taskId} and DELETE /api/persona/video-task/{taskId}, return the engine envelope { "status", "message", "body" }: the payload is `body`, never `data`. - 400 invalid, over-length or conflicting input (nothing is truncated or coerced silently). POST /api/videos/generate-and-schedule lists every problem in one response: `code`, `error` and `field` describe the first one, and `errors` (an array of { code, message, field }) holds at most 20 of them. 401 bad key. 402 not enough tokens. 404 unknown id. 409 conflict (e.g. the persona already has an active schedule). 410 gone: terminal, stop polling. 429 rate limited: retry with backoff. 5xx transient: retry with backoff. Each operation's statuses are in the spec. - Upload, destructive and fan-out routes are rate limited per caller. ================================================================================ VIDEOS (cost prepaid tokens: faceless 1, ok 2, very_good 3) ================================================================================ Check the balance first: GET /api/billing/tokens. 1. POST /api/videos/validate-script mechanical validation, spends no tokens 2. POST /api/videos/score-draft mechanical score + publish check, no tokens 3. POST /api/videos/generate-and-schedule One call generates the video, schedules it and auto-publishes it. There are no orphan videos. Script is segments: hook first, body, CTA last, 60-200 words total. Slot is 3h to 30d ahead, or mode "asap". 4. GET /api/persona/video-status/{taskId} task state state: -1 failed, 1 complete, 3 queued, 4 processing. Only -1 and 1 are terminal. HTTP 200 does not mean the job is alive: read `state`. 410 Gone is terminal too (the engine lost the task): stop polling and read GET /api/schedule/slots/{slotId} to see if the video was delivered or failed and refunded. 5. DELETE /api/persona/video-task/{taskId} cancel a task Jobs stuck for several days are refunded automatically. ================================================================================ ENDPOINTS (all require an API key) ================================================================================ METHOD PATH OPERATION -------------------------------------------------------------------------------- POST /api/videos/validate-script validate script POST /api/videos/score-draft score draft POST /api/videos/generate-and-schedule generate persona video POST /api/videos/batch-discount apply batch discount GET /api/persona/video-status/{taskId} get video status DELETE /api/persona/video-task/{taskId} cancel video task GET /api/persona/video-generations list video generations GET /api/persona/video-generations/{generationId} get video generation POST /api/upload-content publish video direct POST /api/media/upload upload media POST /api/media/check check media GET /api/persona/list list personas POST /api/persona create persona PATCH /api/persona update persona DELETE /api/persona delete persona GET /api/persona/delete-preview get persona delete preview GET /api/persona/faces list faces GET /api/persona/images list persona images POST /api/persona/images add persona image PATCH /api/persona/images update persona image DELETE /api/persona/images remove persona image GET /api/persona/voices list voices GET /api/persona/cloned-voices list cloned voices POST /api/persona/cloned-voices create cloned voice GET /api/persona/cloned-voices/{cloneId} get cloned voice DELETE /api/persona/cloned-voices/{cloneId} delete cloned voice POST /api/persona/cloned-voices/{cloneId}/preview preview cloned voice POST /api/persona/voices/{voiceId}/preview preview house voice GET /api/persona/publishing-accounts get persona publishing accounts PUT /api/persona/publishing-accounts set persona publishing accounts GET /api/account list social accounts GET /api/pinterest/boards list pinterest boards DELETE /api/account disconnect account POST /api/account/connect-url connect account (OAuth URL) POST /api/bluesky-connect connect account (Bluesky) POST /api/threespeak-connect connect account (3Speak) POST /api/rumble-connect connect account (Rumble) GET /api/schedule list schedules DELETE /api/schedule cancel schedule GET /api/schedule/status list posts GET /api/schedule/slots/{slotId} get slot PATCH /api/schedule/slots/{slotId} update slot title DELETE /api/schedule/slots/{slotId} delete slot GET /api/posts/{id} get post GET /api/metrics get post metrics GET /api/metrics/retention-curve get YouTube retention curve POST /api/experiments create experiment GET /api/experiments list experiments GET /api/experiments/{id} get experiment results GET /api/billing/tokens get token balance GET /api/billing/transactions list token transactions GET /api/prompts list recipe prompts GET /api/prompts/{slug} get recipe prompt Not in this list: session-only routes (OAuth callbacks, API key management, billing checkout/webhook, logout, GET /api/health) and the public GET /api/version. ================================================================================ SOCIAL ACCOUNTS ================================================================================ Supported: YouTube, Instagram, LinkedIn, Threads, Facebook Pages, Bluesky, 3Speak, Rumble. Connect via POST /api/account/connect-url (returns an https auth_url to open in a browser), POST /api/bluesky-connect (app password), POST /api/threespeak-connect (Hive posting key) or POST /api/rumble-connect (access token issued by emailing bd@rumble.com). Then map accounts to a persona with PUT /api/persona/publishing-accounts. ================================================================================ MARKETPLACES (RapidAPI, Apify, MCP Registry) ================================================================================ The same API key works everywhere; tokens are always billed by Post Engineer. - RapidAPI: send your Post Engineer key in Authorization: Bearer pe_live_... next to the X-RapidAPI-Key header. RapidAPI forwards it; without it the API returns 401. - Apify: the "Post Engineer video" Actor takes the key as a secret input and calls POST /api/videos/generate-and-schedule for you (source: integrations/apify in the repository). - MCP Registry: io.github.Ryan-Carloso/post-engineer (npm post-engineer-mcp), configured with POST_ENGINEER_API_KEY. ================================================================================ SELF-HOSTING ================================================================================ See docs/SELF_HOSTING.md in https://github.com/Ryan-Carloso/post-engineer.