publora

Publora API — schedule and publish social media posts across 11 platforms (X/Twitter, LinkedIn, Instagram, Threads, TikTok, YouTube, Facebook, Bluesky, Mastodon, Telegram, Pinterest). Use this skill when the user wants to post, schedule, draft, bulk-schedule, manage workspace users, configure webhooks, or retrieve LinkedIn analytics via Publora.

Safety Notice

This listing is from the official public ClawHub registry. Review SKILL.md and referenced scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "publora" with this command: npx skills add sergebulaev/publora

Publora API — Core Skill

Publora is an affordable REST API for scheduling and publishing social media posts across 11 platforms. Base URL: https://api.publora.com/api/v1

Authentication

All requests require the x-publora-key header. Keys start with sk_.

curl https://api.publora.com/api/v1/platform-connections \
  -H "x-publora-key: sk_YOUR_KEY"

Get your key: publora.com → Settings → API Keys → Generate API Key. ⚠️ Copy immediately — shown only once.

Step 0: Get Platform IDs

Always call this first to get valid platform IDs before posting.

const res = await fetch('https://api.publora.com/api/v1/platform-connections', {
  headers: { 'x-publora-key': 'sk_YOUR_KEY' }
});
const { connections } = await res.json();
// connections[i].platformId → e.g. "linkedin-ABC123", "twitter-456"
// Also returns: tokenStatus, tokenExpiresIn, lastSuccessfulPost, lastError

Platform IDs look like: twitter-123, linkedin-ABC, instagram-456, threads-789, etc.

Post Immediately

Omit scheduledTime to publish right away:

await fetch('https://api.publora.com/api/v1/create-post', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', 'x-publora-key': 'sk_YOUR_KEY' },
  body: JSON.stringify({
    content: 'Your post content here',
    platforms: ['twitter-123', 'linkedin-ABC']
  })
});

Schedule a Post

Include scheduledTime in ISO 8601 UTC — must be in the future:

await fetch('https://api.publora.com/api/v1/create-post', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', 'x-publora-key': 'sk_YOUR_KEY' },
  body: JSON.stringify({
    content: 'Scheduled post content',
    platforms: ['twitter-123', 'linkedin-ABC'],
    scheduledTime: '2026-03-16T10:00:00.000Z'
  })
});
// Response: { postGroupId: "pg_abc123", scheduledTime: "..." }

Save as Draft

Omit scheduledTime — post is created as draft. Schedule it later:

// Create draft
const { postGroupId } = await createPost({ content, platforms });

// Schedule later
await fetch(`https://api.publora.com/api/v1/update-post/${postGroupId}`, {
  method: 'PUT',
  headers: { 'Content-Type': 'application/json', 'x-publora-key': 'sk_YOUR_KEY' },
  body: JSON.stringify({ status: 'scheduled', scheduledTime: '2026-03-16T10:00:00.000Z' })
});

List Posts

Filter, paginate and sort your scheduled/published posts:

// GET /api/v1/list-posts
// Query params: status, platform, fromDate, toDate, page, limit, sortBy, sortOrder
const res = await fetch(
  'https://api.publora.com/api/v1/list-posts?status=scheduled&platform=twitter&page=1&limit=20',
  { headers: { 'x-publora-key': 'sk_YOUR_KEY' } }
);
const { posts, pagination } = await res.json();
// pagination: { page, limit, totalItems, totalPages, hasNextPage, hasPrevPage }

Valid statuses: draft, scheduled, published, failed, partially_published

Get / Delete a Post

# Get post details
GET /api/v1/get-post/:postGroupId

# Delete post (also removes media from storage)
DELETE /api/v1/delete-post/:postGroupId

Get Post Logs

Debug failed or partially published posts:

const res = await fetch(
  `https://api.publora.com/api/v1/post-logs/${postGroupId}`,
  { headers: { 'x-publora-key': 'sk_YOUR_KEY' } }
);
const { logs } = await res.json();

Test a Connection

Verify a platform connection is healthy before posting:

const res = await fetch(
  'https://api.publora.com/api/v1/test-connection/linkedin-ABC123',
  { method: 'POST', headers: { 'x-publora-key': 'sk_YOUR_KEY' } }
);
// Returns: { status: "ok"|"error", message, permissions, tokenExpiresIn }

Bulk Schedule (a Week of Content)

