Endpoints
Publish or Schedule Draft
Manage saved unpublished posts without choosing a publish date.
POST
/
api
/
v1
/
drafts
/
{id}
/
submit
Publish or schedule a saved draft
curl --request POST \
--url https://mallary.ai/api/v1/drafts/{id}/submit \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"expected_revision": 2,
"scheduled_at": "<string>",
"scheduled_timezone": "<string>"
}
'import requests
url = "https://mallary.ai/api/v1/drafts/{id}/submit"
payload = {
"expected_revision": 2,
"scheduled_at": "<string>",
"scheduled_timezone": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({expected_revision: 2, scheduled_at: '<string>', scheduled_timezone: '<string>'})
};
fetch('https://mallary.ai/api/v1/drafts/{id}/submit', 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}/submit",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'expected_revision' => 2,
'scheduled_at' => '<string>',
'scheduled_timezone' => '<string>'
]),
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}/submit"
payload := strings.NewReader("{\n \"expected_revision\": 2,\n \"scheduled_at\": \"<string>\",\n \"scheduled_timezone\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", 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.post("https://mallary.ai/api/v1/drafts/{id}/submit")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"expected_revision\": 2,\n \"scheduled_at\": \"<string>\",\n \"scheduled_timezone\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://mallary.ai/api/v1/drafts/{id}/submit")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"expected_revision\": 2,\n \"scheduled_at\": \"<string>\",\n \"scheduled_timezone\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"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
Current revision from a draft read or save.
Required range:
x >= 1Omit to publish now. Absolute time or local time paired with scheduled_timezone.
Required string length:
1 - 80IANA time zone for a local scheduled_at; paid scheduling rules apply.
Required string length:
1 - 100Last modified on October 9, 2026
Was this page helpful?
Publish or schedule a saved draft
curl --request POST \
--url https://mallary.ai/api/v1/drafts/{id}/submit \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"expected_revision": 2,
"scheduled_at": "<string>",
"scheduled_timezone": "<string>"
}
'import requests
url = "https://mallary.ai/api/v1/drafts/{id}/submit"
payload = {
"expected_revision": 2,
"scheduled_at": "<string>",
"scheduled_timezone": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({expected_revision: 2, scheduled_at: '<string>', scheduled_timezone: '<string>'})
};
fetch('https://mallary.ai/api/v1/drafts/{id}/submit', 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}/submit",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'expected_revision' => 2,
'scheduled_at' => '<string>',
'scheduled_timezone' => '<string>'
]),
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}/submit"
payload := strings.NewReader("{\n \"expected_revision\": 2,\n \"scheduled_at\": \"<string>\",\n \"scheduled_timezone\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", 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.post("https://mallary.ai/api/v1/drafts/{id}/submit")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"expected_revision\": 2,\n \"scheduled_at\": \"<string>\",\n \"scheduled_timezone\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://mallary.ai/api/v1/drafts/{id}/submit")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"expected_revision\": 2,\n \"scheduled_at\": \"<string>\",\n \"scheduled_timezone\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"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>"
}
]
}
