RelayAPI

TikTok API

Publish compliant TikTok videos and photo carousels with explicit creator choices, consent, and verified media sources.

Quick reference

PropertyRelayAPI behavior
Platform keytiktok
AuthenticationOAuth 2.0 with video.publish and video.upload
Publishing modeDirect Post or creator-inbox upload
MediaExactly one video with duration_ms, or 1–35 photos; no text-only or mixed-media posts
Video caption2,200 UTF-16 code units
Photo titleFirst 90 Unicode code points of content
Photo description4,000 UTF-16 code units
Video sourcesBounded FILE_UPLOAD, or verified PULL_FROM_URL
Photo sourcesVerified PULL_FROM_URL only
LifecycleRelayAPI records TikTok's publish_id and polls the status API

RelayAPI does not choose privacy, interaction, commercial-disclosure, preview, or consent values for a creator. Your application must render TikTok's current choices, show the exact content preview, obtain the creator's choices and consent, and then send every required field explicitly.

Connections authorized before RelayAPI added creator-inbox uploads do not have the new video.upload grant automatically. Reconnect TikTok before using publish_mode: 'inbox'; token refresh cannot add a scope the user never granted.

Required creator flow

Before creating a TikTok post:

  1. Call GET /v1/accounts/{id}/tiktok-creator-info.
  2. Show the connected creator and only the returned privacy_level_options.
  3. Disable comment, duet, or stitch choices that creator info reports as disabled.
  4. For video, validate the media duration against max_video_post_duration_sec.
  5. Show the exact content preview and the appropriate TikTok commercial-content and Music Usage Confirmation notices.
  6. After the creator makes each choice and expressly consents, submit the post with the required booleans.

RelayAPI queries creator info again immediately before provider I/O. A stale privacy choice, an interaction disabled since the UI was rendered, or a video longer than the creator's current limit fails before TikTok publish initialization.

TikTok requires users to select privacy and interaction settings without a default. The two consent attestations are literal true values, but they are not automatic defaults: set them only after the creator previews the exact post and completes the required consent step.

Publish a video

All eight creator-choice fields shown below are required for a video. Set both commercial disclosure fields explicitly even for non-commercial content.

const post = await client.posts.create({
  content: 'A quiet morning by the sea #travel',
  targets: ['tiktok'],
  scheduled_at: 'now',
  media: [{
    url: 'https://media.example.com/tiktok/morning.mp4',
    type: 'video',
    mime_type: 'video/mp4',
    duration_ms: 18_000,
  }],
  target_options: {
    tiktok: {
      privacy_level: 'PUBLIC_TO_EVERYONE',
      allow_comment: true,
      allow_duet: false,
      allow_stitch: false,
      brand_content_toggle: false,
      brand_organic_toggle: false,
      content_preview_confirmed: true,
      express_consent_given: true,
      source_mode: 'file_upload',
    },
  },
});

The same request with curl:

curl --fail-with-body -X POST https://api.relayapi.dev/v1/posts \
  -H "Authorization: Bearer $RELAY_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
    "content": "A quiet morning by the sea #travel",
    "targets": ["tiktok"],
    "scheduled_at": "now",
    "media": [{
      "url": "https://media.example.com/tiktok/morning.mp4",
      "type": "video",
      "mime_type": "video/mp4",
      "duration_ms": 18000
    }],
    "target_options": {
      "tiktok": {
        "privacy_level": "PUBLIC_TO_EVERYONE",
        "allow_comment": true,
        "allow_duet": false,
        "allow_stitch": false,
        "brand_content_toggle": false,
        "brand_organic_toggle": false,
        "content_preview_confirmed": true,
        "express_consent_given": true,
        "source_mode": "file_upload"
      }
    }
  }'

FILE_UPLOAD does not put binary data in the JSON request. RelayAPI fetches the media URL through its guarded public-media client, validates the response MIME type and declared length, initializes TikTok's upload, and streams bounded, sequential chunks to TikTok. MP4, MOV, and WebM are accepted; the provider limit is 4 GB. RelayAPI's own media library has a separate 200 MiB direct-to-storage upload-session limit (and a 50 MiB Worker-proxy limit) described in Media Uploads.