from datetime import datetime, timedelta, timezone
import requests

HEADERS = { 'Content-Type': 'application/json', 'x-publora-key': 'sk_YOUR_KEY' }
base_date = datetime(2026, 3, 16, 10, 0, 0, tzinfo=timezone.utc)

posts = ['Monday post', 'Tuesday post', 'Wednesday post', 'Thursday post', 'Friday post']

for i, content in enumerate(posts):
    scheduled_time = base_date + timedelta(days=i)
    requests.post('https://api.publora.com/api/v1/create-post', headers=HEADERS, json={
        'content': content,
        'platforms': ['twitter-123', 'linkedin-ABC'],
        'scheduledTime': scheduled_time.isoformat()
    })

Media Uploads

All media (images and videos) use a 3-step pre-signed upload workflow:

Step 1: POST /api/v1/create-post → get postGroupId
Step 2: POST /api/v1/get-upload-url → get uploadUrl
Step 3: PUT {uploadUrl} with file bytes (no auth needed for S3)

import requests

HEADERS = { 'Content-Type': 'application/json', 'x-publora-key': 'sk_YOUR_KEY' }

# Step 1: Create post
post = requests.post('https://api.publora.com/api/v1/create-post', headers=HEADERS, json={
    'content': 'Check this out!',
    'platforms': ['instagram-456'],
    'scheduledTime': '2026-03-15T14:30:00.000Z'
}).json()
post_group_id = post['postGroupId']

# Step 2: Get pre-signed upload URL
upload = requests.post('https://api.publora.com/api/v1/get-upload-url', headers=HEADERS, json={
    'fileName': 'photo.jpg',
    'contentType': 'image/jpeg',
    'type': 'image',  # or 'video'
    'postGroupId': post_group_id
}).json()

# Step 3: Upload directly to S3 (no auth header needed)
with open('./photo.jpg', 'rb') as f:
    requests.put(upload['uploadUrl'], headers={'Content-Type': 'image/jpeg'}, data=f)

For carousels: call get-upload-url N times with the same postGroupId.

Cross-Platform Threading

X/Twitter and Threads support auto-threading. Separate segments with --- on its own line:

await fetch('https://api.publora.com/api/v1/create-post', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', 'x-publora-key': 'sk_YOUR_KEY' },
  body: JSON.stringify({
    content: 'First tweet in the thread.\n\n---\n\nSecond tweet continues.\n\n---\n\nFinal tweet wraps up.',
    platforms: ['twitter-123', 'threads-789']
  })
});

⚠️ Threads Restriction: Multi-threaded nested posts (content auto-split into connected replies) are temporarily unavailable on Threads due to Threads app reconnection status. Single posts and carousels continue to work normally. Contact support@publora.com for updates.

LinkedIn Analytics

// Post statistics
await fetch('https://api.publora.com/api/v1/linkedin-post-statistics', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', 'x-publora-key': 'sk_YOUR_KEY' },
  body: JSON.stringify({
    postedId: 'urn:li:share:7123456789',
    platformId: 'linkedin-ABC123',
    queryTypes: 'ALL'  // or: IMPRESSION, MEMBERS_REACHED, RESHARE, REACTION, COMMENT
  })
});

// Profile summary (followers + aggregated stats)
await fetch('https://api.publora.com/api/v1/linkedin-profile-summary', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', 'x-publora-key': 'sk_YOUR_KEY' },
  body: JSON.stringify({ platformId: 'linkedin-ABC123' })
});

Available analytics endpoints:

EndpointDescription
POST /linkedin-post-statisticsImpressions, reactions, reshares for a post
POST /linkedin-account-statisticsAggregated account metrics
POST /linkedin-followersFollower count and growth
POST /linkedin-profile-summaryCombined profile overview
POST /linkedin-create-reactionReact to a post
DELETE /linkedin-delete-reactionRemove a reaction

Webhooks

Get real-time notifications when posts are published, fail, or tokens are expiring.

// Create a webhook
await fetch('https://api.publora.com/api/v1/webhooks', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', 'x-publora-key': 'sk_YOUR_KEY' },
  body: JSON.stringify({
    name: 'My webhook',
    url: 'https://myapp.com/webhooks/publora',
    events: ['post.published', 'post.failed', 'token.expiring']
  })
});
// Returns: { webhook: { _id, name, url, events, secret, isActive } }
// Save the `secret` — it's only shown once. Use it to verify webhook signatures.

