Create Draft
Create a new post draft. Attach media by setting post_type and one of media_url or media_urls. Requires a paid Creator or Lifetime plan.
POST /v1/posts creates a LinkedIn post draft in LinkedMash. content is the only required field; everything else — title, format, and the media fields — is optional. The draft is created unscheduled, so nothing is published by this call, and the returned id is what you pass to the schedule, update and delete endpoints.
To attach media, upload or re-host it first with POST /v1/media/upload and pass the returned URL as media_url (or several as media_urls), together with post_type and media_mime_type. Passing a LinkedIn-hosted or short-lived URL directly is the usual cause of a draft that publishes without its image.
Example request
Authenticate with a bearer token in the Authorization header. Create a key on the API page in your LinkedMash settings and export it as LINKEDMASH_API_KEY before running this.
curl -X POST "https://api.linkedmash.com/v1/posts" \
-H "Authorization: Bearer $LINKEDMASH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "5 lessons from shipping every week for a year:",
"title": "Weekly shipping lessons",
"format": "text"
}'Header parameters
Your secret API key as a Bearer token.
Body parameters
The post body text.
An optional title for the draft.
Post format: text, image, video, article, or poll.
Media type to attach: text, image, video, or pdf. Set this when attaching media.
Public URL of an image, video, or PDF to attach.
Multiple public media URLs to attach.
MIME type of the attached media (e.g., 'image/png').
Response
{
"status": true,
"data": {
"id": "drf_8f3a21c9",
"content": "5 lessons from shipping every week for a year:",
"title": "Weekly shipping lessons",
"format": "text",
"status": "draft",
"created_at": "2026-06-22T09:14:02.118Z",
"updated_at": "2026-06-22T09:14:02.118Z"
}
}Response fields
Every response is wrapped in the same envelope: a status flag and a data payload, with meta present where there is pagination or a plan limit to report.
true on success. Every LinkedMash API response carries this envelope flag alongside data, so a client can branch on it without re-reading the HTTP status.
Draft identifier. Pass it to GET, PATCH and DELETE /v1/posts/{id} and to the schedule route.
The post body. Drafts written in the Studio editor can store this as an object with a text field rather than a bare string — handle both.
Internal working title. It is never published to LinkedIn; it exists so drafts are findable.
Composition format, e.g. text or carousel.
One of draft, scheduled or published.
ISO-8601 creation timestamp.
ISO-8601 timestamp of the last edit.
From idea to scheduled post
Creating a draft is step one of four. Nothing publishes until you call the schedule route.
Upload media first, if there is any
POST /v1/media/upload returns a stable URL. Doing this before the draft exists means you can attach it in one call rather than creating and then patching.
Create the draft
Send content, plus title and format if you want them. Keep the returned data.id — it is required by every later step and there is no way to look a draft up by content.
Revise with PATCH
Iterating on a hook is PATCH /v1/posts/{id}, not a new create. Creating a second draft for each revision is the most common way these libraries fill with near-duplicates.
Schedule when it is ready
POST /v1/posts/{id}/schedule with publish_at as an ISO timestamp, 'next-slot', or 'now'. A draft that is never scheduled simply stays a draft.
Behaviour and limits
Requires a Creator or Lifetime plan
Everything under /v1/posts, /v1/queue, /v1/schedule, /v1/media and /v1/analytics sits behind one middleware that checks for an unlocked Studio, so a Reader-plan or free key gets 402 with code SUBSCRIPTION_REQUIRED before the handler runs. Bookmark and label reads are on a separate router and are not affected by this gate.
Returns 201, not 200
A successful create answers 201 with the new draft in data. Clients that only branch on status === 200 will treat a successful create as a failure.
content is validated here, before the draft store sees it
A missing or empty content field returns 400 with "content is required." immediately, so an empty draft is never persisted.
media_url and media_urls are the same field
A single media_url is folded into the media_urls array the draft actually stores. Send one or the other; sending both means media_urls wins.
Errors
Failures carry the same envelope as a success, with the reason in message and a stable machine-readable code where the status alone is ambiguous — several distinct conditions share a 402.