Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 48 additions & 12 deletions SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: late-api
description: Official Late API reference for scheduling posts across 13 social media platforms. Covers authentication, endpoints, webhooks, and platform-specific features. Use when building with the Late Social Media Scheduling API.
description: Official Late API (getlate.dev) reference for scheduling, publishing, and managing social media posts across 13 platforms. Use this skill whenever the user is working with getlate.dev, the Late social media scheduling API, connecting social accounts via Late OAuth, uploading media to Late, debugging Late API errors, or integrating Late into their app. Covers authentication, all endpoints, webhooks, platform-specific data, media uploads, and error handling. Always use this skill rather than guessing Late API shapes — Claude frequently gets the endpoint paths and field names wrong without it.
---

# Late API Reference
Expand All @@ -9,7 +9,7 @@ Schedule posts across 13 social media platforms with a single API.

**Base URL:** `https://getlate.dev/api/v1`

**Docs:** [getlate.dev/docs](https://getlate.dev/docs)
**Docs:** [docs.getlate.dev](https://docs.getlate.dev)

## Quick Start

Expand All @@ -19,32 +19,68 @@ curl -X POST https://getlate.dev/api/v1/profiles \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{"name": "My Brand"}'

# 2. Connect account (opens OAuth)
curl "https://getlate.dev/api/v1/connect/twitter?profileId=PROFILE_ID" \
# 2. Connect account (opens OAuth) — redirectUrl is required
curl "https://getlate.dev/api/v1/connect/twitter?profileId=PROFILE_ID&redirectUrl=https://yourapp.com/callback" \
-H "Authorization: Bearer YOUR_API_KEY"
# Returns { "authUrl": "https://twitter.com/oauth/..." } — redirect user there

# 3. Create post
curl -X POST https://getlate.dev/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{"content": "Hello!", "platforms": [{"platform": "twitter", "accountId": "ACC_ID"}], "publishNow": true}'
```

## Common Gotchas

These are the most frequent mistakes when using the Late API without reference docs:

| What Claude gets wrong | What's actually correct |
|------------------------|------------------------|
| `POST /profiles/{id}/connect` | `GET /v1/connect/{platform}?profileId=...&redirectUrl=...` |
| `POST /profiles/{id}/publish` | `POST /v1/posts` |
| `scheduledAt: "..."` | `scheduledFor: "..."` (ISO 8601) |
| `overrides: { twitter: {...} }` | `customContent: { twitter: "..." }` |
| `profiles: [{ profileKey: "..." }]` | `platforms: [{ platform: "twitter", accountId: "..." }]` |
| `platformSpecificData.postType: "story"` | `platformSpecificData.contentType: "story"` |
| Connect returns `{ url: "..." }` | Connect returns `{ authUrl: "..." }` |
| Media → use `uploadUrl` in post | Media → use `publicUrl` in post (not `uploadUrl`) |
| Upload media with FormData | Media uses presign flow: `POST /v1/media/presign` → PUT to `uploadUrl` |

## End-to-End Integration Guide

See [rules/integration-guide.md](rules/integration-guide.md) for a complete walkthrough: profile creation → OAuth connect → media upload → post with scheduling, custom content, and platform-specific data.

## Rule Files

Read individual rule files for detailed documentation:

- [rules/authentication.md](rules/authentication.md) - API key format, usage examples, core concepts
- [rules/posts.md](rules/posts.md) - Create, schedule, retry posts, bulk upload
- [rules/accounts.md](rules/accounts.md) - List accounts, health checks, follower stats
- [rules/connect.md](rules/connect.md) - OAuth flows, Bluesky app password, Telegram bot token
- [rules/platforms.md](rules/platforms.md) - Platform-specific data for all 13 platforms
- [rules/profiles.md](rules/profiles.md) - Create, list, update, delete profiles (account containers)
- [rules/posts.md](rules/posts.md) - Create, schedule, retry, unpublish posts, bulk upload; response schema
- [rules/accounts.md](rules/accounts.md) - List accounts, health checks, follower stats, Reddit flairs
- [rules/connect.md](rules/connect.md) - OAuth flows, headless mode, Bluesky, Telegram, Reddit subreddits; response schemas
- [rules/platforms.md](rules/platforms.md) - Platform-specific data for all 13 platforms including Reddit
- [rules/webhooks.md](rules/webhooks.md) - Configure webhooks, verify signatures, events
- [rules/media.md](rules/media.md) - Presigned uploads, supported formats, platform limits
- [rules/media.md](rules/media.md) - Presigned uploads, custom media per platform, auto-compression; response schemas
- [rules/queue.md](rules/queue.md) - Queue management, slots configuration
- [rules/analytics.md](rules/analytics.md) - YouTube daily views, LinkedIn analytics
- [rules/tools.md](rules/tools.md) - Media download, hashtag checker, transcripts
- [rules/errors.md](rules/errors.md) - Error codes, rate limits, publishing logs
- [rules/analytics.md](rules/analytics.md) - Daily metrics, best times, content decay, YouTube, LinkedIn
- [rules/tools.md](rules/tools.md) - Media download, validation endpoints, hashtag checker
- [rules/errors.md](rules/errors.md) - Error codes, rate limits, duplicate detection, platform errors
- [rules/sdks.md](rules/sdks.md) - Direct API usage examples
- [rules/integration-guide.md](rules/integration-guide.md) - Full end-to-end integration walkthrough

## Pricing Context

Late plans affect architecture decisions in multi-tenant apps:

| Plan | Profiles | Posts/mo | Use case |
|------|----------|----------|----------|
| Free | 2 | 20 | Testing only |
| Build ($19/mo) | 10 | 120 | Personal tools only — 120 posts/mo is a shared pool |
| Accelerate ($49/mo) | 50 (stackable) | Unlimited | Minimum viable for multi-user SaaS |
| Unlimited ($999/mo) | Unlimited | Unlimited | Scale |

**For multi-user SaaS**: each end-user = 1 profile. Build plan's 120 post/mo limit is account-level (shared across all users) — makes it unusable for SaaS. Use Accelerate minimum.

## Supported Platforms

Expand Down
20 changes: 20 additions & 0 deletions rules/accounts.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
| `PUT` | `/v1/accounts/{accountId}/pinterest-boards` | Set default Pinterest board |
| `GET` | `/v1/accounts/{accountId}/reddit-subreddits` | List user's subreddits |
| `PUT` | `/v1/accounts/{accountId}/reddit-subreddits` | Set default subreddit |
| `GET` | `/v1/accounts/{accountId}/reddit-flairs` | List available flairs for a subreddit |

## List Accounts

Expand Down Expand Up @@ -53,3 +54,22 @@ Response indicates if tokens are valid or need reconnection.
| `DELETE` | `/v1/account-groups/{groupId}` | Delete account group |

Account groups let you organize accounts for bulk posting operations.

## Reddit-Specific Account Endpoints

```bash
# List subreddits the Reddit account can post to
curl "https://getlate.dev/api/v1/accounts/ACCOUNT_ID/reddit-subreddits" \
-H "Authorization: Bearer YOUR_API_KEY"

# Set default posting subreddit
curl -X PUT "https://getlate.dev/api/v1/accounts/ACCOUNT_ID/reddit-subreddits" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"subreddit": "distrilicious"}'

# List available flairs for a subreddit (many subreddits require flair)
curl "https://getlate.dev/api/v1/accounts/ACCOUNT_ID/reddit-flairs?subreddit=distrilicious" \
-H "Authorization: Bearer YOUR_API_KEY"
# Returns: array of { id, text, ... } — use id as flairId in platformSpecificData
```
85 changes: 73 additions & 12 deletions rules/analytics.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,76 @@
| Method | Endpoint | Description |
|--------|----------|-------------|
| `GET` | `/v1/analytics` | Get general analytics |
| `GET` | `/v1/analytics/youtube/daily-views` | Get YouTube video daily views |
| `GET` | `/v1/accounts/{accountId}/linkedin-aggregate-analytics` | LinkedIn account analytics |
| `GET` | `/v1/accounts/{accountId}/linkedin-post-analytics` | LinkedIn post analytics |
| `GET` | `/v1/accounts/follower-stats` | Follower count history |
| `GET` | `/v1/analytics/daily-metrics` | Daily aggregated metrics with platform breakdown |
| `GET` | `/v1/analytics/best-time-to-post` | Optimal posting times by day/hour |
| `GET` | `/v1/analytics/content-decay` | Engagement accumulation over time |
| `GET` | `/v1/analytics/posting-frequency` | Posting cadence vs engagement correlation |
| `GET` | `/v1/analytics/post-timeline` | Daily metric evolution for a specific post |
| `GET` | `/v1/analytics/youtube-daily-views` | YouTube video daily view counts |
| `GET` | `/v1/analytics/linkedin-aggregate` | LinkedIn account aggregate analytics |
| `GET` | `/v1/analytics/linkedin-post` | LinkedIn post analytics by URN |
| `GET` | `/v1/analytics/follower-stats` | Follower count history and growth |

## General Analytics

```bash
curl "https://getlate.dev/api/v1/analytics?profileId=PROFILE_ID" \
-H "Authorization: Bearer YOUR_API_KEY"
```

Optional filter: `?postId=POST_ID` to get analytics for a specific post.

Analytics responses include `latePostId` field for correlation with scheduled posts (added Jan 2026).

## Daily Metrics (Feb 2026)

```bash
curl "https://getlate.dev/api/v1/analytics/daily-metrics?profileId=PROFILE_ID&startDate=2026-02-01&endDate=2026-02-28" \
-H "Authorization: Bearer YOUR_API_KEY"
```

Returns daily aggregated analytics metrics with platform breakdown.

## Best Time to Post (Feb 2026)

```bash
curl "https://getlate.dev/api/v1/analytics/best-time-to-post?profileId=PROFILE_ID" \
-H "Authorization: Bearer YOUR_API_KEY"
```

Returns optimal posting slots by day/hour based on historical engagement data.

## Content Decay (Feb 2026)

```bash
curl "https://getlate.dev/api/v1/analytics/content-decay?postId=POST_ID" \
-H "Authorization: Bearer YOUR_API_KEY"
```

Shows how engagement accumulates over time after publishing — useful for understanding content shelf life.

## Posting Frequency (Feb 2026)

```bash
curl "https://getlate.dev/api/v1/analytics/posting-frequency?profileId=PROFILE_ID" \
-H "Authorization: Bearer YOUR_API_KEY"
```

Correlates posting cadence with engagement rates — helps find the optimal number of posts per day/week.

## Post Timeline (Mar 2026)

```bash
curl "https://getlate.dev/api/v1/analytics/post-timeline?postId=POST_ID" \
-H "Authorization: Bearer YOUR_API_KEY"
```

Returns daily timeline showing metric evolution for a specific post, broken down by platform.

## YouTube Daily Views

```bash
curl "https://getlate.dev/api/v1/analytics/youtube/daily-views?accountId=ACCOUNT_ID&videoId=VIDEO_ID&startDate=2024-01-01&endDate=2024-01-31" \
curl "https://getlate.dev/api/v1/analytics/youtube-daily-views?accountId=ACCOUNT_ID&videoId=VIDEO_ID&startDate=2026-01-01&endDate=2026-01-31" \
-H "Authorization: Bearer YOUR_API_KEY"
```

Expand All @@ -24,13 +85,13 @@ Response:
"success": true,
"videoId": "dQw4w9WgXcQ",
"dateRange": {
"startDate": "2024-01-01",
"endDate": "2024-01-31"
"startDate": "2026-01-01",
"endDate": "2026-01-31"
},
"totalViews": 15420,
"dailyViews": [
{
"date": "2024-01-01",
"date": "2026-01-01",
"views": 523,
"estimatedMinutesWatched": 1045,
"averageViewDuration": 120,
Expand All @@ -50,19 +111,19 @@ Response:

```bash
# Aggregate analytics for account
curl "https://getlate.dev/api/v1/accounts/ACCOUNT_ID/linkedin-aggregate-analytics" \
curl "https://getlate.dev/api/v1/analytics/linkedin-aggregate?accountId=ACCOUNT_ID" \
-H "Authorization: Bearer YOUR_API_KEY"

# Analytics for specific post
curl "https://getlate.dev/api/v1/accounts/ACCOUNT_ID/linkedin-post-analytics?postUrn=URN" \
curl "https://getlate.dev/api/v1/analytics/linkedin-post?accountId=ACCOUNT_ID&postUrn=URN" \
-H "Authorization: Bearer YOUR_API_KEY"
```

## Follower Stats

```bash
curl "https://getlate.dev/api/v1/accounts/follower-stats?profileId=PROFILE_ID" \
curl "https://getlate.dev/api/v1/analytics/follower-stats?profileId=PROFILE_ID" \
-H "Authorization: Bearer YOUR_API_KEY"
```

Returns historical follower counts across all connected accounts.
Returns historical follower counts and growth metrics across all connected accounts.
73 changes: 64 additions & 9 deletions rules/connect.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,30 @@
| Method | Endpoint | Description |
|--------|----------|-------------|
| `GET` | `/v1/connect/{platform}` | Start OAuth flow |
| `GET` | `/v1/connect/get-connect-url` | Start OAuth flow (generic, supports headless) |
| `POST` | `/v1/connect/callback` | Exchange OAuth code for tokens |
| `GET` | `/v1/connect/pending-data` | Get pending OAuth data (headless mode) |
| `POST` | `/v1/connect/bluesky/credentials` | Connect Bluesky (app password) |
| `GET` | `/v1/connect/telegram` | Generate Telegram access code |
| `POST` | `/v1/connect/telegram` | Direct connect via chat ID |
| `PATCH` | `/v1/connect/telegram` | Poll connection status |

## Platform Selection Endpoints

Some platforms require selecting a page/location after OAuth:
Some platforms require selecting a page/location/subreddit after OAuth:

| Method | Endpoint | Description |
|--------|----------|-------------|
| `GET` | `/v1/connect/facebook/select-page` | List Facebook pages |
| `GET` | `/v1/connect/facebook/pages` | List Facebook pages |
| `POST` | `/v1/connect/facebook/select-page` | Select Facebook page |
| `GET` | `/v1/connect/linkedin/organizations` | List available LinkedIn orgs |
| `POST` | `/v1/connect/linkedin/select-organization` | Select LinkedIn org |
| `GET` | `/v1/connect/googlebusiness/locations` | List GMB locations |
| `POST` | `/v1/connect/googlebusiness/select-location` | Select GMB location |
| `GET` | `/v1/connect/google-business/locations` | List GMB locations |
| `POST` | `/v1/connect/google-business/select-location` | Select GMB location |
| `GET` | `/v1/connect/pinterest/select-board` | List Pinterest boards |
| `POST` | `/v1/connect/pinterest/select-board` | Select Pinterest board |
| `GET` | `/v1/connect/reddit/subreddits` | List Reddit subreddits (during connect) |
| `POST` | `/v1/connect/reddit/update-subreddits` | Set default subreddit (during connect) |
| `GET` | `/v1/connect/snapchat/select-profile` | List Snapchat profiles |
| `POST` | `/v1/connect/snapchat/select-profile` | Select Snapchat profile |

Expand All @@ -33,11 +38,36 @@ Some platforms require selecting a page/location after OAuth:

```bash
# Get OAuth URL
curl "https://getlate.dev/api/v1/connect/twitter?profileId=PROFILE_ID&callbackUrl=https://yourapp.com/callback" \
curl "https://getlate.dev/api/v1/connect/twitter?profileId=PROFILE_ID&redirectUrl=https://yourapp.com/callback" \
-H "Authorization: Bearer YOUR_API_KEY"
```

Returns `{ "url": "https://twitter.com/oauth/..." }` - redirect user there.
Returns `{ "authUrl": "https://twitter.com/oauth/..." }` — redirect user there.

**Query parameters:**
- `profileId` (required) — the Late profile ID
- `redirectUrl` (required) — where to redirect after OAuth completes

### Headless Mode (custom UI)

For apps that want full control over the OAuth UI:

```bash
# Get connect URL with headless mode
curl "https://getlate.dev/api/v1/connect/get-connect-url?profileId=PROFILE_ID&redirectUrl=https://yourapp.com/callback&headless=true" \
-H "Authorization: Bearer YOUR_API_KEY"
```

Returns `{ "authUrl": "...", "connectToken": "tok_..." }`.

Use `connectToken` in subsequent calls via `X-Connect-Token` header:

```bash
# Get pending OAuth data after user completes consent
curl "https://getlate.dev/api/v1/connect/pending-data?token=PENDING_DATA_TOKEN" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "X-Connect-Token: tok_..."
```

### Bluesky (App Password)

Expand All @@ -48,7 +78,7 @@ curl -X POST https://getlate.dev/api/v1/connect/bluesky/credentials \
-d '{
"profileId": "PROFILE_ID",
"identifier": "user.bsky.social",
"appPassword": "xxxx-xxxx-xxxx-xxxx"
"password": "xxxx-xxxx-xxxx-xxxx"
}'
```

Expand Down Expand Up @@ -85,18 +115,43 @@ curl -X POST https://getlate.dev/api/v1/connect/telegram \

The Late bot must already be added as admin in your channel/group.

## Reddit OAuth Flow

Reddit requires subreddit selection after connecting:

```bash
# 1. Start OAuth
curl "https://getlate.dev/api/v1/connect/reddit?profileId=PROFILE_ID&redirectUrl=https://yourapp.com/callback" \
-H "Authorization: Bearer YOUR_API_KEY"
# Returns: { "authUrl": "https://www.reddit.com/api/v1/authorize?..." }

# 2. After user completes OAuth, list available subreddits
curl "https://getlate.dev/api/v1/connect/reddit/subreddits?profileId=PROFILE_ID" \
-H "Authorization: Bearer YOUR_API_KEY"

# 3. Set default subreddit
curl -X POST "https://getlate.dev/api/v1/connect/reddit/update-subreddits" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"profileId": "PROFILE_ID", "subreddit": "distrilicious"}'
```

You can also manage subreddits post-connect via the Accounts API:
- `GET /v1/accounts/{accountId}/reddit-subreddits`
- `PUT /v1/accounts/{accountId}/reddit-subreddits`

## Supported Platforms

| Platform | Auth Method | Notes |
|----------|-------------|-------|
| Twitter/X | OAuth 2.0 PKCE | Requires code verifier |
| Instagram | OAuth 2.0 | 2-step token exchange |
| Facebook | OAuth 2.0 | Requires page selection |
| LinkedIn | OAuth 2.0 | Optional org selection |
| LinkedIn | OAuth 2.0 | Optional org selection; headless restructured Jan 2026 |
| TikTok | OAuth 2.0 | UX compliance required |
| YouTube | Google OAuth | access_type=offline |
| Pinterest | OAuth 2.0 | Requires board selection |
| Reddit | OAuth 2.0 | Strict user-agent |
| Reddit | OAuth 2.0 | Strict user-agent; requires subreddit selection |
| Bluesky | App password | No OAuth, uses AT Protocol |
| Threads | OAuth 2.0 | Similar to Instagram |
| Google Business | Google OAuth | Requires location selection |
Expand Down
Loading