Skip to content

Meta Threads

OpenQuok CLI examples for Meta Threads — single posts, reply chains, the reconciliation flow, and per-post analytics.

3 min read

Connect your agent today

Draft from chat, review in your calendar, and publish only what you approve.

Start for $0

Channel quick reference

PropertyValue
Provider identifierthreads
Max content length500 characters
Required attachmentsNone — text-only posts publish
OAuth scopesthreads_basic, threads_content_publish, threads_manage_replies, threads_manage_insights, threads_manage_mentions
OAuth setupMeta Threads
THREADS_ID=$(openquok integrations:list | jq -r '.[] | select(.identifier=="threads") | .id')

Simple text post

openquok posts:create 
  -s "2026-01-15T10:00:00Z" 
  -t schedule 
  -c "Hello Threads!" 
  -i "$THREADS_ID"

Post with media

Threads accepts at most one image or video per post. Upload the asset and pass the returned id/path:

MEDIA=$(openquok upload ./hero.png | jq -c '[{id: .data.id, path: .data.filePath}]')

openquok posts:create 
  -s "2026-01-15T10:00:00Z" 
  -t schedule 
  -c "Launch day. 🚀" 
  -i "$THREADS_ID" 
  -m "$MEDIA"

Scheduled reply chain (thread + follow-ups)

providerSettings.threads.replies[] carries follow-up comments that are published from the same account a fixed number of seconds after the main thread. Pass them on posts:create with --providerSettingsByIntegrationId:
openquok posts:create 
  -s "2026-01-15T10:00:00Z" 
  -c "Thread 1/3: Why we built OpenQuok" 
  -i "$THREADS_ID" 
  --providerSettingsByIntegrationId "$(jq -nc --arg id "$THREADS_ID" '
    {
      ($id): {
        threads: {
          replies: [
            { message: "Thread 2/3: The architecture", delaySeconds: 60 },
            { message: "Thread 3/3: What is next",      delaySeconds: 120 }
          ]
        }
      }
    }
  ')"

Thread reply with image or video

Upload the reply attachment first, then nest media on the matching replies[] row (same { id, path } shape as the main post). Threads supports images and video on follow-ups:

REPLY_MEDIA=$(openquok upload ./thread-slide.jpg | jq -c '[{id: .data.id, path: (.data.path // .data.filePath)}]')

openquok posts:create 
  -s "2026-01-15T10:00:00Z" 
  -c "Thread 1/2: Why we built OpenQuok" 
  -i "$THREADS_ID" 
  --providerSettingsByIntegrationId "$(jq -nc 
    --arg id "$THREADS_ID" 
    --argjson media "$REPLY_MEDIA" '
    {
      ($id): {
        threads: {
          replies: [
            { message: "Thread 2/2: Architecture diagram", delaySeconds: 60, media: $media }
          ]
        }
      }
    }
  ')"

JSON recipe: threads-follow-up-reply-with-image.json in the agent skill examples folder (agent/skills/openquok-core/resources/examples/).

Add a “finisher” reply

Enable a closing reply (e.g. “Thanks for reading!”) by toggling providerSettings.threads.enabled and providing a message:

openquok posts:create 
  -s "2026-01-15T10:00:00Z" 
  -c "Thread 1/2: A short story" 
  -i "$THREADS_ID" 
  --providerSettingsByIntegrationId "$(jq -nc --arg id "$THREADS_ID" '
    {
      ($id): {
        threads: {
          enabled: true,
          message: "Thanks for reading — like and follow for more!",
          replies: [
            { message: "Thread 2/2: The punchline", delaySeconds: 30 }
          ]
        }
      }
    }
  ')"

Delayed engagement reply

providerSettings.threads.internalEngagementPlug schedules a same-account engagement reply (a self-comment that boosts engagement signals) some seconds after publish:
openquok posts:create 
  -s "2026-01-15T10:00:00Z" 
  -c "Big announcement! 🧵" 
  -i "$THREADS_ID" 
  --providerSettingsByIntegrationId "$(jq -nc --arg id "$THREADS_ID" '
    {
      ($id): {
        internalEngagementPlug: {
          enabled: true,
          message: "Have questions? Reply here and I will get back to you.",
          delaySeconds: 300
        }
      }
    }
  ')"

Cross-account comments

providerSettings.threads.crossAccountPlugs schedules comments from other Threads channels in the same workspace after the publishing channel’s post goes live. Use plug name threads-cross-account-comment and list acting channel UUIDs in integrationIds (not the publishing channel).

Connect two or more Threads integrations, then pass settings on the publishing integration id:

THREADS_PUBLISH_ID=$(openquok integrations:list | jq -r '.[] | select(.identifier=="threads") | .id' | head -n1)
THREADS_OTHER_ID=$(openquok integrations:list | jq -r '.[] | select(.identifier=="threads") | .id' | sed -n '2p')

openquok posts:create 
  -s "2026-01-15T10:00:00Z" 
  -c "Main thread from our brand account" 
  -i "$THREADS_PUBLISH_ID" 
  --providerSettingsByIntegrationId "$(jq -nc 
    --arg publish "$THREADS_PUBLISH_ID" 
    --arg other "$THREADS_OTHER_ID" '
    {
      ($publish): {
        threads: {
          crossAccountPlugs: [
            {
              plugName: "threads-cross-account-comment",
              enabled: true,
              delayMs: 120000,
              integrationIds: [$other],
              fields: { comment: "Great thread — sharing from our other account." }
            }
          ]
        }
      }
    }
  ')"

Reconnect a “missing” Threads post

Threads occasionally fails to return a release_id immediately after publish; OpenQuok stores it as missing and per-post analytics stay locked until you link the real id manually.

POST_ID=$(openquok posts:list 
  --start "2026-01-01T00:00:00Z" 
  --end   "2026-02-01T00:00:00Z" 
  | jq -r --arg id "$THREADS_ID" '
    .[]
    | select(.integration_id==$id and .release_id=="missing")
    | .id
  ' 
  | head -n1)

openquok posts:missing "$POST_ID" | jq '.[] | {id, url}'

openquok posts:connect "$POST_ID" -r "7321456789012345678"

openquok analytics:post "$POST_ID" -d 7

Per-channel analytics

openquok analytics:platform "$THREADS_ID" -d 30 
  | jq '.[] | {label, percentageChange}'
openquok analytics:post <post-id> -d 30 
  | jq '.[] | {label, latest: .data[-1].total}'
Search documentation
Find a docs page
Discord Support