Skip to content

Late.dev API Reference (Grounding Document)

Source: docs.getlate.dev — Official Late API Documentation

Last verified: 2026-02-09

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


Authentication

All requests require a Bearer token in the Authorization header:

Authorization: Bearer YOUR_API_KEY

API keys are generated from the Late Dashboard.


Endpoints Overview

Core

MethodEndpointDescription
GET/v1/postsList posts (paginated, filterable)
POST/v1/postsCreate draft, scheduled, or immediate post
GET/v1/posts/{postId}Get single post
PUT/v1/posts/{postId}Update draft/scheduled/failed post
DELETE/v1/posts/{postId}Delete draft/scheduled post
POST/v1/posts/{postId}/retryRetry a failed post
POST/v1/posts/bulk-uploadBulk create from CSV
GET/v1/accountsList connected social accounts
DELETE/v1/accounts/{accountId}Disconnect account
PUT/v1/accounts/{accountId}Update account display info
GET/v1/accounts/healthCheck health of all accounts
GET/v1/accounts/{accountId}/healthCheck health of specific account
GET/v1/accounts/follower-statsFollower growth metrics (requires analytics)
GET/v1/connect/{platform}Start OAuth connection flow
GET/v1/profilesList profiles
POST/v1/profilesCreate profile
GET/v1/analyticsPost analytics (requires analytics add-on)

Utilities

MethodEndpointDescription
POST/v1/media/presignGet presigned upload URL (up to 5GB)
GET/v1/queue/next-slotGet next queue slot

Create Post (POST /v1/posts)

Request Body

typescript
{
  // Content
  title?: string                    // Post title (used by YouTube, Pinterest)
  content?: string                  // Caption/text. Optional when media attached or customContent set.
                                    // Required for text-only posts.

  // ⚠️ MEDIA — Use mediaItems, NOT mediaUrls
  mediaItems?: MediaItem[]          // Array of media objects (see below)

  // Targeting
  platforms: PlatformTarget[]       // Required — at least one platform

  // Scheduling
  scheduledFor?: string             // ISO 8601 datetime (e.g. "2024-11-01T10:00:00Z")
  publishNow?: boolean              // Default: false. Set true for immediate publish.
  isDraft?: boolean                 // Default: false. Saves without scheduling.
  timezone?: string                 // Default: "UTC" (e.g. "America/New_York")

  // Queue scheduling (alternative to scheduledFor)
  queuedFromProfile?: string        // Profile ID — auto-assigns next slot
  queueId?: string                  // Specific queue (optional, uses default if omitted)
  // ⚠️ Do NOT call /queue/next-slot then use scheduledFor — that bypasses queue locking

  // Metadata
  tags?: string[]                   // Tags/keywords (YouTube: ≤100 chars each, ≤500 total)
  hashtags?: string[]
  mentions?: string[]
  crosspostingEnabled?: boolean     // Default: true
  metadata?: object

  // TikTok shorthand (merged into each TikTok platform entry)
  tiktokSettings?: TikTokSettings
}

MediaItem Object

typescript
interface MediaItem {
  type: 'image' | 'video'          // Required
  url: string                       // Public URL (from presign flow)
  thumbnail?: {                     // Optional — YouTube custom thumbnail
    url: string                     // Thumbnail public URL
  }
}

Example:

json
{
  "mediaItems": [
    { "type": "video", "url": "https://media.getlate.dev/temp/123_abc_video.mp4" }
  ]
}

PlatformTarget Object

typescript
interface PlatformTarget {
  platform: string                  // "twitter" | "instagram" | "tiktok" | "youtube" | "linkedin" | etc.
  accountId: string                 // Account ID from GET /v1/accounts
  platformSpecificData?: object     // Platform-specific settings (see below)
  customContent?: string            // Override content for this platform
  customMedia?: MediaItem[]         // Override media for this platform
}

Response Shape

json
// 201 Created
{
  "post": {
    "_id": "65f1c0a9e2b5af0012ab34cd",
    "content": "...",
    "status": "scheduled",
    "scheduledFor": "2024-11-01T10:00:00Z",
    "platforms": [{
      "platform": "twitter",
      "accountId": { "_id": "64e1f0...", "platform": "twitter", "username": "@acme", ... },
      "status": "pending"
    }]
  },
  "message": "Post scheduled successfully"
}

Error Responses

StatusMeaningExample
400Validation error{"error": "Tiktok posts require media content (images or videos)"}
401Bad/missing API key{"error": "Unauthorized"}
403Permission denied{"error": "..."}
409Duplicate content{"error": "This exact content was already posted...", "details": {...}}
429Rate limited{"error": "...", "details": {}} — check Retry-After header

List Posts (GET /v1/posts)

Query Parameters

