API version 2026-08-21
Publish once.
Ship everywhere.
The Werepost API creates immediate and scheduled social posts for one isolated profile, with durable idempotency, status refresh, retry, and deletion controls.
https://werepost.ai/api/v1
Authentication and scope
Create an API key in Settings → API keys. The complete key is copied and shown once. Store it in a server-side secret manager.
Authorization: Bearer wrp_live_your_key
Content-Type: application/json
Keys are stored as one-way hashes, can be deleted from Settings, and are never accepted for a profile belonging to another Werepost account. Every API-key request is scoped with a profile_id. A key owned by an account can address that account's profiles, but it cannot cross account ownership.
Do not put a live API key in front-end JavaScript, a mobile binary, a public repository, a URL, or logs. If a key is exposed, delete it in Settings and create a replacement.
Connection-management endpoints use a signed-in Werepost user access token, not an API key. For a normal server integration, connect destinations in the Werepost app and use the API key only for post operations.
Quickstart
- Sign in to Werepost and create or select a profile.
- Connect every destination from the profile's Connections page. Finish page or channel selection where required.
- Create an API key in Settings and save the one-time value.
- Host the video at a fetchable public HTTPS CDN URL.
- Send a create request with a unique
Idempotency-Key.
curl https://werepost.ai/api/v1/posts \
--request POST \
--header "Authorization: Bearer $WEREPOST_API_KEY" \
--header "Content-Type: application/json" \
--header "Idempotency-Key: product-launch-2026-08-21" \
--data '{
"profile_id": "4a40c92d-68af-4f10-b1cc-881591b575fd",
"title": "Product launch",
"caption": "A first look at what we built.",
"media_url": "https://cdn.example.com/video/launch.mp4",
"platforms": ["tiktok", "instagram", "youtube"]
}'
A new request returns 201. A replay that resolves to an existing post returns 200 with "idempotent": true.
Media and CDN flow
API clients supply media by URL. Werepost validates the URL, prepares the remote media for publishing, and passes the resulting media reference into the selected platform jobs.
| Requirement | Contract |
|---|---|
| Scheme | https:// only for API clients; embedded URL credentials are rejected. |
| Host | Use a publicly resolvable CDN host. localhost and literal private IP addresses are rejected. |
| Availability | The object must remain fetchable while the create request is processed. Avoid short-lived signed URLs that may expire during transfer. |
| Length | The media URL may be at most 4,096 characters. |
| Request size | JSON bodies are limited to 1,000,000 bytes. Do not base64-encode media into JSON. |
There is no public multipart upload endpoint in /api/v1. The Werepost web app uploads files to its private media bucket and uses an internal storage://scheduled-videos/… reference. That form is reserved for app-managed uploads; external API clients should use a public HTTPS CDN URL.
Deleting a post removes app-managed private media associated with that record. Werepost does not delete an object from your public CDN.
Create a post
/api/v1/posts| Field | Type | Description |
|---|---|---|
profile_id required | UUID | Owned Werepost profile. |
media_url required | string | Public HTTPS CDN URL. video_url is accepted as an alias. |
platforms required | string[] | At least one supported, connected platform key. Duplicates are removed. |
caption | string | Text adapted to the selected platforms, up to 20,000 characters. text and description are accepted aliases. |
title | string | Internal title, truncated to 180 characters. Werepost derives a fallback when omitted. |
scheduled_at | ISO-8601 | Future publication time. Omit for immediate publication. publish_at and post_date are accepted aliases. |
platform_options | object | Optional per-platform controls described below. |
Immediate publishing
Omit scheduled_at. Werepost places the job shortly ahead so the remote media can be prepared safely. “Immediate” is asynchronous: use the returned post ID to check delivery.
Scheduled publishing
{
"profile_id": "4a40c92d-68af-4f10-b1cc-881591b575fd",
"caption": "Publishing Tuesday at 16:30 Paris time.",
"media_url": "https://cdn.example.com/video/tuesday.mp4",
"platforms": ["facebook", "linkedin"],
"scheduled_at": "2026-08-25T14:30:00Z"
}
Send a timezone-aware timestamp. UTC with a trailing Z is recommended. A timestamp materially in the past returns 400 invalid_schedule.
Supported platform keys
tiktok, instagram, facebook, youtube, x, linkedin, pinterest, reddit, bluesky, threads, googlebusiness, and discord. Use GET /api/v1/platforms as the live source of truth.
Platform options
Keys under platform_options match the Werepost platform key. Omitted booleans default to false unless stated otherwise.
pinterest.board_name, reddit.subreddit, and discord.channel_id are mandatory whenever their platform is selected. A missing value returns 400 platform_option_required.
| Platform | Supported option fields |
|---|---|
tiktok | privacy (default PUBLIC_TO_EVERYONE), disable_comments, disable_duet, disable_stitch, is_brand_content, is_organic_brand_content, is_ai_generated |
instagram | type (default REEL), share_to_feed (default true), is_paid_partnership, is_ai_generated |
facebook | type (default REEL) |
youtube | type (default SHORT), title (100 characters), privacy (default PUBLIC), made_for_kids, contains_synthetic_media, has_paid_product_placement |
x | is_ai_generated. Caption is capped at 280 characters by Werepost. |
linkedin | disable_reshare |
pinterest | board_name required, title, link, alt_text, is_ai_generated |
reddit | subreddit required, title, nsfw, flair_id |
discord | channel_id required |
googlebusiness | topic_type (default STANDARD) |
threads | topic_tag |
bluesky | tags as an array of strings |
{
"platforms": ["pinterest", "reddit", "discord"],
"platform_options": {
"pinterest": { "board_name": "Product launches", "alt_text": "Product demo" },
"reddit": { "subreddit": "r/SideProject", "title": "What we shipped" },
"discord": { "channel_id": "123456789012345678" }
}
}
Platform policies can impose additional requirements that depend on the connected account or content. Those rejections are returned as safe Werepost errors or appear in the post's error field after refresh.
Idempotency
Every create request requires an Idempotency-Key header containing 8–128 letters, digits, dots, underscores, colons, or dashes.
- Generate one key for one intended post and reuse it for every retry of that same intent.
- The key is combined with
profile_id, so the same literal key in two different profiles does not identify the same post. - A confirmed new post returns
201andidempotent: false. - A replay that already has a publishing job returns
200and the existing post withidempotent: true. - Do not reuse a key with different content. Werepost compares a stable request fingerprint and returns
409 idempotency_conflictwhen the same key is used for a different request.
If a request times out or the connection drops, retry the exact request with the same key. For 429, 502, or 503, use exponential backoff and preserve the key.
For clients that cannot set headers, idempotency_key in the JSON body is accepted as a compatibility fallback. The header is the production recommendation.
Status and refresh
/api/v1/posts/{post_id}Without a query parameter, this endpoint returns the last state stored by Werepost. Add ?refresh=true to synchronise the publishing job before responding.
curl "https://werepost.ai/api/v1/posts/4cf807c9-5e93-4c98-9077-586b5ce0e20e?refresh=true" \
--header "Authorization: Bearer $WEREPOST_API_KEY"
pendingAccepted and waiting for the scheduled time or next processing stage.
processingMedia transfer, publication, retry, or review is in progress.
deliveredThe publishing job reported success. The destination may still process or review content.
failedThe job reported an error or deletion. Inspect provider_status and error.
provider_status gives the detailed state when available, including UPLOADING, SCHEDULED, PROCESSING, RETRYING, REVIEW, POSTED, ERROR, and DELETED.
Per-platform deliveries
Every post response also includes deliveries, an array with one entry per destination. This is the best field for partial success: the overall post can finish while a specific platform reports its own result.
{
"platform": "youtube",
"status": "delivered",
"external_id": "video_123",
"external_url": "https://www.youtube.com/watch?v=video_123",
"error": null,
"delivered_at": "2026-08-25T14:31:08.000Z"
}
Delivery status is one of pending, uploading, delivered, or failed. external_id and external_url are present only when the destination returns them. Errors and URLs are sanitised before Werepost exposes them.
Poll the normal endpoint for local state and periodically request refresh=true while a post is pending or processing. Use increasing intervals, stop on delivered or failed, and back off on 429 or dependency errors.
/api/v1/posts?profile_id={uuid}&limit=100Lists posts in descending scheduled order. API keys must include profile_id. limit defaults to 100 and is clamped from 1 to 200.
Retry and delete
/api/v1/posts/{post_id}/retryRetries an existing failed publishing job, immediately refreshes it, and returns { "data": post }. If the original create failed before a publishing job existed, Werepost returns 409 resubmit_required. Resend the original POST /posts request with the same Idempotency-Key.
/api/v1/posts/{post_id}Attempts to cancel the job, removes app-managed private media if applicable, and deletes the Werepost post record. It returns:
{
"deleted": true,
"id": "4cf807c9-5e93-4c98-9077-586b5ce0e20e"
}
A job may already be processing or delivered. Content already published on a destination may remain there; manage it with that platform's controls. Public CDN media also remains under your control.
Connection flow
Connection routes are used by the Werepost web application and require a signed-in user access token. They reject wrp_live_… API keys. This prevents a leaked publishing key from authorising or disconnecting social accounts.
- Provision the owned profile with
POST /profiles/{profile_id}/provision. - Request a direct platform URL with
GET /connect/{platform}?profile_id={uuid}. - Navigate the browser to the returned
url. It is a fresh provider authorisation URL; do not store it. - After the browser returns to Werepost, call
GET /connections?profile_id={uuid}. - If the connection says
needs_channel_selection: true, present itschannelsand submit one selection.
/api/v1/connect/{platform}?profile_id={uuid}&choose_account=truechoose_account defaults to true so providers ask which account to use where supported. The response is { "url": "https://…", "platform": "tiktok" }.
/api/v1/connections?profile_id={uuid}Returns account display data, connection status, and available destinations. Valid status values are connected, action_required, and disconnected.
/api/v1/connections/{platform}?profile_id={uuid}Disconnects the platform for this profile. It does not delete existing posts from the destination.
Channel selection
Facebook, YouTube, LinkedIn, and Google Business may return pages, channels, organisations, or locations that require a selection. Use the exact channel id returned in connections[].channels.
/api/v1/connections/channel{
"profile_id": "4a40c92d-68af-4f10-b1cc-881591b575fd",
"platform": "youtube",
"channel_id": "UC123456789"
}
Werepost verifies that the channel belongs to the profile's connection and refreshes the available channel list once if necessary. Publishing returns 409 channel_selection_required until setup is complete.
Endpoint reference
| Method | Path | Credential | Purpose |
|---|---|---|---|
| GET | /api/v1 | Public | API version and implemented routes. |
| GET | /api/v1/health | Public | Configuration health. |
| GET | /api/v1/platforms | Public | Supported platform metadata. |
| POST | /api/v1/profiles/{id}/provision | User session | Prepare a profile publishing workspace. |
| GET | /api/v1/connections | User session | List profile connections. |
| GET | /api/v1/connect/{platform} | User session | Create a direct authorisation URL. |
| POST | /api/v1/connections/channel | User session | Select a page or channel. |
| DELETE | /api/v1/connections/{platform} | User session | Disconnect a platform. |
| POST | /api/v1/posts | API key or user session | Create an immediate or scheduled post. |
| GET | /api/v1/posts | API key or user session | List posts. |
| GET | /api/v1/posts/{id} | API key or user session | Read or refresh one post. |
| POST | /api/v1/posts/{id}/retry | API key or user session | Retry a failed publishing job. |
| DELETE | /api/v1/posts/{id} | API key or user session | Cancel and delete a Werepost post. |
The authoritative request and response schemas are available as OpenAPI 3.1 JSON.
Errors
Every error is JSON. The request_id also appears in the X-Request-Id response header.
{
"error": "platform_not_connected",
"message": "Connect every selected platform before publishing.",
"details": {
"missing": ["tiktok"],
"needs_channel": []
},
"request_id": "b4805362-5580-4eb0-b4e3-d95b30235b2b"
}
| Status | Meaning | Typical codes |
|---|---|---|
400 | Invalid JSON, field, platform, media URL, schedule, option, or channel selection. | invalid_json, platforms_required, media_url_required, invalid_schedule, platform_option_required |
401 | Missing, invalid, revoked, wrong-type, or profile-mismatched credential. | unauthorized, user_session_required |
404 | Endpoint, profile, or post not found or not visible to the caller. | not_found |
409 | Publishing precondition, idempotency, or resubmission conflict. | platform_not_connected, channel_selection_required, idempotency_conflict, resubmit_required |
413 | JSON body exceeds 1,000,000 bytes. | payload_too_large |
429 | A publishing dependency applied a rate limit. | rate_limited |
500 | Unexpected Werepost error. Public message is intentionally generic. | internal_error |
502 | Connection, media, database, or publishing dependency failed. | social_provider_error, social_provider_timeout, social_provider_unavailable |
503 | A required service is unavailable or not configured. | social_provider_not_configured |
For status codes below 500, message describes the problem. For 5xx errors it is deliberately generic; record the request ID. Structured details may identify missing platforms, destinations awaiting channel selection, or safe validation issues.
Production checklist
- Keep the API key in a server-side secret manager and rotate it after any suspected exposure.
- Persist the Werepost
profile_idand postid; never infer profile ownership client-side. - Generate and persist an idempotency key before the first create attempt.
- Use a durable HTTPS CDN URL and keep it available until the post is accepted.
- Supply required Pinterest, Reddit, and Discord options when those destinations are selected.
- Use
refresh=truewith backoff until a post reachesdeliveredorfailed. - Handle
409 resubmit_requiredby replaying the original create request with the original idempotency key. - Log
X-Request-Idwith your request metadata, but never log Bearer credentials or sensitive authorisation URLs. - Expect platform-specific rejection and review. A successful API response means the job was accepted, not that every destination has published it.
Questions or a reproducible failure? Email info@sofuto.uk with the request ID, endpoint, timestamp, and post ID. Do not include your API key.