TikTok photo publishing always uses PULL_FROM_URL. Every image must use an HTTPS URL under a TikTok URL prefix that was verified by the RelayAPI operator and pinned when this account connected.

const post = await client.posts.create({
  content: 'Weekend in Cornwall',
  targets: ['tiktok'],
  scheduled_at: 'now',
  media: [
    { url: 'https://media.example.com/tiktok/cornwall-1.jpg', type: 'image' },
    { url: 'https://media.example.com/tiktok/cornwall-2.jpg', type: 'image' },
  ],
  target_options: {
    tiktok: {
      privacy_level: 'MUTUAL_FOLLOW_FRIENDS',
      allow_comment: true,
      brand_content_toggle: false,
      brand_organic_toggle: false,
      content_preview_confirmed: true,
      express_consent_given: true,
      source_mode: 'pull_from_url',
      description: 'The complete weekend recap #cornwall',
      photo_cover_index: 0,
      auto_add_music: false,
    },
  },
});

Duet and stitch do not apply to photos. source_mode: "file_upload" is not supported for photo posts. Direct mode sends DIRECT_POST; inbox mode sends TikTok's official MEDIA_UPLOAD flow.

Upload to the creator inbox

Set publish_mode: 'inbox' to upload media for the creator to finish in TikTok after receiving the provider notification. This is not a RelayAPI local draft: the bytes have reached TikTok, while privacy, interaction, disclosure, and final publishing choices happen in TikTok.

const post = await client.posts.create({
  content: '',
  targets: ['tiktok'],
  scheduled_at: 'now',
  media: [{
    url: 'https://media.example.com/tiktok/rough-cut.mp4',
    type: 'video',
    mime_type: 'video/mp4',
    duration_ms: 24_000,
  }],
  target_options: {
    tiktok: {
      publish_mode: 'inbox',
      source_mode: 'file_upload',
    },
  },
});

Inbox mode rejects Direct Post fields including privacy_level, interaction choices, disclosure/consent attestations, AI/music flags, and video_cover_timestamp_ms. TikTok's video inbox endpoint accepts only source_info, so description is also rejected for inbox video; add the caption when completing the post in TikTok. Photo inbox uploads can retain the photo title/description and photo_cover_index supported by TikTok's MEDIA_UPLOAD photo contract.

Media source selection

Media and requestResult
Video, source_mode: "file_upload"RelayAPI performs bounded TikTok FILE_UPLOAD; no verified prefix is needed
Video, source_mode: "pull_from_url"Allowed only when the URL matches a prefix pinned to the connected account
Video, source_mode omitted, URL is pinnedRelayAPI uses PULL_FROM_URL
Video, source_mode omitted, URL is not pinnedRelayAPI falls back to bounded FILE_UPLOAD
PhotosEvery image must match a pinned prefix; TikTok requires PULL_FROM_URL

For pull mode, the media must remain publicly reachable over HTTPS for TikTok's download window and must not redirect. A URL that is merely on the same site is not sufficient: its hostname and path must be beneath a configured, verified prefix.

Verified prefixes are connection authority, not caller-controlled post options. The operator configures them, and RelayAPI snapshots the canonical list into the TikTok account when OAuth completes. Changing the operator list does not silently expand an existing account's media authority; reconnect the account to adopt the new list.

For self-hosted installations, configure the non-secret list in relayapi.selfhost.json before connecting TikTok:

{
  "publishing": {
    "tiktokVerifiedUrlPrefixes": [
      "https://media.example.com/tiktok/"
    ]
  }
}

The deployment CLI validates and emits this as the API Worker's TIKTOK_VERIFIED_URL_PREFIXES variable. Each prefix must use HTTPS and contain no credentials, IP host, non-default port, query string, or fragment. Its path must end in /, which keeps /media/ from authorizing /mediaevil. Verify the same exact prefix in the TikTok developer application's URL properties first.

Provider media limits