ParamTypeDescription
pageintegerPage number (1-based). Default: 1
limitintegerPage size (1–100). Default: 10
statusstring"draft" | "scheduled" | "published" | "failed"
platformstringFilter by platform
profileIdstringFilter by profile
createdBystringFilter by creator
dateFromstringISO date filter
dateTostringISO date filter
includeHiddenbooleanDefault: false

Response Shape

json
{
  "posts": [...],
  "pagination": { "page": 1, "limit": 10, "total": 42, "pages": 5 }
}

Media Upload (Presign Flow)

Step 1: Get presigned URL

POST /v1/media/presign
{
  "filename": "my-video.mp4",
  "contentType": "video/mp4",
  "size": 702000000           // Optional — pre-validate size (max 5GB)
}

Allowed content types: image/jpeg, image/jpg, image/png, image/webp, image/gif, video/mp4, video/mpeg, video/quicktime, video/avi, video/x-msvideo, video/webm, video/x-m4v, application/pdf

Response:

json
{
  "uploadUrl": "<presigned-r2-url>",
  "publicUrl": "https://media.getlate.dev/temp/1234567890_abc123_my-video.mp4",
  "key": "temp/1234567890_abc123_my-video.mp4",
  "type": "video"
}

Step 2: Upload file to presigned URL

PUT {uploadUrl}
Content-Type: video/mp4
Content-Length: 702000000
Body: <file bytes>
  • Presigned URLs expire in 3600 seconds (1 hour)
  • Public URLs are served from media.getlate.dev CDN
  • URLs are immediately accessible after upload — no confirmation step needed

Step 3: Use publicUrl in createPost

json
{
  "mediaItems": [{ "type": "video", "url": "https://media.getlate.dev/temp/..." }]
}

Accounts (GET /v1/accounts)

Response Shape

json
{
  "accounts": [
    {
      "_id": "64e1...",
      "platform": "twitter",
      "profileId": { "_id": "64f0...", "name": "My Brand", "slug": "my-brand" },
      "username": "@acme",
      "displayName": "Acme",
      "profileUrl": "https://x.com/acme",
      "isActive": true
    }
  ],
  "hasAnalyticsAccess": false
}

Query Parameters

ParamTypeDescription
profileIdstringFilter by profile
includeOverLimitbooleanInclude over-plan-limit accounts

Profiles (GET /v1/profiles)

Response Shape

json
{
  "profiles": [
    {
      "_id": "prof_abc123",
      "name": "My First Profile",
      "description": "...",
      "createdAt": "2024-01-15T10:00:00.000Z"
    }
  ]
}

Platform-Specific Settings

Settings go in platformSpecificData within each platforms[] entry:

json
{
  "platforms": [{
    "platform": "youtube",
    "accountId": "acc_123",
    "platformSpecificData": {
      "title": "My Video Title",
      "visibility": "public"
    }
  }]
}

Twitter/X

PropertyTypeDescription
threadItemsarray[{content, mediaItems?}] — multi-tweet thread

Instagram

PropertyTypeDescription
contentType"story"Publish as Instagram Story
shareToFeedbooleanFor Reels: show on profile feed (default: true)
collaboratorsstring[]Up to 3 usernames as collaborators
firstCommentstringAuto-post first comment
userTagsarray[{username, x, y}] — tag users in photos
audioNamestringCustom audio name for Reels
thumbOffsetintegerMillisecond offset for Reel thumbnail

YouTube

PropertyTypeDescription
titlestringVideo title (max 100 chars, defaults to first line of content)
visibility"public" | "private" | "unlisted"Default: "public"
madeForKidsbooleanCOPPA flag (default: false)
firstCommentstringAuto-post first comment (max 10k chars)
tagsstring[]Video tags (≤100 chars each, ≤500 total)
containsSyntheticMediabooleanAI content disclosure
categoryIdstringCategory (default: "22" People & Blogs). Common: "27" Education, "28" Science & Technology

Auto-detection: Videos ≤3 min → YouTube Shorts. Videos >3 min → Regular video.

TikTok

⚠️ Required consent fields: Posts WILL FAIL without content_preview_confirmed: true and express_consent_given: true.

TikTok settings use a nested structure: platformSpecificData.tiktokSettings (or root-level tiktokSettings shorthand):

PropertyTypeRequiredDescription
privacy_levelstringYesMust match account's allowed values
allow_commentbooleanYesAllow comments
allow_duetbooleanVideosAllow duets
allow_stitchbooleanVideosAllow stitches
content_preview_confirmedbooleanYesMust be true
express_consent_givenbooleanYesMust be true
draftbooleanNoSend to Creator Inbox
video_cover_timestamp_msintegerNoThumbnail frame (default: 1000ms)
video_made_with_aibooleanNoAI disclosure
media_type"video" | "photo"NoOverride auto-detection

Example:

