curl --request POST \
--url https://api.superx.so/v1/articles \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"title": "How we grew to 10k followers",
"content_markdown": "# The system\n\nConsistency beats intensity.\n\n- Post daily\n- Reply to your top contacts"
}
'import requests
url = "https://api.superx.so/v1/articles"
payload = {
"title": "How we grew to 10k followers",
"content_markdown": "# The system
Consistency beats intensity.
- Post daily
- Reply to your top contacts"
}
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({
title: 'How we grew to 10k followers',
content_markdown: '# The system\n\nConsistency beats intensity.\n\n- Post daily\n- Reply to your top contacts'
})
};
fetch('https://api.superx.so/v1/articles', 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://api.superx.so/v1/articles",
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([
'title' => 'How we grew to 10k followers',
'content_markdown' => '# The system
Consistency beats intensity.
- Post daily
- Reply to your top contacts'
]),
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://api.superx.so/v1/articles"
payload := strings.NewReader("{\n \"title\": \"How we grew to 10k followers\",\n \"content_markdown\": \"# The system\\n\\nConsistency beats intensity.\\n\\n- Post daily\\n- Reply to your top contacts\"\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://api.superx.so/v1/articles")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"title\": \"How we grew to 10k followers\",\n \"content_markdown\": \"# The system\\n\\nConsistency beats intensity.\\n\\n- Post daily\\n- Reply to your top contacts\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.superx.so/v1/articles")
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 \"title\": \"How we grew to 10k followers\",\n \"content_markdown\": \"# The system\\n\\nConsistency beats intensity.\\n\\n- Post daily\\n- Reply to your top contacts\"\n}"
response = http.request(request)
puts response.read_body{
"data": {
"id": "<string>",
"title": "<string>",
"status": "draft",
"content_markdown": "<string>",
"cover": {
"url": "<string>"
},
"scheduled_for": "2023-11-07T05:31:56Z",
"published_at": "2023-11-07T05:31:56Z",
"x_post_id": "<string>",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z"
},
"warnings": [
"<string>"
]
}{
"error": {
"code": "invalid_parameter",
"message": "since must be a UTC ISO-8601 timestamp"
}
}{
"error": {
"code": "invalid_api_key",
"message": "Unknown or revoked API key"
}
}{
"error": {
"code": "insufficient_scope",
"message": "This API key is read-only. Create a key with the write scope to use this endpoint."
}
}{
"error": {
"code": "idempotency_key_reuse",
"message": "This Idempotency-Key was already used with a different request body."
}
}{
"error": {
"code": "rate_limited",
"message": "Rate limit exceeded for the Pro plan (30 requests/min). Upgrade for higher limits.",
"retry_after": 42
}
}{
"error": {
"code": "upstream_error",
"message": "Failed to fetch scheduled posts. Try again shortly."
}
}{
"error": {
"code": "upstream_unavailable",
"message": "The scheduling service is temporarily unavailable. Retry with the same Idempotency-Key."
}
}Create an article draft
Creates a draft. content_markdown (max 400KB) converts to the article’s stored rich-text form: headings (h1-h3), bullet and numbered lists (one nesting level), blockquotes, bold/italic/strikethrough, links, images by http(s) URL, and bare X post URLs alone on a line as embeds. Constructs the format cannot express (code blocks, horizontal rules) degrade to plain text and are reported in a warnings array. Non-http(s) image or link URLs are rejected with 400.
Supports Idempotency-Key (max 64 chars): retries with the same key and body replay the original response with Idempotency-Replayed: true. Works for your main account or any account linked to it (account_id); accounts shared with you are read-only.
curl --request POST \
--url https://api.superx.so/v1/articles \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"title": "How we grew to 10k followers",
"content_markdown": "# The system\n\nConsistency beats intensity.\n\n- Post daily\n- Reply to your top contacts"
}
'import requests
url = "https://api.superx.so/v1/articles"
payload = {
"title": "How we grew to 10k followers",
"content_markdown": "# The system
Consistency beats intensity.
- Post daily
- Reply to your top contacts"
}
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({
title: 'How we grew to 10k followers',
content_markdown: '# The system\n\nConsistency beats intensity.\n\n- Post daily\n- Reply to your top contacts'
})
};
fetch('https://api.superx.so/v1/articles', 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://api.superx.so/v1/articles",
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([
'title' => 'How we grew to 10k followers',
'content_markdown' => '# The system
Consistency beats intensity.
- Post daily
- Reply to your top contacts'
]),
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://api.superx.so/v1/articles"
payload := strings.NewReader("{\n \"title\": \"How we grew to 10k followers\",\n \"content_markdown\": \"# The system\\n\\nConsistency beats intensity.\\n\\n- Post daily\\n- Reply to your top contacts\"\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://api.superx.so/v1/articles")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"title\": \"How we grew to 10k followers\",\n \"content_markdown\": \"# The system\\n\\nConsistency beats intensity.\\n\\n- Post daily\\n- Reply to your top contacts\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.superx.so/v1/articles")
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 \"title\": \"How we grew to 10k followers\",\n \"content_markdown\": \"# The system\\n\\nConsistency beats intensity.\\n\\n- Post daily\\n- Reply to your top contacts\"\n}"
response = http.request(request)
puts response.read_body{
"data": {
"id": "<string>",
"title": "<string>",
"status": "draft",
"content_markdown": "<string>",
"cover": {
"url": "<string>"
},
"scheduled_for": "2023-11-07T05:31:56Z",
"published_at": "2023-11-07T05:31:56Z",
"x_post_id": "<string>",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z"
},
"warnings": [
"<string>"
]
}{
"error": {
"code": "invalid_parameter",
"message": "since must be a UTC ISO-8601 timestamp"
}
}{
"error": {
"code": "invalid_api_key",
"message": "Unknown or revoked API key"
}
}{
"error": {
"code": "insufficient_scope",
"message": "This API key is read-only. Create a key with the write scope to use this endpoint."
}
}{
"error": {
"code": "idempotency_key_reuse",
"message": "This Idempotency-Key was already used with a different request body."
}
}{
"error": {
"code": "rate_limited",
"message": "Rate limit exceeded for the Pro plan (30 requests/min). Upgrade for higher limits.",
"retry_after": 42
}
}{
"error": {
"code": "upstream_error",
"message": "Failed to fetch scheduled posts. Try again shortly."
}
}{
"error": {
"code": "upstream_unavailable",
"message": "The scheduling service is temporarily unavailable. Retry with the same Idempotency-Key."
}
}Authorizations
A SuperX API key ("sxk_..."), created in the SuperX app under Account > API / MCP / CLI. Keys are server-side secrets.
Headers
Unique key (max 64 characters) for safe retries. Replays carry the "Idempotency-Replayed" response header set to "true". Keys are retained for 24 hours.
64Body
1 - 300Article body as markdown. Omit for an empty draft.
Any account you own, meaning your main account (the default when omitted) or one linked to it. An account shared with you returns 403 writes_main_account_only.