Endpoints
Edit Draft
Manage saved unpublished posts without choosing a publish date.
PATCH
/
api
/
v1
/
drafts
/
{id}
Edit an unpublished draft
curl --request PATCH \
--url https://mallary.ai/api/v1/drafts/{id} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"expected_revision": 2,
"profile_id": "AbC123xYz90",
"message": "<string>",
"platforms": [],
"media": [
{
"url": "<string>"
}
],
"comments_under_post": [
"<string>"
],
"platform_options": {},
"auto_reply_enabled": true
}
'import requests
url = "https://mallary.ai/api/v1/drafts/{id}"
payload = {
"expected_revision": 2,
"profile_id": "AbC123xYz90",
"message": "<string>",
"platforms": [],
"media": [{ "url": "<string>" }],
"comments_under_post": ["<string>"],
"platform_options": {},
"auto_reply_enabled": True
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
expected_revision: 2,
profile_id: 'AbC123xYz90',
message: '<string>',
platforms: [],
media: [{url: '<string>'}],
comments_under_post: ['<string>'],
platform_options: {},
auto_reply_enabled: true
})
};
fetch('https://mallary.ai/api/v1/drafts/{id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://mallary.ai/api/v1/drafts/{id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'expected_revision' => 2,
'profile_id' => 'AbC123xYz90',
'message' => '<string>',
'platforms' => [
],
'media' => [
[
'url' => '<string>'
]
],
'comments_under_post' => [
'<string>'
],
'platform_options' => [
],
'auto_reply_enabled' => true
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://mallary.ai/api/v1/drafts/{id}"
payload := strings.NewReader("{\n \"expected_revision\": 2,\n \"profile_id\": \"AbC123xYz90\",\n \"message\": \"<string>\",\n \"platforms\": [],\n \"media\": [\n {\n \"url\": \"<string>\"\n }\n ],\n \"comments_under_post\": [\n \"<string>\"\n ],\n \"platform_options\": {},\n \"auto_reply_enabled\": true\n}")
req, _ := http.NewRequest("PATCH", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.patch("https://mallary.ai/api/v1/drafts/{id}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"expected_revision\": 2,\n \"profile_id\": \"AbC123xYz90\",\n \"message\": \"<string>\",\n \"platforms\": [],\n \"media\": [\n {\n \"url\": \"<string>\"\n }\n ],\n \"comments_under_post\": [\n \"<string>\"\n ],\n \"platform_options\": {},\n \"auto_reply_enabled\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://mallary.ai/api/v1/drafts/{id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"expected_revision\": 2,\n \"profile_id\": \"AbC123xYz90\",\n \"message\": \"<string>\",\n \"platforms\": [],\n \"media\": [\n {\n \"url\": \"<string>\"\n }\n ],\n \"comments_under_post\": [\n \"<string>\"\n ],\n \"platform_options\": {},\n \"auto_reply_enabled\": true\n}"
response = http.request(request)
puts response.read_body{
"status": "ok",
"data": {
"profile_id": "AbC123xYz90",
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"revision": 2,
"status": "draft",
"message": "<string>",
"platforms": [
"facebook"
],
"media": [
{
"url": "<string>"
}
],
"comments_under_post": [
"<string>"
],
"platform_options": {},
"auto_reply_enabled": true,
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"submission": {
"status": "queued",
"batch_id": "<string>",
"profile_id": "<string>",
"jobs": [
{
"platform": "twitter",
"jobId": "<string>",
"platform_post_id": "<string>",
"platform_post_url": "<string>"
}
],
"warnings": [
{
"platform": "twitter",
"code": "<string>",
"severity": "warning",
"message": "<string>"
}
]
}
}
}Saved drafts are available to all users. Normal publishing and scheduling rules apply when submitting.
Drafts stay separate from scheduled and published posts. Saving does not publish or use your posting allowance. Text, media, destinations, and platform settings can be unfinished.
Use the draft UUID from the save response. Read the draft’s current
revision before editing, deleting, or submitting, then send it as expected_revision. A 409 means the draft changed or was submitted; read it again before continuing.
Only the submit endpoint publishes or schedules. It runs the same account, plan, content, and platform checks as Create Post. If validation fails, the draft stays saved. After a successful submission, the draft read includes submission with the original jobs. Repeating the same submission revision and schedule returns those same jobs.
Use profile_id for a non-default connection profile. A draft uses one profile. Lists include only unpublished drafts in that profile.
See the draft workflow for dashboard, API, MCP, and CLI examples.Authorizations
Use Authorization: Bearer {api_key}
Path Parameters
Query Parameters
Omit to use the default profile on lists. On reads, deletes and submissions, optionally verify the draft belongs to this profile.
Random public connection profile ID returned by GET /api/v1/profiles.
Pattern:
^[A-Za-z0-9]{6,32}$Example:
"AbC123xYz90"
Body
application/json
Unpublished content. All fields are optional; no scheduled date or connected destination is needed to save. Supplied arrays and platform_options replace the saved value when editing. Media must already be uploaded to files.mallary.ai.
Current revision from a draft read or save.
Required range:
x >= 1Random public connection profile ID returned by GET /api/v1/profiles.
Pattern:
^[A-Za-z0-9]{6,32}$Example:
"AbC123xYz90"
Maximum string length:
10000Maximum array length:
10Available options:
facebook, meta, instagram, threads, twitter, x, linkedin, tiktok, youtube, pinterest, reddit, bluesky Maximum array length:
20Show child attributes
Show child attributes
Maximum array length:
3Maximum string length:
10000Show child attributes
Show child attributes
Last modified on October 9, 2026
Was this page helpful?
Edit an unpublished draft
curl --request PATCH \
--url https://mallary.ai/api/v1/drafts/{id} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"expected_revision": 2,
"profile_id": "AbC123xYz90",
"message": "<string>",
"platforms": [],
"media": [
{
"url": "<string>"
}
],
"comments_under_post": [
"<string>"
],
"platform_options": {},
"auto_reply_enabled": true
}
'import requests
url = "https://mallary.ai/api/v1/drafts/{id}"
payload = {
"expected_revision": 2,
"profile_id": "AbC123xYz90",
"message": "<string>",
"platforms": [],
"media": [{ "url": "<string>" }],
"comments_under_post": ["<string>"],
"platform_options": {},
"auto_reply_enabled": True
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
expected_revision: 2,
profile_id: 'AbC123xYz90',
message: '<string>',
platforms: [],
media: [{url: '<string>'}],
comments_under_post: ['<string>'],
platform_options: {},
auto_reply_enabled: true
})
};
fetch('https://mallary.ai/api/v1/drafts/{id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://mallary.ai/api/v1/drafts/{id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'expected_revision' => 2,
'profile_id' => 'AbC123xYz90',
'message' => '<string>',
'platforms' => [
],
'media' => [
[
'url' => '<string>'
]
],
'comments_under_post' => [
'<string>'
],
'platform_options' => [
],
'auto_reply_enabled' => true
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://mallary.ai/api/v1/drafts/{id}"
payload := strings.NewReader("{\n \"expected_revision\": 2,\n \"profile_id\": \"AbC123xYz90\",\n \"message\": \"<string>\",\n \"platforms\": [],\n \"media\": [\n {\n \"url\": \"<string>\"\n }\n ],\n \"comments_under_post\": [\n \"<string>\"\n ],\n \"platform_options\": {},\n \"auto_reply_enabled\": true\n}")
req, _ := http.NewRequest("PATCH", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.patch("https://mallary.ai/api/v1/drafts/{id}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"expected_revision\": 2,\n \"profile_id\": \"AbC123xYz90\",\n \"message\": \"<string>\",\n \"platforms\": [],\n \"media\": [\n {\n \"url\": \"<string>\"\n }\n ],\n \"comments_under_post\": [\n \"<string>\"\n ],\n \"platform_options\": {},\n \"auto_reply_enabled\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://mallary.ai/api/v1/drafts/{id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"expected_revision\": 2,\n \"profile_id\": \"AbC123xYz90\",\n \"message\": \"<string>\",\n \"platforms\": [],\n \"media\": [\n {\n \"url\": \"<string>\"\n }\n ],\n \"comments_under_post\": [\n \"<string>\"\n ],\n \"platform_options\": {},\n \"auto_reply_enabled\": true\n}"
response = http.request(request)
puts response.read_body{
"status": "ok",
"data": {
"profile_id": "AbC123xYz90",
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"revision": 2,
"status": "draft",
"message": "<string>",
"platforms": [
"facebook"
],
"media": [
{
"url": "<string>"
}
],
"comments_under_post": [
"<string>"
],
"platform_options": {},
"auto_reply_enabled": true,
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"submission": {
"status": "queued",
"batch_id": "<string>",
"profile_id": "<string>",
"jobs": [
{
"platform": "twitter",
"jobId": "<string>",
"platform_post_id": "<string>",
"platform_post_url": "<string>"
}
],
"warnings": [
{
"platform": "twitter",
"code": "<string>",
"severity": "warning",
"message": "<string>"
}
]
}
}
}
