Posts
List, update, and manage images on generated LinkedIn drafts.
/api/v1/projects/:id/postsList Posts
List generated posts for a project.
Query parameters
- status - filter by post status: pending, approved, or discarded
Response 200
{
"posts": [
{
"id": "uuid",
"moment_id": "uuid",
"platform": "linkedin",
"generated_content": "Full LinkedIn post text...",
"first_comment": "Hashtags and CTA...",
"status": "pending",
"publish_tool": null,
"image_url": null,
"created_at": "2026-05-01T10:05:00Z"
}
]
}v1 post model: One long-form LinkedIn post per extracted moment. post_type and carousel_slides are not part of v1.
image_url values while generating: __generating__ (in progress), __error__ (failed), a normal https:// URL when ready, or null.
/api/v1/projects/:id/posts/:postIdGet Post
Fetch a single post. Same fields as the list endpoint.
Response 200
{
"post": {
"id": "uuid",
"moment_id": "uuid",
"platform": "linkedin",
"generated_content": "...",
"first_comment": "...",
"status": "pending",
"publish_tool": null,
"image_url": null,
"created_at": "..."
}
}/api/v1/projects/:id/posts/:postIdUpdate Post
Update a post's status and content. Optionally publish or schedule to a connected tool in the same call.
Request body (all fields optional)
{
"status": "approved",
"generated_content": "Revised content...",
"first_comment": "Updated hashtags...",
"image_url": "https://...",
"provider": "linkedin",
"account_id": "optional-provider-account-id"
}| Field | Values |
|---|---|
| status | pending, approved, discarded |
| generated_content | String |
| first_comment | String or null |
| image_url | Valid https:// URL (SparkVox R2 or legacy Supabase public storage) or null |
| provider | linkedin - triggers publishing (see below) |
| account_id | Provider-specific account ID; omit to use the default account |
Publishing behavior
- Without provider - sets status: approved in SparkVox only. No post is sent anywhere.
- With provider - you must include status: approved in the same request body. Schedules the post to the connected tool. Requires a connection in Settings → Integrations. generated_content must be present when scheduling.
Scheduling with provider only runs when status is approved in the same PATCH. Sending provider alone without status does not publish.
Error responses
- 400 - invalid status, unknown provider, integration not connected, missing generated_content when scheduling
- 403 - post not owned by API key user
- 404 - project or post not found
- 502 - provider scheduling failed
Response 200
Without provider: returns the updated post object.
With provider: returns the updated post object plus scheduling details:
{
"id": "uuid",
"status": "approved",
"publish_tool": "linkedin",
"generated_content": "...",
"scheduled_at": "2026-06-02T09:00:00.000Z",
"job_id": "provider-job-id"
}/api/v1/projects/:id/posts/:postId/generate-imageGenerate Image
Start AI image generation for a post (async). Matches in-app Generate image: Claude Sonnet drafts a hook-anchored visual brief, then fal.ai Flux renders a 16:9 image (heuristic fallback if the brief step fails).
Request body (optional)
{ "post_content": "Override text to illustrate (defaults to saved generated_content)" }Response 202
{ "accepted": true }Poll GET.../posts/:postId until image_url is a normal URL (or __error__ on failure). While running, image_url is __generating__.
/api/v1/projects/:id/posts/:postId/upload-urlImage Upload URL
Get a presigned URL to upload your own media (JPG, PNG, GIF, WebP - max 50 MB; MP4 - max 200 MB). After uploading with PUT to upload_url, set the post media via PATCH with image_url set to public_url.
Request body
{
"filename": "hero.png",
"mime_type": "image/png",
"file_size_bytes": 1048576
}| Field | Required | Notes |
|---|---|---|
| filename | Yes | |
| mime_type | No | video/mp4 selects the 200 MB limit |
| file_size_bytes | No |
The web app uses same-origin proxy uploads for browsers that cannot PUT directly to R2. API clients can use the presigned upload_url flow.
Response 200
{
"upload_url": "https://...",
"storage_path": "post-images/...",
"content_type": "image/png",
"public_url": "https://media.sparkvox.io/..."
}