json
{
  "platforms": [{
    "platform": "tiktok",
    "accountId": "tiktok_123",
    "platformSpecificData": {
      "tiktokSettings": {
        "privacy_level": "PUBLIC_TO_EVERYONE",
        "allow_comment": true,
        "allow_duet": true,
        "allow_stitch": true,
        "content_preview_confirmed": true,
        "express_consent_given": true
      }
    }
  }]
}

LinkedIn

PropertyTypeDescription
organizationUrnstringTarget org: urn:li:organization:123456789
firstCommentstringAuto-post first comment
disableLinkPreviewbooleanDisable URL previews

Facebook

PropertyTypeDescription
contentType"story"Publish as Facebook Story (24h ephemeral)
firstCommentstringAuto-post first comment
pageIdstringTarget Page ID for multi-page posting

Pinterest

PropertyTypeDescription
titlestringPin title (max 100 chars)
boardIdstringTarget board ID (required)
linkstringDestination URL

Platform Media Requirements

PlatformMedia Required?Max ItemsVideo MaxFormatsNotes
TikTokYes1 video or 35 photos4GB, 10 minMP4, MOV, WebMCannot mix photos/videos
YouTubeYes1 video256GB, 12hMP4, MOV, AVI, WMV, FLV≤3min = Shorts, >3min = Regular
InstagramYes10 (carousel)Feed: 300MB, Story: 100MBSee platform docs9:16 images → use Story
Twitter/XNo4 images or 1 video--Text-only OK
LinkedInNo20 images or 1 video-+ PDF (100MB)Text-only OK
FacebookNo (Stories: Yes)10 images--Cannot mix photos/videos
BlueskyNo4 images--Images >1MB auto-recompressed
SnapchatYes1500MB, 5-60sMP4 (9:16)Stories, Saved Stories, Spotlight
PinterestYes1 image or 1 video--boardId required
ThreadsNo10 images (carousel)--No videos in carousels

TikTok Video Specs

PropertyRequirementRecommended
Resolution720×1280 min1080×1920
Aspect Ratio9:169:16
Duration3s – 10min-
Frame Rate24-60 fps30 fps
CodecH.264H.264
File Size≤4GB-

YouTube Video Specs

PropertyShorts (≤3 min)Regular (>3 min)
Max Duration3 minutes12 hours
Max File Size256 GB256 GB
Aspect Ratio9:1616:9
Resolution1080×19201920×1080 (1080p) / 3840×2160 (4K)
Custom Thumbnail❌ Not via API✅ JPEG/PNG/GIF, 1280×720, ≤2MB

Rate Limiting

  • Status 429 returned when rate limited
  • Retry-After header indicates wait time in seconds
  • Recommended: retry with backoff, max 3 retries

Complete Post Example (Multi-Platform with Media)

json
{
  "content": "Excited to announce our new product! 🎉",
  "mediaItems": [
    { "url": "https://media.getlate.dev/temp/123_product.mp4", "type": "video" }
  ],
  "platforms": [
    {
      "platform": "youtube",
      "accountId": "yt_123",
      "platformSpecificData": {
        "title": "New Product Announcement",
        "visibility": "public",
        "categoryId": "28",
        "firstComment": "Thanks for watching! 🔔"
      }
    },
    {
      "platform": "tiktok",
      "accountId": "tt_456",
      "platformSpecificData": {
        "tiktokSettings": {
          "privacy_level": "PUBLIC_TO_EVERYONE",
          "allow_comment": true,
          "allow_duet": true,
          "allow_stitch": true,
          "content_preview_confirmed": true,
          "express_consent_given": true
        }
      }
    },
    {
      "platform": "instagram",
      "accountId": "ig_789",
      "platformSpecificData": {
        "firstComment": "Link in bio! 🔗"
      }
    },
    {
      "platform": "linkedin",
      "accountId": "li_012",
      "platformSpecificData": {
        "firstComment": "What do you think? 👇"
      }
    },
    {
      "platform": "twitter",
      "accountId": "tw_345"
    }
  ],
  "scheduledFor": "2024-11-01T10:00:00Z",
  "timezone": "America/New_York"
}

⚠️ Known Code Mismatches (vidpipe)

These issues were identified by comparing our lateApi.ts against the official docs:

1. mediaUrlsmediaItems (CRITICAL)

Our code sends mediaUrls: string[] but the API expects mediaItems: Array<{type, url}>.

Wrong (our code):

json
{ "mediaUrls": ["https://media.getlate.dev/temp/..."] }

Correct (API):

json
{ "mediaItems": [{ "type": "video", "url": "https://media.getlate.dev/temp/..." }] }

2. Missing TikTok Required Fields

TikTok posts require tiktokSettings with consent fields. Without them, posts fail with validation errors.

3. YouTube Missing title in platformSpecificData

YouTube uses platformSpecificData.title for the video title. Without it, falls back to first line of content or "Untitled Video".

4. Queue Scheduling

Late has a built-in queue system (queuedFromProfile). Using scheduledFor with manually calculated slots bypasses queue locking and can cause duplicates.