AgentSkillsCN

late-api

管理 Late.co 社交媒体排期 API——包括列出、重新排期、批量删除以及同步已排期的帖子。在被要求管理已排期的帖子、清理 Late 队列、重新排期帖子、检查 Late API 状态,或排查 Late API 问题时,运用此技能。

SKILL.md
--- frontmatter
name: late-api
description: Manage Late.co social media scheduling API — list, reschedule, bulk delete, and sync scheduled posts. Use this skill when asked to manage scheduled posts, clean up the Late queue, reschedule posts, inspect Late API state, or troubleshoot Late API issues.

Late API Management Skill

Operational workflows for managing scheduled social media posts via the Late.co API (https://getlate.dev/api/v1). This skill helps you list, reschedule, bulk delete, and sync posts when the posting schedule changes or issues arise.

Prerequisites

  • LATE_API_KEY environment variable set (Bearer token, format: sk_...)
  • The project's schedule.json in the repo root defines posting time slots per platform

Authentication

All requests use Bearer auth:

bash
curl -H "Authorization: Bearer $env:LATE_API_KEY" https://getlate.dev/api/v1/posts

API Base URL

code
https://getlate.dev/api/v1

API Reference

Posts

MethodEndpointDescription
GET/v1/postsList posts. Supports query params: status (draft/scheduled/published/failed), platform, profileId, dateFrom, dateTo, createdBy, includeHidden
POST/v1/postsCreate a post. Fields: content, platforms (array of {platform, accountId}), scheduledFor (ISO datetime), timezone, isDraft, publishNow, mediaItems, queuedFromProfile, queueId, tags, hashtags, tiktokSettings, platformSpecificData
GET/v1/posts/{postId}Get a single post by ID
PUT/v1/posts/{postId}Update a post. Only draft/scheduled/failed/partial posts can be edited. Fields: content, scheduledFor, tiktokSettings
DELETE/v1/posts/{postId}Delete a post. Published posts cannot be deleted. Refunds upload quota
POST/v1/posts/bulk-uploadBulk upload from CSV. Optional dryRun query param

Accounts

MethodEndpointDescription
GET/v1/accountsList connected social media accounts

Profiles

MethodEndpointDescription
GET/v1/profilesList profiles
POST/v1/profilesCreate a profile

Queue (Late's built-in scheduling)

MethodEndpointDescription
GET/v1/queue/slots?profileId=XGet queue schedules for a profile. Add all=true for all queues
POST/v1/queue/slotsCreate a new queue. Body: profileId, name, timezone, slots, active
PUT/v1/queue/slotsUpdate queue. Body: profileId, queueId, timezone, slots, reshuffleExisting (auto-reschedule existing posts)
DELETE/v1/queue/slots?profileId=X&queueId=YDelete a queue
GET/v1/queue/preview?profileId=X&count=NPreview upcoming N queue slots
GET/v1/queue/next-slot?profileId=XPreview next available slot (informational only — do NOT use with scheduledFor)

Media

MethodEndpointDescription
POST/v1/media/presignGet presigned upload URL. Body: {filename, contentType}{uploadUrl, publicUrl, key, expiresIn}
PUT{uploadUrl}Upload file bytes to the presigned URL with Content-Type header

Analytics

MethodEndpointDescription
GET/v1/analyticsGet post performance metrics and engagement data

Publishing Logs

MethodEndpointDescription
GET/v1/logsView publishing attempt logs (API endpoint, status, request/response, retries). Retained 7 days

Webhooks

MethodEndpointDescription
GET/v1/webhooksList configured webhooks
POST/v1/webhooksCreate a webhook. Events: post.scheduled, post.published, post.failed, post.partial, account.connected, account.disconnected, message.received

Rate Limits

PlanRequests/min
Free60
Build120
Accelerate600
Unlimited1,200

Additional limits:

  • Velocity: 15 posts/hour/account
  • Daily: Platform-specific (X: 20, Pinterest: 25, Instagram/Facebook: 100, Threads: 250, others: 50)
  • Cooldown: Escalating backoff on repeated errors (10min → 20min → 40min → 24h)

Project-Specific Context

schedule.json Format

The project's schedule.json (repo root) defines local posting time slots:

json
{
  "timezone": "America/Chicago",
  "platforms": {
    "linkedin": {
      "slots": [
        { "days": ["tue", "wed"], "time": "08:00", "label": "Morning thought leadership" }
      ],
      "avoidDays": ["sat", "sun"]
    }
  }
}

Existing LateApiClient (src/services/lateApi.ts)

The project has a TypeScript client with these methods:

  • listProfiles()LateProfile[]
  • listAccounts()LateAccount[]
  • getScheduledPosts(platform?)LatePost[]
  • getDraftPosts(platform?)LatePost[]
  • createPost(params)LatePost
  • updatePost(postId, updates)LatePost
  • deletePost(postId)void
  • uploadMedia(filePath){url, type}
  • validateConnection(){valid, profileName?, error?}

Local Queue (src/services/postStore.ts)

Published posts are tracked locally in publish-queue/ (pending) and published/ (done). Each item has metadata.json with latePostId, scheduledFor, platform, accountId, status.

Scheduler (src/services/scheduler.ts)

findNextSlot(platform) finds the next available time slot by:

  1. Loading schedule.json config
  2. Fetching booked slots from Late API + local published items
  3. Generating candidates in 14-day chunks, sorted chronologically
  4. Returning the first unbooked candidate

Operational Workflows

1. List All Scheduled Posts

bash
curl -s -H "Authorization: Bearer $env:LATE_API_KEY" \
  "https://getlate.dev/api/v1/posts?status=scheduled" | python -m json.tool

Filter by platform:

bash
curl -s -H "Authorization: Bearer $env:LATE_API_KEY" \
  "https://getlate.dev/api/v1/posts?status=scheduled&platform=linkedin"

Filter by date range:

bash
curl -s -H "Authorization: Bearer $env:LATE_API_KEY" \
  "https://getlate.dev/api/v1/posts?status=scheduled&dateFrom=2026-02-01&dateTo=2026-03-01"

2. Reschedule a Single Post

bash
curl -s -X PUT -H "Authorization: Bearer $env:LATE_API_KEY" \
  -H "Content-Type: application/json" \
  "https://getlate.dev/api/v1/posts/{postId}" \
  -d '{"scheduledFor": "2026-02-20T08:00:00-06:00"}'

3. Bulk Reschedule All Posts (Schedule Change)

When schedule.json changes, use this workflow:

  1. Read the new schedule from schedule.json
  2. Fetch all scheduled posts from Late API
  3. For each post, compute the new optimal time slot based on the updated schedule
  4. Update each post with the new scheduledFor datetime via PUT /v1/posts/{postId}
  5. Report what changed (old time → new time for each post)

Important: Always confirm with the user before executing bulk reschedule. Show them the proposed changes first.

4. Bulk Delete Scheduled Posts

bash
# First list to confirm what will be deleted
curl -s -H "Authorization: Bearer $env:LATE_API_KEY" \
  "https://getlate.dev/api/v1/posts?status=scheduled&platform=twitter"

# Then delete each post by ID (published posts CANNOT be deleted)
curl -s -X DELETE -H "Authorization: Bearer $env:LATE_API_KEY" \
  "https://getlate.dev/api/v1/posts/{postId}"

Important: Always list and confirm with the user before deleting. Show post content previews.

5. Sync Local Queue with Late API

Compare local published/ metadata with Late API state:

  1. Read all local published items from recordings/*/publish-queue/ and published/
  2. For each item with a latePostId, fetch the Late post via GET /v1/posts/{postId}
  3. Report mismatches:
    • Orphaned in Late: Posts in Late API with no matching local item
    • Orphaned locally: Local items with latePostId that no longer exists in Late
    • Schedule mismatch: scheduledFor differs between local metadata and Late API

6. Validate Late API Connection

bash
curl -s -H "Authorization: Bearer $env:LATE_API_KEY" \
  "https://getlate.dev/api/v1/profiles"

If this returns profiles, the connection is valid. If 401, the API key is invalid or expired.

7. View Publishing Logs

bash
curl -s -H "Authorization: Bearer $env:LATE_API_KEY" \
  "https://getlate.dev/api/v1/logs"

Shows publishing attempts with platform API endpoint, HTTP status, request/response bodies, and retry info. Logs are retained for 7 days.

8. Inspect Connected Accounts

bash
curl -s -H "Authorization: Bearer $env:LATE_API_KEY" \
  "https://getlate.dev/api/v1/accounts" | python -m json.tool

Returns all connected social accounts with _id, platform, username, displayName, isActive, profileId.

9. Update Late Queue Slots (with auto-reshuffle)

If you want Late's built-in queue (not the local schedule.json) to reschedule existing posts:

bash
curl -s -X PUT -H "Authorization: Bearer $env:LATE_API_KEY" \
  -H "Content-Type: application/json" \
  "https://getlate.dev/api/v1/queue/slots" \
  -d '{
    "profileId": "PROFILE_ID",
    "timezone": "America/Chicago",
    "slots": [
      {"day": "tue", "time": "08:00"},
      {"day": "wed", "time": "12:00"}
    ],
    "reshuffleExisting": true
  }'

The reshuffleExisting: true flag tells Late to automatically move existing queued posts to match the new slots.


Safety Rules

  1. Never delete published posts — the API will reject it anyway (400 error)
  2. Always list before bulk operations — show the user what will be affected
  3. Confirm destructive actions — ask the user to approve before deleting or rescheduling multiple posts
  4. Use dryRun for bulk uploads — test with ?dryRun=true query param first
  5. Respect rate limits — add delays between bulk API calls (60 req/min on free plan)
  6. Handle 429 responses — check Retry-After header and wait before retrying

Troubleshooting

ProblemCauseFix
401 UnauthorizedInvalid or expired API keyCheck LATE_API_KEY env var, regenerate key at getlate.dev settings
429 Rate LimitedToo many requestsWait for Retry-After period, add delays between bulk calls
400 on DELETETrying to delete a published postPublished posts cannot be deleted — only draft/scheduled/failed
400 on PUTTrying to update a published postPublished/publishing/cancelled posts cannot be edited
Empty posts listWrong status filter or no posts existTry without status filter, check platform filter matches account
Media upload failsPresigned URL expired (1 hour)Request a new presigned URL and retry upload
Duplicate 409Same content posted to same account within 24hChange content or wait 24 hours
Account cooldownRepeated publishing errorsWait for cooldown to expire (escalating: 10min → 24h)