MediaTikTok limit
Video containerMP4, MOV, or WebM
Video codecH.264, H.265, VP8, or VP9
Video frame rate23–60 FPS
Video dimensionsEach side 360–4,096 pixels
Video durationAt most 10 minutes and no longer than fresh creator info allows
Video sizeAt most 4 GB
Photo formatJPEG or WebP
Photo dimensionsAt most 1080p
Photo sizeAt most 20 MB each

RelayAPI can best-effort normalize ready media when processing is enabled, but TikTok remains authoritative for its provider limits. RelayAPI's media library accepts direct-to-storage upload sessions up to 200 MiB; the Worker-proxy endpoint remains 50 MiB.

target_options.tiktok

FieldRequiredBehavior
publish_modeNodirect by default; inbox uses TikTok's official creator-inbox upload and rejects Direct Post-only fields
privacy_levelYesExplicit creator selection; RelayAPI checks it against fresh privacy_level_options
allow_commentYesExplicit creator choice; true is rejected when comments are disabled for the creator
allow_duetYes for videoExplicit video choice; true is rejected when duet is disabled
allow_stitchYes for videoExplicit video choice; true is rejected when stitch is disabled
brand_content_toggleYestrue means paid partnership/third-party promotion
brand_organic_toggleYestrue means the creator's own brand or business
content_preview_confirmedYes, literal trueAttests that the creator previewed this exact content
express_consent_givenYes, literal trueAttests that the creator expressly consented after TikTok's required notice
source_modeNofile_upload or pull_from_url; photo posts always use pull mode
descriptionNoVideo caption override up to 2,200; photo description up to 4,000
video_made_with_aiNoSends TikTok's AI-generated-content disclosure for video
video_cover_timestamp_msNoVideo cover frame position in milliseconds
photo_cover_indexNoZero-based carousel cover index; defaults to 0
auto_add_musicNoRequests TikTok-recommended music for photos
content / mediaNoTikTok-specific override of the shared post fields

The fields marked required apply to Direct Post. Inbox mode rejects those Direct Post choices instead. brand_content_toggle: true cannot be combined with SELF_ONLY. Video media must include duration_ms so RelayAPI can enforce both TikTok's global limit and the creator-specific limit before publish initialization. Legacy draft and commercial_content_type options are rejected before provider I/O. Use publish_mode: 'inbox' for TikTok's provider inbox; use the two explicit disclosure booleans for Direct Post.

Processing and errors

RelayAPI persists TikTok's publish_id before continuing, polls /v2/post/publish/status/fetch/, and reconciles retries from that provider operation rather than initializing a duplicate post. PROCESSING_UPLOAD and PROCESSING_DOWNLOAD remain nonterminal; PUBLISH_COMPLETE is terminal even when TikTok does not expose a public post ID. FAILED records TikTok's failure reason.

Common pre-provider errors include:

CodeMeaning
PRIVACY_LEVEL_UNAVAILABLEThe requested privacy level is absent from fresh creator info
COMMENTS_DISABLED_BY_CREATORThe request enabled comments although creator settings disable them
VIDEO_INTERACTIONS_REQUIREDA video omitted allow_duet or allow_stitch
COMMERCIAL_DISCLOSURE_REQUIREDOne of the two disclosure booleans was omitted
TIKTOK_CONSENT_REQUIREDPreview confirmation or express consent was not explicitly true
VIDEO_TOO_LONG_FOR_CREATORThe media duration exceeds fresh creator info
VIDEO_DURATION_REQUIREDVideo media omitted the required duration_ms
TIKTOK_VERIFIED_MEDIA_URL_REQUIREDPull-mode media is outside the account's immutable verified prefixes
PHOTO_FILE_UPLOAD_UNSUPPORTEDA photo request selected file_upload
DIRECT_OPTION_WITH_INBOX_MODEAn inbox upload included a Direct Post-only choice
VIDEO_INBOX_DESCRIPTION_UNSUPPORTEDAn inbox video supplied a description that must instead be added when completing the post in TikTok

TikTok also applies creator posting caps, app active-user caps, moderation, and client-audit restrictions. An unaudited TikTok client can be limited to private visibility regardless of RelayAPI's request.

Official TikTok references

Found something wrong? Help us improve this page.

On this page