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. mediaUrls → mediaItems (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.