Sign in with Klap (OAuth)Captions & Social Posts

Caption & Social Post Endpoints

Write captions with AI and schedule clips to the social accounts the user connected in Klap (YouTube, TikTok, Instagram, LinkedIn, Facebook). Users connect their social accounts in Klap at https://klap.app/calendar; this API can’t connect new accounts.

Write Caption

Write a social media caption for a clip with AI. The caption is platform-agnostic: use the same text for every platform you post the clip to.

Endpoint: GET /projects/{clip_id}/caption

Request

GET /projects/{clip_id}/caption?tone=casual&prompt=Mention%20our%20free%20trial
Authorization: Bearer <access_token>

Path Parameters

ParameterTypeDescription
clip_idstringID of the clip

Query Parameters

ParameterTypeRequiredDefaultDescription
tonestringNo”casual”Tone of the caption, e.g. casual, professional, funny, inspirational, educational
promptstringNo-Extra instructions for the caption, up to 1000 characters

Response

{
  "caption": "Most startups don't die from competition. They die from building something nobody asked for 👀 #startups #founders"
}

Writing a caption takes a few seconds. Returns 404 if the clip isn’t in the user’s account.

List Social Accounts

List the social accounts the user connected in Klap.

Endpoint: GET /integrations/accounts

Request

GET /integrations/accounts
Authorization: Bearer <access_token>

Response

Returns an array of Social Account Objects:

[
  {
    "id": "UCx8Zk2mQv7LpR4tN9wB1cDe",
    "provider": "youtube",
    "name": "Startup Stories",
    "username": "startupstories",
    "profile_picture": "https://yt3.ggpht.com/abc123",
    "settings": {},
    "needs_reconnect": false
  },
  {
    "id": "-000Ab12Cd34Ef56Gh78",
    "provider": "tiktok",
    "name": "Startup Stories",
    "username": "startupstories",
    "profile_picture": "https://p16-sign.tiktokcdn.com/abc123.jpeg",
    "settings": {},
    "needs_reconnect": true
  }
]

Notes

  • This request can take up to about 5 seconds: Klap fetches each account’s current name and picture from the platform.
  • An account with needs_reconnect: true lost its connection to the platform. The user must reconnect it at https://klap.app/calendar before you can post to it.

Schedule Posts

Schedule a clip to one or more of the user’s social accounts. At the scheduled time, Klap exports the clip and publishes it. Users can review and change scheduled posts in Klap at https://klap.app/calendar.

Endpoint: POST /integrations/publications/batch

Request

POST /integrations/publications/batch
Authorization: Bearer <access_token>
Content-Type: application/json
 
{
  "time_zone": "Europe/Paris",
  "expected_publications": [],
  "updates": [],
  "delete_ids": [],
  "creates": [
    {
      "id": "8d0c5f3e-6a1b-4c2d-9e7f-0a1b2c3d4e5f",
      "project_id": "hT4kq9ZpW2xe",
      "account_id": "UCx8Zk2mQv7LpR4tN9wB1cDe",
      "provider": "youtube",
      "scheduled_at": "2026-10-08T18:00:00+02:00",
      "post_info": {
        "title": "Why most startups fail",
        "description": "Most startups don't die from competition. They die from building something nobody asked for.",
        "tags": [],
        "visibility": "public",
        "category_id": "22"
      }
    },
    {
      "id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
      "project_id": "hT4kq9ZpW2xe",
      "account_id": "-000Ab12Cd34Ef56Gh78",
      "provider": "tiktok",
      "scheduled_at": "2026-10-08T18:00:00+02:00",
      "post_info": {
        "title": "Most startups don't die from competition. They die from building something nobody asked for.",
        "privacy_level": "PUBLIC_TO_EVERYONE",
        "disable_duet": false,
        "disable_stitch": false,
        "disable_comment": false,
        "video_cover_timestamp_ms": 0,
        "brand_content_toggle": false,
        "brand_organic_toggle": false,
        "is_aigc": false
      }
    }
  ]
}

Request Parameters

All five fields are required, and no other fields are accepted.

