Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsBlogPro
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Authors
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges
  • Chrome Extension
  • Skill Manager

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

ProTermsPrivacyRefunds
Back to skills

Postthatlater

DSecurity

Schedule and manage social media posts across multiple social platforms. Query analytics, manage your queue, and publish immediately — all via natural language. Call GET /api/v1/platforms for the list of platforms active on this instance.

33 stars
0 votes
0 copies
2 views
Added 9/5/2026
content-marketinggobashapi

Works with

claude codeapi

Security Analysis

D46/100
mediumUses curl or wget to download content
criticalModifies startup scripts or system services for persistence
criticalModifies startup scripts or system services for persistence

Pro shows the line behind each finding and how to fix it

Scanned 9/5/2026

$npx -y skills add dvcrn/openclaw-skills-marketplace --skill postthatlater --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Postthatlater?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Postthatlater
[![Security: D — Skills Directory](https://www.skillsdirectory.com/api/skills/dvcrn-postthatlater/badge)](https://www.skillsdirectory.com/skills/dvcrn-postthatlater)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
Files
SKILL.md
---
name: PostThatLater
description: "Schedule and manage social media posts across multiple social platforms. Query analytics, manage your queue, and publish immediately — all via natural language. Call GET /api/v1/platforms for the list of platforms active on this instance."
homepage: https://postthatlater.com
---

# PostThatLater Skill

Schedule and manage social media posts from Claude Code or any AI assistant.

## Setup

### 1. Create an account

Sign up at https://postthatlater.com — a subscription is required to use the API.

### 2. Generate an API key

In PostThatLater: **Account Settings → API Keys → Create new key**

Copy the `sk_ptl_...` key — it's shown only once.

### 3. Set the environment variable

```bash
export PTL_API_KEY=sk_ptl_your_key_here
```

Add to `~/.zshrc` or `~/.bashrc` to persist across sessions.

### 4. Verify

```bash
curl https://postthatlater.com/api/v1/accounts \
  -H "Authorization: Bearer $PTL_API_KEY"
```

You should see your connected social media accounts.

---

## Base URL

```
https://postthatlater.com
```

All API requests require:
```
Authorization: Bearer $PTL_API_KEY
Content-Type: application/json   (for POST/PATCH)
```

---

## Critical Tips for Agents

1. **Call `GET /api/v1/accounts` first** — you need numeric account IDs to schedule posts. Never guess them.
2. **Ask for timezone once per session** — all `scheduled_at` values must be ISO 8601 UTC (e.g. `2026-03-10T09:00:00Z`). Convert from the user's local time.
3. **Confirm before `publish_now`** — publishing is immediate and irreversible. Always confirm with the user before calling the publish-now endpoint.
4. **Use `Idempotency-Key` on every POST/PATCH** — generate a UUID per request to prevent duplicate posts on retry. Example: `Idempotency-Key: $(uuidgen | tr '[:upper:]' '[:lower:]')`.
5. **Check platform limits** — always call `GET /api/v1/platforms` to get the live list of available platforms and their limits. Never hardcode a platform list or assume a platform is available.
6. **Cross-posting** — pass multiple IDs in `account_ids` to post the same content everywhere at once. The API creates one post record per account and links them via `group_id`.
7. **All times are UTC in responses** — convert to the user's timezone when displaying scheduled times.
8. **Posting with an image** — first `POST /api/v1/images` with the image URL to get a filename, then pass that filename in the `images` array of `POST /api/v1/posts`. Use `GET /api/v1/images` to list already-stored images that can be reused without re-uploading.

---

## Accounts

### List all connected accounts

```bash
curl https://postthatlater.com/api/v1/accounts \
  -H "Authorization: Bearer $PTL_API_KEY"
```

Response:
```json
{
  "data": [
    {
      "id": 12,
      "platform": "bluesky",
      "handle": "you.bsky.social",
      "display_name": "you.bsky.social",
      "status": "connected",
      "created_at": "2026-01-10T08:30:00.000Z",
      "updated_at": "2026-01-10T08:30:00.000Z"
    }
  ],
  "meta": { "request_id": "..." }
}
```

`status` is `"connected"` (healthy) or `"error"` (needs reconnecting in dashboard).

### Get a single account

```bash
curl https://postthatlater.com/api/v1/accounts/12 \
  -H "Authorization: Bearer $PTL_API_KEY"
```

---

## Posts

### List posts

```bash
curl "https://postthatlater.com/api/v1/posts?status=pending&limit=10&offset=0" \
  -H "Authorization: Bearer $PTL_API_KEY"
```

Query parameters:
- `status` — `pending`, `posted`, or `failed` (omit for all)
- `platform` — e.g. `bluesky`, `mastodon`, `linkedin`
- `limit` — max results (default: 20, max: 100)
- `offset` — skip N results for pagination (default: 0)

Response:
```json
{
  "data": [
    {
      "id": 101,
      "text": "Hello from the API!",
      "scheduled_at": "2026-03-15T09:00:00.000Z",
      "status": "pending",
      "platform": "bluesky",
      "account_id": 12,
      "images": [],
      "platform_post_id": null,
      "platform_post_url": null,
      "error_message": null,
      "retry_count": 0,
      "likes": 0,
      "comments": 0,
      "shares": 0,
      "group_id": null,
      "created_at": "2026-03-01T12:00:00.000Z",
      "updated_at": null
    }
  ],
  "meta": { "request_id": "...", "total": 5, "limit": 10, "offset": 0 }
}
```

### Create a post (schedule)

```bash
curl -X POST https://postthatlater.com/api/v1/posts \
  -H "Authorization: Bearer $PTL_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen | tr '[:upper:]' '[:lower:]')" \
  -d '{
    "text": "Hello from the PostThatLater API!",
    "scheduled_at": "2026-03-15T09:00:00.000Z",
    "account_ids": [12, 15]
  }'
```

Body parameters:
- `text` *(required)* — post content; must not exceed platform char limit
- `scheduled_at` *(required)* — ISO 8601 UTC datetime; must be in the future
- `account_ids` *(required)* — array of account IDs (at least one)
- `images` — optional array of image filenames

Returns HTTP `201` with the first created post. All posts share a `group_id`.

### Get a single post

```bash
curl https://postthatlater.com/api/v1/posts/101 \
  -H "Authorization: Bearer $PTL_API_KEY"
```

### Update a post

Only works on `pending` posts. Returns `409 conflict` if already published or failed.

```bash
curl -X PATCH https://postthatlater.com/api/v1/posts/101 \
  -H "Authorization: Bearer $PTL_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen | tr '[:upper:]' '[:lower:]')" \
  -d '{
    "text": "Updated content for the post",
    "scheduled_at": "2026-03-16T10:00:00.000Z"
  }'
```

### Delete a post

Cannot delete `posted` posts (returns `409`). Failed posts can be deleted.

```bash
curl -X DELETE https://postthatlater.com/api/v1/posts/101 \
  -H "Authorization: Bearer $PTL_API_KEY"
```

Response:
```json
{ "data": { "deleted": true, "id": 101 }, "meta": { "request_id": "..." } }
```

### Publish immediately

Bypasses the scheduler. Post must be `pending` or `failed`. **Irreversible — confirm with user first.**

```bash
curl -X POST https://postthatlater.com/api/v1/posts/101/publish-now \
  -H "Authorization: Bearer $PTL_API_KEY"
```

Response:
```json
{
  "data": {
    "id": 101,
    "status": "posted",
    "platform_post_url": "https://bsky.app/profile/you.bsky.social/post/...",
    ...
  },
  "meta": { "request_id": "..." }
}
```

---

## Images

Post with images by first ingesting the image from a URL, then passing the returned filename when creating a post.

### Ingest an image from a URL

Downloads, processes (EXIF rotation, compression, format conversion), and stores the image server-side. Returns a `filename` to use in posts.

```bash
curl -X POST https://postthatlater.com/api/v1/images \
  -H "Authorization: Bearer $PTL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/photo.jpg"}'
```

Response:
```json
{
  "data": { "filename": "1741036800000-123456789.jpeg" },
  "meta": { "request_id": "..." }
}
```

Pass the filename in the `images` array of `POST /api/v1/posts`. Check `GET /api/v1/platforms` for the `max_images` limit per platform.

### List stored images

Returns all images referenced by your posts with file metadata and which post IDs use each image. Use this to reuse an already-uploaded image without re-ingesting.

```bash
curl https://postthatlater.com/api/v1/images \
  -H "Authorization: Bearer $PTL_API_KEY"
```

Response:
```json
{
  "data": [
    {
      "filename": "1741036800000-123456789.jpeg",
      "url": "/uploads/1741036800000-123456789.jpeg",
      "size": 284672,
      "created_at": "2026-03-01T09:00:00.000Z",
      "referenced_by_post_ids": [101, 104]
    }
  ],
  "meta": { "request_id": "...", "total": 1 }
}
```

---

## Analytics

### Overall posting health summary

```bash
curl "https://postthatlater.com/api/v1/analytics/summary?period=30d" \
  -H "Authorization: Bearer $PTL_API_KEY"
```

Query parameters: `period` — `7d`, `30d`, `90d`, or `all` (default: `30d`)

Response:
```json
{
  "data": {
    "period": "30d",
    "total_posts": 45,
    "by_status": {
      "posted": 40,
      "pending": 3,
      "failed": 2
    },
    "success_rate": 95.2,
    "total_likes": 312,
    "total_comments": 48,
    "total_shares": 91,
    "total_engagement": 451
  },
  "meta": { "request_id": "..." }
}
```

### Top posts by engagement

```bash
curl "https://postthatlater.com/api/v1/analytics/top-posts?period=30d&limit=5" \
  -H "Authorization: Bearer $PTL_API_KEY"
```

Query parameters:
- `period` — `7d`, `30d`, or `all` (default: `30d`)
- `limit` — number of posts (default: 5, max: 20)

### Per-post metrics

```bash
curl https://postthatlater.com/api/v1/posts/101/metrics \
  -H "Authorization: Bearer $PTL_API_KEY"
```

Response:
```json
{
  "data": {
    "post_id": 101,
    "platform": "bluesky",
    "likes": 42,
    "comments": 8,
    "shares": 15,
    "engagement": 65,
    "published_at": "2026-03-01T09:00:00.000Z"
  },
  "meta": { "request_id": "..." }
}
```

### Breakdown by platform

```bash
curl "https://postthatlater.com/api/v1/analytics/by-platform?period=30d" \
  -H "Authorization: Bearer $PTL_API_KEY"
```

### Timeline (daily post counts)

```bash
curl "https://postthatlater.com/api/v1/analytics/timeline?period=7d" \
  -H "Authorization: Bearer $PTL_API_KEY"
```

---

## Platform Capabilities

**Public endpoint — no authentication required.**

Returns character limits and capabilities for all currently available platforms.
New platforms may be added over time, so always fetch this list rather than
hardcoding platform names or limits.

```bash
curl https://postthatlater.com/api/v1/platforms
```

Response fields per platform:
- `name` — slug used in API calls (e.g. `bluesky`)
- `display_name` — human-readable name
- `char_limit` — maximum post length in characters
- `max_images` — maximum images per post
- `supports_video` — whether video uploads are accepted
- `notes` — platform-specific connection or usage notes
```

---

## Error Handling

All errors follow:
```json
{
  "error": {
    "code": "validation_error",
    "message": "Validation failed.",
    "details": [
      { "field": "text", "message": "Text exceeds Bluesky character limit (300 chars)." },
      { "field": "scheduled_at", "message": "scheduled_at must be a future datetime." }
    ]
  }
}
```

| Code | HTTP | Meaning |
|------|------|---------|
| `invalid_api_key` | 401 | Missing, malformed, or revoked Bearer token |
| `subscription_required` | 402 | No active subscription |
| `not_found` | 404 | Resource doesn't exist or belongs to another user |
| `conflict` | 409 | Action not allowed in current state (e.g. editing a published post) |
| `validation_error` | 400 | Request body failed validation — check `details` array for field-level errors |
| `rate_limited` | 429 | 60 req/min per key — check `Retry-After` header |
| `internal_error` | 500 | Unexpected server error |

---

## Example Session

```
User: Schedule a post about our summer sale on Bluesky and Mastodon for tomorrow at 10am EST

Agent workflow:
1. GET /api/v1/accounts       → find Bluesky (id: 12) and Mastodon (id: 15)
2. GET /api/v1/platforms      → confirm char limits (300 / 500)
3. Convert 10am EST → 15:00 UTC (March 5 → 2026-03-05T15:00:00Z)
4. Confirm with user: "Ready to schedule 'Summer sale...' to Bluesky + Mastodon for Mar 5 at 10am EST?"
5. POST /api/v1/posts with account_ids: [12, 15] and Idempotency-Key header
6. Report back: "Scheduled! Post #101 and #102 will go out March 5 at 10am EST."
```

Attribution

dvcrndvcrn
View sourceSee grades on GitHubMore from dvcrn →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Postiz

Postiz is a tool to schedule social media and chat posts to 28+ channels X, LinkedIn, LinkedIn Page, Reddit, Instagram, Facebook Page, Threads, YouTube, Google My Business, TikTok, Pinterest, Dribbble, Discord, Slack, Kick, Twitch, Mastodon, Bluesky, Lemmy, Farcaster, Telegram, Nostr, VK, Medium, Dev.to, Hashnode, WordPress, ListMonk

21281 votes

Serp Analysis

SERP analysis techniques for intent classification, feature identification, and competitive intelligence. Use when analyzing search results for content strategy.

2831 votes

On Page Seo Auditor

This skill performs detailed on-page SEO audits to identify issues and optimization opportunities. It analyzes all on-page elements that affect search rankings and provides actionable recommendations.

1821 votes

Brand

Brand voice, visual identity, messaging frameworks, asset management, brand consistency. Activate for branded content, tone of voice, marketing assets, brand compliance, style guides.

1328090 votes

Release Announcement

Write a release announcement — changelog, blog post, in-app note, or social post — that leads with user impact, names the audience, and includes upgrade/migration steps without filler.

953190 votes
View all in content-marketing →