# Send Publora to your agent
Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.
## Fast path
- Download the package from Yavira.
- Extract it into a folder your agent can access.
- Paste one of the prompts below and point your agent at the extracted folder.
## Suggested prompts
### New install

```text
I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete.
```
### Upgrade existing

```text
I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run.
```
## Machine-readable fields
```json
{
  "schemaVersion": "1.0",
  "item": {
    "slug": "publora",
    "name": "Publora",
    "source": "tencent",
    "type": "skill",
    "category": "开发工具",
    "sourceUrl": "https://clawhub.ai/sergebulaev/publora",
    "canonicalUrl": "https://clawhub.ai/sergebulaev/publora",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadUrl": "/downloads/publora",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=publora",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "packageFormat": "ZIP package",
    "primaryDoc": "SKILL.md",
    "includedAssets": [
      "SKILL.md"
    ],
    "downloadMode": "redirect",
    "sourceHealth": {
      "source": "tencent",
      "slug": "publora",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-05-07T14:17:31.161Z",
      "expiresAt": "2026-05-14T14:17:31.161Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=publora",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=publora",
        "contentDisposition": "attachment; filename=\"publora-1.2.1.zip\"",
        "redirectLocation": null,
        "bodySnippet": null,
        "slug": "publora"
      },
      "scope": "item",
      "summary": "Item download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this item.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/publora"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    }
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/publora",
    "downloadUrl": "https://openagent3.xyz/downloads/publora",
    "agentUrl": "https://openagent3.xyz/skills/publora/agent",
    "manifestUrl": "https://openagent3.xyz/skills/publora/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/publora/agent.md"
  }
}
```
## Documentation

### 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:

EndpointDescriptionPOST /linkedin-post-statisticsImpressions, reactions, reshares for a postPOST /linkedin-account-statisticsAggregated account metricsPOST /linkedin-followersFollower count and growthPOST /linkedin-profile-summaryCombined profile overviewPOST /linkedin-create-reactionReact to a postDELETE /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

CodeMeaning400Invalid request (check scheduledTime format, required fields)401Invalid or missing API key403Plan limit reached or Workspace API not enabled404Post/resource not found429Platform rate limit exceeded
## Trust
- Source: tencent
- Verification: Indexed source record
- Publisher: sergebulaev
- Version: 1.2.0
## Source health
- Status: healthy
- Item download looks usable.
- Yavira can redirect you to the upstream package for this item.
- Health scope: item
- Reason: direct_download_ok
- Checked at: 2026-05-07T14:17:31.161Z
- Expires at: 2026-05-14T14:17:31.161Z
- Recommended action: Download for OpenClaw
## Links
- [Detail page](https://openagent3.xyz/skills/publora)
- [Send to Agent page](https://openagent3.xyz/skills/publora/agent)
- [JSON manifest](https://openagent3.xyz/skills/publora/agent.json)
- [Markdown brief](https://openagent3.xyz/skills/publora/agent.md)
- [Download page](https://openagent3.xyz/downloads/publora)