ParameterTypeRequiredDescription
time_zonestringYesThe user’s IANA time zone (e.g., “UTC”, “Europe/Paris”)
createsarrayYesPosts to schedule (up to 1000). See Post Object
expected_publicationsarrayYesSend []
updatesarrayYesSend []
delete_idsarrayYesSend []

Post Object

ParameterTypeRequiredDescription
idstringYesA new UUID (v4) that you generate for this post. Re-sending a post with the same id returns 409 publication_exists instead of posting twice, so retries are safe.
project_idstringYesID of the clip to post (a clip id, despite the field’s name)
account_idstringYesid of the Social Account to post to
providerstringYesprovider of that account: "youtube", "tiktok", "instagram", "linkedin" or "facebook"
scheduled_atstringYesWhen to publish, as an ISO 8601 date-time with a UTC offset (e.g., “2026-10-08T16:00:00Z” or “2026-10-08T18:00:00+02:00”). To post right away, use the current time plus 2 minutes.
post_infoobjectYesPlatform-specific settings. See Post Info

Post Info

Captions can be up to 2200 characters. Use the shape that matches the account’s provider:

YouTube

{
  "title": "Why most startups fail",
  "description": "<caption>",
  "tags": [],
  "visibility": "public",
  "category_id": "22"
}
  • title: Video title, up to 100 characters (for example the first 100 characters of the caption).
  • visibility: "public", "unlisted" or "private".
  • category_id: YouTube video category ID ("22" is People & Blogs).

TikTok

{
  "title": "<caption>",
  "privacy_level": "PUBLIC_TO_EVERYONE",
  "disable_duet": false,
  "disable_stitch": false,
  "disable_comment": false,
  "video_cover_timestamp_ms": 0,
  "brand_content_toggle": false,
  "brand_organic_toggle": false,
  "is_aigc": false
}
  • privacy_level (required): Who can see the post: "PUBLIC_TO_EVERYONE", "MUTUAL_FOLLOW_FRIENDS", "FOLLOWER_OF_CREATOR" or "SELF_ONLY". Let the user choose it; don’t assume one.

Instagram

{
  "caption": "<caption>",
  "share_to_feed": true
}

Facebook

{
  "caption": "<caption>"
}

LinkedIn

{
  "share_commentary": "<caption>",
  "media_title": "",
  "media_description": "",
  "visibility": "PUBLIC"
}
  • visibility: "PUBLIC" or "CONNECTIONS".

If the user leaves the caption empty, you can write one with Write Caption.

Response

Returns the scheduled posts:

{
  "publications": [
    {
      "id": "8d0c5f3e-6a1b-4c2d-9e7f-0a1b2c3d4e5f",
      "project_id": "hT4kq9ZpW2xe",
      "account_id": "UCx8Zk2mQv7LpR4tN9wB1cDe",
      "provider": "youtube",
      "scheduled_at": "2026-10-08T16:00:00+00:00",
      "status": "scheduled",
      "post_info": {
        "title": "Why most startups fail",
        "description": "Most startups don't die from competition. They die from building something nobody asked for.",
        "tags": [],
        "visibility": "public",
        "category_id": "22"
      },
      "created_at": "2026-10-07T12:30:00.000000+00:00",
      ...
    }
  ],
  "deleted_ids": []
}
  • publications (array): One entry per scheduled post, with its id, project_id (the clip ID), account_id, provider, scheduled_at, post_info and status ("scheduled"). Entries can include other fields.
  • deleted_ids (array): Always empty for requests that only create posts.

Notes

  • All or nothing: The posts in one request are saved together. If one is refused, none are saved.
  • One post per platform per clip: A clip can’t be posted to two accounts on the same platform, or scheduled again on a platform where it is already scheduled or published (409 duplicate_post).
  • Retries: Re-send the same request with the same post ids. If the first attempt went through, you get 409 publication_exists.
  • Errors: 409 account_disconnected (an account needs reconnecting in Klap), 409 youtube_capacity (YouTube’s daily posting capacity is reached for that day), 402 (plan or subscription), 503 (scheduling is busy: retry shortly with the same ids). See Errors.