Valid events: post.scheduled, post.published, post.failed, token.expiring

EndpointMethodDescription
/webhooksGETList all webhooks
/webhooksPOSTCreate webhook
/webhooks/:idPATCHUpdate webhook
/webhooks/:idDELETEDelete webhook
/webhooks/:id/regenerate-secretPOSTRotate webhook secret

Max 10 webhooks per account.

Workspace / B2B API

Manage multiple users under your workspace account. Contact serge@publora.com to enable Workspace API access.

// Create a managed user
const user = await fetch('https://api.publora.com/api/v1/workspace/users', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', 'x-publora-key': 'sk_CORP_KEY' },
  body: JSON.stringify({ email: 'client@example.com', displayName: 'Acme Corp' })
}).then(r => r.json());

// Generate connection URL for user to connect their social accounts
const { connectionUrl } = await fetch(
  `https://api.publora.com/api/v1/workspace/users/${user.id}/connection-url`,
  { method: 'POST', headers: { 'x-publora-key': 'sk_CORP_KEY' } }
).then(r => r.json());

// Post on behalf of managed user
await fetch('https://api.publora.com/api/v1/create-post', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-publora-key': 'sk_CORP_KEY',
    'x-publora-user-id': user.id  // ← key header for acting on behalf of a user
  },
  body: JSON.stringify({ content: 'Post for Acme Corp!', platforms: ['linkedin-XYZ'] })
});

Workspace endpoints:

EndpointMethodDescription
/workspace/usersGETList managed users
/workspace/usersPOSTCreate managed user
/workspace/users/:userIdDELETERemove managed user
/workspace/users/:userId/api-keyPOSTGenerate per-user API key
/workspace/users/:userId/connection-urlPOSTGenerate OAuth connection link

Each managed user has a limit of 100 posts/day (dailyPostsLeft). Never expose your workspace key client-side — use per-user API keys for client-facing scenarios.

Platform Limits Quick Reference (API)

⚠️ API limits are often stricter than native app limits. Always design against these.

PlatformChar LimitMax ImagesVideo MaxText Only?
Twitter/X280 (25K Premium)4 × 5MB2 min / 512MB
LinkedIn3,00020 × 5MB30 min / 500MB
Instagram2,20010 × 8MB (JPEG only)90s / 300MB
Threads50020 × 8MB5 min / 500MB
TikTok2,200Video only10 min / 4GB
YouTube5,000 descVideo only12h / 256GB
Facebook63,20610 × 10MB45 min / 2GB
Bluesky3004 × 1MB3 min / 100MB
Mastodon5004 × 16MB~99MB
Telegram4,096 (1,024 captions)10 × 10MB50MB (Bot API)

For full limits detail, see the docs/guides/platform-limits.md in the Publora API Docs.

Platform-Specific Skills

For platform-specific settings, limits, and examples:

  • publora-linkedin — LinkedIn posts + analytics + reactions
  • publora-twitter — X/Twitter posts & threads
  • publora-instagram — Instagram images/reels/carousels
  • publora-threads — Threads posts
  • publora-tiktok — TikTok videos
  • publora-youtube — YouTube videos
  • publora-facebook — Facebook page posts
  • publora-bluesky — Bluesky posts
  • publora-mastodon — Mastodon posts
  • publora-telegram — Telegram channels

Post Statuses

  • draft — Not scheduled yet
  • scheduled — Waiting to publish
  • published — Successfully posted
  • failed — Publishing failed (check /post-logs)
  • partially_published — Some platforms failed

Errors

CodeMeaning
400Invalid request (check scheduledTime format, required fields)
401Invalid or missing API key
403Plan limit reached or Workspace API not enabled
404Post/resource not found
429Platform rate limit exceeded

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

Ai Competitor Analyzer

提供AI驱动的竞争对手分析,支持批量自动处理,提升企业和专业团队分析效率与专业度。

Registry SourceRecently Updated
General

Ai Data Visualization

提供自动化AI分析与多格式批量处理,显著提升数据可视化效率,节省成本,适用企业和个人用户。

Registry SourceRecently Updated
General

Ai Cost Optimizer

提供基于预算和任务需求的AI模型成本优化方案,计算节省并指导OpenClaw配置与模型切换策略。

Registry SourceRecently Updated