Posts API Reference
The Posts API allows you to create, retrieve, and delete social media posts across multiple platforms.
Endpoints
Section titled “Endpoints”| Method | Endpoint | Description |
|---|---|---|
GET | /api/posts | List all posts |
GET | /api/posts/:id | Get a single post |
GET | /api/posts/stats | Get stats snapshots for posts |
POST | /api/posts | Create a new post |
POST | /api/posts/:id/publish | Publish a draft post |
DELETE | /api/posts/:id | Delete a post |
List posts
Section titled “List posts”GET /api/posts
Retrieves a paginated list of all posts in the current profile group.
Query parameters
Section titled “Query parameters”| Name | Type | Required | Default | Description |
|---|---|---|---|---|
page | integer | No | 0 | Page number (zero-indexed) |
per_page | integer | No | 10 | Number of posts per page |
profile_group_id | string | No | - | Filter by profile group (hashid) |
status | string | No | - | Filter by status: draft, scheduled, published, failed |
platforms | array | No | - | Array of platforms (e.g., platforms[]=instagram&platforms[]=tiktok) |
scheduled_after | string | No | - | ISO 8601 date to filter posts scheduled after that date |
Example
Section titled “Example”curl -X GET "https://api.postproxy.dev/api/posts?page=0&per_page=10" \ -H "Authorization: Bearer YOUR_API_KEY"import PostProxy from "postproxy-sdk";
const client = new PostProxy("YOUR_API_KEY");const posts = await client.posts.list({ page: 0, perPage: 10 });console.log(posts);from postproxy import PostProxy
client = PostProxy("YOUR_API_KEY")posts = await client.posts.list(page=0, per_page=10)print(posts)package main
import ( "fmt" postproxy "github.com/postproxy/postproxy-go")
func main() { client := postproxy.New("YOUR_API_KEY") posts, _ := client.Posts.List(&postproxy.ListPostsOptions{ Page: 0, PerPage: 10, }) fmt.Println(posts)}require "postproxy"
client = PostProxy::Client.new("YOUR_API_KEY")posts = client.posts.list(page: 0, per_page: 10)puts postsuse PostProxy\PostProxy;
$client = new PostProxy("YOUR_API_KEY");$posts = $client->posts->list(["page" => 0, "per_page" => 10]);print_r($posts);import dev.postproxy.PostProxy;
PostProxy client = new PostProxy("YOUR_API_KEY");var posts = client.posts().list(new ListPostsOptions().page(0).perPage(10));System.out.println(posts);using PostProxy;
var client = new PostProxyClient("YOUR_API_KEY");var posts = await client.Posts.ListAsync(new ListPostsOptions { Page = 0, PerPage = 10 });Console.WriteLine(posts);Response:
{ "total": 42, "page": 0, "per_page": 10, "data": [ { "id": "abc123xyz", "body": "Check out our latest update!", "status": "processed", "scheduled_at": null, "created_at": "2024-01-15T10:30:00.000Z", "platforms": [ { "platform": "twitter", "status": "published", "params": null, "error": null, "attempted_at": "2024-01-15T10:30:01.000Z", "insights": { "impressions": 1523, "on": "2024-01-15T18:00:00.000Z" } }, { "platform": "instagram", "status": "published", "params": { "format": "post", "first_comment": "Link in bio!" }, "error": null, "attempted_at": "2024-01-15T10:30:02.000Z", "insights": { "impressions": 3842, "on": "2024-01-15T18:00:00.000Z" } } ] } ]}Response fields
Section titled “Response fields”| Field | Type | Description |
|---|---|---|
total | integer | Total number of posts |
page | integer | Current page number |
per_page | integer | Items per page |
data | array | Array of post objects |
Get post
Section titled “Get post”GET /api/posts/:id
Retrieves a single post by its ID.
Path parameters
Section titled “Path parameters”| Name | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Post hashid |
Example
Section titled “Example”curl -X GET "https://api.postproxy.dev/api/posts/abc123xyz" \ -H "Authorization: Bearer YOUR_API_KEY"import PostProxy from "postproxy-sdk";
const client = new PostProxy("YOUR_API_KEY");const post = await client.posts.get("abc123xyz");console.log(post);from postproxy import PostProxy
client = PostProxy("YOUR_API_KEY")post = await client.posts.get("abc123xyz")print(post)package main
import ( "fmt" postproxy "github.com/postproxy/postproxy-go")
func main() { client := postproxy.New("YOUR_API_KEY") post, _ := client.Posts.Get("abc123xyz") fmt.Println(post)}require "postproxy"
client = PostProxy::Client.new("YOUR_API_KEY")post = client.posts.get("abc123xyz")puts postuse PostProxy\PostProxy;
$client = new PostProxy("YOUR_API_KEY");$post = $client->posts->get("abc123xyz");print_r($post);import dev.postproxy.PostProxy;
PostProxy client = new PostProxy("YOUR_API_KEY");var post = client.posts().get("abc123xyz");System.out.println(post);using PostProxy;
var client = new PostProxyClient("YOUR_API_KEY");var post = await client.Posts.GetAsync("abc123xyz");Console.WriteLine(post);Response:
{ "id": "abc123xyz", "body": "Check out our latest update!", "status": "processed", "scheduled_at": null, "created_at": "2024-01-15T10:30:00.000Z", "platforms": [ { "platform": "twitter", "status": "published", "params": null, "error": null, "attempted_at": "2024-01-15T10:30:01.000Z", "insights": { "impressions": 1523, "on": "2024-01-15T18:00:00.000Z" } } ]}Response fields
Section titled “Response fields”| Field | Type | Description |
|---|---|---|
id | string | Unique post identifier (hashid) |
body | string | Post body/text content |
status | string | Post status: processing, processed, scheduled |
scheduled_at | string|null | ISO 8601 timestamp if scheduled, null otherwise |
created_at | string | ISO 8601 timestamp of creation |
media | array | Array of media attachment objects |
platforms | array | Array of platform-specific posting results |
thread | array | Array of thread child posts (only present for thread posts) |
Media object fields
Section titled “Media object fields”| Field | Type | Description |
|---|---|---|
id | string | Unique attachment identifier (hashid) |
status | string | Processing status: pending, processed, failed |
error_message | string|null | Error details if processing failed |
content_type | string | MIME type (e.g. image/jpeg, video/mp4) |
source_url | string|null | Original source URL if media was provided as a URL |
url | string|null | Hosted URL of the processed file (null if not yet processed) |
Thread child fields
Section titled “Thread child fields”| Field | Type | Description |
|---|---|---|
id | string | Unique identifier (hashid) of the child post |
body | string | Text content of the child post |
media | array | Array of media attachment objects (same structure as above) |
Platform object fields
Section titled “Platform object fields”| Field | Type | Description |
|---|---|---|
platform | string | Platform identifier: facebook, instagram, tiktok, linkedin, youtube, twitter, threads, pinterest |
status | string | Platform posting status: processing, published, failed, deleted |
params | object|null | Platform-specific parameters used for this post |
attempted_at | string|null | ISO 8601 timestamp of posting attempt |
insights | object | Engagement metrics (when available) |
insights.impressions | integer | Number of impressions/views |
insights.on | string | ISO 8601 timestamp when insights were captured |
Post stats
Section titled “Post stats”GET /api/posts/stats
Retrieves stats snapshots for one or more posts. Returns all matching snapshots (not just the latest) so you can see trends over time. Supports filtering by profiles/networks and timespan.
Query parameters
Section titled “Query parameters”| Name | Type | Required | Description |
|---|---|---|---|
post_ids | string | Yes | Comma-separated list of post hashids (max 50) |
profiles | string | No | Comma-separated list of profile hashids or platform names (e.g. instagram,twitter or abc123,def456 or mixed) |
from | string | No | ISO 8601 timestamp — only include snapshots recorded at or after this time |
to | string | No | ISO 8601 timestamp — only include snapshots recorded at or before this time |
Platform names are matched against known platforms (facebook, instagram, tiktok, linkedin, youtube, twitter, threads, pinterest). Anything else is treated as a profile hashid.
Example
Section titled “Example”curl -X GET "https://api.postproxy.dev/api/posts/stats?post_ids=abc123,def456&profiles=instagram,twitter&from=2026-02-01T00:00:00Z&to=2026-02-24T00:00:00Z" \ -H "Authorization: Bearer YOUR_API_KEY"import PostProxy from "postproxy-sdk";
const client = new PostProxy("YOUR_API_KEY");const stats = await client.posts.stats( ["abc123", "def456"], { profiles: ["instagram", "twitter"], from: "2026-02-01T00:00:00Z", to: "2026-02-24T00:00:00Z", },);console.log(stats);from postproxy import PostProxy
client = PostProxy("YOUR_API_KEY")stats = await client.posts.stats( post_ids=["abc123", "def456"], profiles=["instagram", "twitter"], from_date="2026-02-01T00:00:00Z", to_date="2026-02-24T00:00:00Z",)print(stats)package main
import ( "context" "fmt" postproxy "github.com/postproxy/postproxy-go")
func main() { client := postproxy.New("YOUR_API_KEY") from := "2026-02-01T00:00:00Z" to := "2026-02-24T00:00:00Z" stats, _ := client.Posts.Stats(context.Background(), []string{"abc123", "def456"}, &postproxy.PostStatsOptions{ Profiles: []string{"instagram", "twitter"}, From: &from, To: &to, }) fmt.Println(stats)}require "postproxy"
client = PostProxy::Client.new("YOUR_API_KEY")stats = client.posts.stats( ["abc123", "def456"], profiles: ["instagram", "twitter"], from: Time.now - 86400 * 30, to: Time.now)puts statsuse PostProxy\PostProxy;
$client = new PostProxy("YOUR_API_KEY");$stats = $client->posts()->stats( ['abc123', 'def456'], profiles: ['instagram', 'twitter'], from: '2026-02-01T00:00:00Z', to: '2026-02-24T00:00:00Z',);print_r($stats);import dev.postproxy.PostProxy;
PostProxy client = new PostProxy("YOUR_API_KEY");var stats = client.posts().stats(GetStatsParams.builder() .postIds(List.of("abc123", "def456")) .profiles(List.of("instagram", "twitter")) .from("2026-02-01T00:00:00Z") .to("2026-02-24T00:00:00Z") .build());System.out.println(stats);using PostProxy;
var client = new PostProxyClient("YOUR_API_KEY");var stats = await client.Posts.StatsAsync(new PostStatsOptions{ PostIds = new[] { "abc123", "def456" }, Profiles = new[] { "instagram", "twitter" }, From = "2026-02-01T00:00:00Z", To = "2026-02-24T00:00:00Z",});Console.WriteLine(stats);Response:
{ "data": { "abc123": { "platforms": [ { "profile_id": "prof_abc", "platform": "instagram", "records": [ { "stats": { "impressions": 1200, "likes": 85, "comments": 12, "saved": 8 }, "recorded_at": "2026-02-20T12:00:00Z" }, { "stats": { "impressions": 1523, "likes": 102, "comments": 15, "saved": 11 }, "recorded_at": "2026-02-21T04:00:00Z" } ] } ] }, "def456": { "platforms": [ { "profile_id": "prof_def", "platform": "twitter", "records": [ { "stats": { "impressions": 430, "likes": 22, "retweets": 5 }, "recorded_at": "2026-02-20T12:00:00Z" } ] } ] } }}Response fields
Section titled “Response fields”| Field | Type | Description |
|---|---|---|
data | object | Keyed by post hashid |
data.<post_id>.platforms | array | Array of platform objects for this post |
platforms[].profile_id | string | Profile hashid |
platforms[].platform | string | Platform name (instagram, twitter, etc.) |
platforms[].records | array | Snapshots ordered by recorded_at ascending |
records[].stats | object | Platform-specific metrics (varies by platform) |
records[].recorded_at | string | ISO 8601 timestamp when the snapshot was captured |
Stats fields by platform
Section titled “Stats fields by platform”| Platform | Fields |
|---|---|
impressions, likes, comments, saved, profile_visits, follows | |
impressions, clicks, likes | |
| Threads | impressions, likes, replies, reposts, quotes, shares |
impressions, likes, retweets, comments, quotes, saved | |
| YouTube | impressions, likes, comments, saved |
impressions | |
| TikTok | impressions, likes, comments, shares |
impressions, likes, comments, saved, outbound_clicks |
Error responses
Section titled “Error responses”Missing post_ids parameter (400):
{ "status": 400, "error": "Bad Request", "message": "param is missing or the value is empty: post_ids"}Create post
Section titled “Create post”POST /api/posts
Creates a new post and publishes it to the specified platforms.
Request body
Section titled “Request body”| Name | Type | Required | Description |
|---|---|---|---|
post[body] | string | No* | Text content of the post |
post[scheduled_at] | string | No | ISO 8601 timestamp to schedule the post |
post[draft] | boolean | No | If true, creates a draft that won’t publish until reviewed |
profiles | array | Yes | Array of profile IDs or platform names |
media | array | No* | Array of media URLs or file uploads |
platforms | object | No | Platform-specific parameters |
profile_group_id | string | No | Profile group ID |
*Some platforms require media (Instagram, TikTok, YouTube). Some platforms require text content.
Draft posts
Section titled “Draft posts”Set draft: true to create a post that won’t be published automatically. Draft posts can be reviewed and then published using the Publish endpoint.
{ "post": { "body": "Content to review before posting", "draft": true }, "profiles": ["instagram"]}Profiles parameter
Section titled “Profiles parameter”The profiles array accepts either:
- Platform names:
"twitter","instagram","facebook", etc. - Uses the first connected profile for that platform - Profile IDs: Hashid of a specific profile
Media parameter
Section titled “Media parameter”You can provide media in two ways:
Option 1: URLs (JSON request)
Pass URLs to images or videos that Postproxy will download:
{ "media": [ "https://example.com/image1.jpg", "https://example.com/image2.png" ]}Option 2: File upload (multipart form)
Upload files directly using multipart/form-data:
curl -X POST "https://api.postproxy.dev/api/posts" \ -H "Authorization: Bearer YOUR_API_KEY" \ -F "post[body]=Check out this photo!" \ -F "profiles[]=instagram" \ -F "profiles[]=facebook" \ -F "media[]=@/path/to/image.jpg"import PostProxy from "postproxy-sdk";import fs from "fs";
const client = new PostProxy("YOUR_API_KEY");const post = await client.posts.create("Check out this photo!", ["instagram", "facebook"], { mediaFiles: [fs.createReadStream("/path/to/image.jpg")],});console.log(post);from postproxy import PostProxy
client = PostProxy("YOUR_API_KEY")post = await client.posts.create( "Check out this photo!", ["instagram", "facebook"], media_files=[open("/path/to/image.jpg", "rb")],)print(post)package main
import ( "fmt" "os" postproxy "github.com/postproxy/postproxy-go")
func main() { client := postproxy.New("YOUR_API_KEY") file, _ := os.Open("/path/to/image.jpg") defer file.Close()
post, _ := client.Posts.Create("Check out this photo!", []string{"instagram", "facebook"}, &postproxy.CreatePostOptions{ MediaFiles: []*os.File{file}, }) fmt.Println(post)}require "postproxy"
client = PostProxy::Client.new("YOUR_API_KEY")post = client.posts.create( "Check out this photo!", profiles: ["instagram", "facebook"], media_files: [File.open("/path/to/image.jpg")])puts postuse PostProxy\PostProxy;
$client = new PostProxy("YOUR_API_KEY");$post = $client->posts->create("Check out this photo!", ["instagram", "facebook"], [ "media_files" => ["/path/to/image.jpg"],]);print_r($post);import dev.postproxy.PostProxy;import java.io.File;import java.util.List;
PostProxy client = new PostProxy("YOUR_API_KEY");var post = client.posts().create( "Check out this photo!", List.of("instagram", "facebook"), new CreatePostOptions() .mediaFiles(List.of(new File("/path/to/image.jpg"))));System.out.println(post);using PostProxy;
var client = new PostProxyClient("YOUR_API_KEY");var post = await client.Posts.CreateAsync("Check out this photo!", ["instagram", "facebook"], new CreatePostOptions{ MediaFiles = [File.OpenRead("/path/to/image.jpg")],});Console.WriteLine(post);When using file upload, use form field names with brackets: post[body], profiles[], media[].
Platform-specific parameters
Section titled “Platform-specific parameters”Pass platform-specific options in the platforms object. See Platform Parameters for all available options.
{ "platforms": { "instagram": { "format": "reel", "first_comment": "Check the link in bio!" }, "youtube": { "title": "My Video Title", "privacy_status": "public" } }}Example
Section titled “Example”curl -X POST "https://api.postproxy.dev/api/posts" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "post": { "body": "Hello from the API!" }, "profiles": ["twitter", "linkedin", "threads"], "media": ["https://example.com/image.jpg"] }'import PostProxy from "postproxy-sdk";
const client = new PostProxy("YOUR_API_KEY");const post = await client.posts.create("Hello from the API!", ["twitter", "linkedin", "threads"], { media: ["https://example.com/image.jpg"],});console.log(post);from postproxy import PostProxy
client = PostProxy("YOUR_API_KEY")post = await client.posts.create( "Hello from the API!", ["twitter", "linkedin", "threads"], media=["https://example.com/image.jpg"],)print(post)package main
import ( "fmt" postproxy "github.com/postproxy/postproxy-go")
func main() { client := postproxy.New("YOUR_API_KEY") post, _ := client.Posts.Create("Hello from the API!", []string{"twitter", "linkedin", "threads"}, &postproxy.CreatePostOptions{ Media: []string{"https://example.com/image.jpg"}, }) fmt.Println(post)}require "postproxy"
client = PostProxy::Client.new("YOUR_API_KEY")post = client.posts.create( "Hello from the API!", profiles: ["twitter", "linkedin", "threads"], media: ["https://example.com/image.jpg"])puts postuse PostProxy\PostProxy;
$client = new PostProxy("YOUR_API_KEY");$post = $client->posts->create("Hello from the API!", ["twitter", "linkedin", "threads"], [ "media" => ["https://example.com/image.jpg"],]);print_r($post);import dev.postproxy.PostProxy;import java.util.List;
PostProxy client = new PostProxy("YOUR_API_KEY");var post = client.posts().create( "Hello from the API!", List.of("twitter", "linkedin", "threads"), new CreatePostOptions() .media(List.of("https://example.com/image.jpg")));System.out.println(post);using PostProxy;
var client = new PostProxyClient("YOUR_API_KEY");var post = await client.Posts.CreateAsync("Hello from the API!", ["twitter", "linkedin", "threads"], new CreatePostOptions{ Media = ["https://example.com/image.jpg"],});Console.WriteLine(post);Request body (JSON):
{ "post": { "body": "Hello from the API!" }, "profiles": [ "twitter", "linkedin", "threads" ], "media": [ "https://example.com/image.jpg" ]}Response (201 Created):
{ "id": "xyz789abc", "body": "Hello from the API!", "status": "processed", "scheduled_at": null, "created_at": "2024-01-15T10:30:00.000Z", "platforms": [ { "platform": "twitter", "status": "pending", "error": null, "params": null, "attempted_at": null }, { "platform": "linkedin", "status": "pending", "error": null, "params": null, "attempted_at": null }, { "platform": "threads", "status": "pending", "error": null, "params": null, "attempted_at": null } ]}Error responses
Section titled “Error responses”Missing profiles parameter (400):
{ "status": 400, "error": "Bad Request", "message": "param is missing or the value is empty: Missing profiles parameter"}Validation errors (422):
{ "errors": [ "Post profiles must have at least one profile selected", "Media is required for feed post on Instagram" ]}Delete post
Section titled “Delete post”DELETE /api/posts/:id
Deletes a post from the database. Note: This does not remove the post from social media platforms.
Path parameters
Section titled “Path parameters”| Name | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Post hashid |
Example
Section titled “Example”curl -X DELETE "https://api.postproxy.dev/api/posts/abc123xyz" \ -H "Authorization: Bearer YOUR_API_KEY"import PostProxy from "postproxy-sdk";
const client = new PostProxy("YOUR_API_KEY");const result = await client.posts.delete("abc123xyz");console.log(result);from postproxy import PostProxy
client = PostProxy("YOUR_API_KEY")result = await client.posts.delete("abc123xyz")print(result)package main
import ( "fmt" postproxy "github.com/postproxy/postproxy-go")
func main() { client := postproxy.New("YOUR_API_KEY") result, _ := client.Posts.Delete("abc123xyz") fmt.Println(result)}require "postproxy"
client = PostProxy::Client.new("YOUR_API_KEY")result = client.posts.delete("abc123xyz")puts resultuse PostProxy\PostProxy;
$client = new PostProxy("YOUR_API_KEY");$result = $client->posts->delete("abc123xyz");print_r($result);import dev.postproxy.PostProxy;
PostProxy client = new PostProxy("YOUR_API_KEY");var result = client.posts().delete("abc123xyz");System.out.println(result);using PostProxy;
var client = new PostProxyClient("YOUR_API_KEY");var result = await client.Posts.DeleteAsync("abc123xyz");Console.WriteLine(result);Response:
{ "deleted": true}Publish post
Section titled “Publish post”POST /api/posts/:id/publish
Publishes a draft post. Only posts with status: "draft" can be published using this endpoint.
Path parameters
Section titled “Path parameters”| Name | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Post hashid |
Example
Section titled “Example”curl -X POST "https://api.postproxy.dev/api/posts/abc123xyz/publish" \ -H "Authorization: Bearer YOUR_API_KEY"import PostProxy from "postproxy-sdk";
const client = new PostProxy("YOUR_API_KEY");const post = await client.posts.publishDraft("abc123xyz");console.log(post);from postproxy import PostProxy
client = PostProxy("YOUR_API_KEY")post = await client.posts.publish_draft("abc123xyz")print(post)package main
import ( "fmt" postproxy "github.com/postproxy/postproxy-go")
func main() { client := postproxy.New("YOUR_API_KEY") post, _ := client.Posts.PublishDraft("abc123xyz") fmt.Println(post)}require "postproxy"
client = PostProxy::Client.new("YOUR_API_KEY")post = client.posts.publish_draft("abc123xyz")puts postuse PostProxy\PostProxy;
$client = new PostProxy("YOUR_API_KEY");$post = $client->posts->publishDraft("abc123xyz");print_r($post);import dev.postproxy.PostProxy;
PostProxy client = new PostProxy("YOUR_API_KEY");var post = client.posts().publishDraft("abc123xyz");System.out.println(post);using PostProxy;
var client = new PostProxyClient("YOUR_API_KEY");var post = await client.Posts.PublishDraftAsync("abc123xyz");Console.WriteLine(post);Response:
{ "id": "abc123xyz", "content": "Hello World!", "status": "processing", "scheduled_at": null, "created_at": "2024-01-15T10:30:00.000Z", "platforms": [ { "platform": "instagram", "status": "processing", "params": { "format": "post" }, "attempted_at": null } ]}Error responses
Section titled “Error responses”Post not found (404):
{ "error": "Not found"}Post is not a draft (422):
{ "error": "Post is not a draft"}Post statuses
Section titled “Post statuses”Post-level status
Section titled “Post-level status”| Status | Description |
|---|---|
draft | Post is saved but not published, awaiting review |
processing | Post is being published to platforms |
processed | All platform publishing attempts completed |
scheduled | Post is scheduled for future publishing |
media_processing_failed | One or more media attachments failed to process |
Platform-level status
Section titled “Platform-level status”| Status | Description |
|---|---|
processing | Currently being published to this platform |
published | Successfully published |
failed | Publishing failed (check error message) |
deleted | Post was deleted on a platform |
Insights
Section titled “Insights”Insights (impressions/views) are collected periodically after a post is published. The insights object in the platform response contains:
| Field | Description |
|---|---|
impressions | Number of views/impressions on the platform |
on | Timestamp when the metrics were captured |
Insights are updated approximately every 8 hours for published posts.