Threads API Guide for Developers (2026)

Threads API Guide for Developers (2026)

What the Threads API publishes, the Meta app and token model behind it, the two-step container flow, and the 250 posts per 24 hours limit.

Publishing to Threads takes two API calls, not one: you create a media container, then publish it. Profiles are limited to 250 API-published posts per 24 hours, text posts cap at 500 characters, and every permission your app uses has to clear Meta’s App Review before anyone outside your tester list can connect.

What can the Threads API publish, and what can it not?

Single posts support three media types: TEXT, IMAGE and VIDEO. Carousels support IMAGE and VIDEO children, between 2 and 20 of them, and a carousel counts as a single post against your publishing limit.

The specs, from Meta’s own documentation:

ConstraintValue
Text length500 characters
Carousel children2 to 20
Image formatsJPEG, PNG
Image file size8 MB maximum
Image width320 to 1440 pixels
Image aspect ratio10:1 maximum
Video containerMOV or MP4
Video codecsH264 or HEVC video, AAC audio
Video frame rate23 to 60 FPS
Video duration300 seconds (5 minutes)
Video file size1 GB maximum
Video bitrate100 Mbps video, 128 kbps audio

One detail that surprises people: emoji count against the 500 characters by UTF-8 byte value, not as single characters. A caption that looks like 480 characters in your editor can be rejected. If you are counting client-side, count bytes for emoji. The Threads character limit post and the free Threads character counter both handle this.

Note: Figures here were verified against developers.facebook.com/docs/threads/posts and /docs/threads/overview as of September 2026. Platforms change these without notice.

What is the auth model?

Threads runs on Meta’s app infrastructure but with its own credentials. You create a Meta app with the Threads use case, and that app issues a Threads-specific app ID and secret, distinct from the ones shown elsewhere in the dashboard. Using the wrong pair is a common first-hour mistake.

The scopes are granular:

  • threads_basic (required by every endpoint)
  • threads_content_publish (publishing)
  • threads_manage_replies and threads_read_replies
  • threads_manage_insights
  • threads_delete
  • threads_location_tagging

App review is not optional. Each permission must be approved through App Review, and the app must be published to production, before any non-tester can grant it. Until then you can only post to Threads profiles you have explicitly invited as testers through the app dashboard, and who have accepted the invitation from their Threads settings. Meta’s documentation does not state how long review takes, so we will not guess.

The token lifecycle you have to build

This is the part that becomes a background job.

  1. The authorization window returns a code.
  2. Exchange it for a short-lived access token, valid for 1 hour.
  3. Exchange that for a long-lived token via GET /access_token with grant_type=th_exchange_token. Valid for 60 days.
  4. Refresh via GET /refresh_access_token with grant_type=th_refresh_token. A token must be at least 24 hours old and not yet expired to be refreshable. A refreshed token is good for another 60 days.

A token that goes 60 days without a refresh expires and the user must reauthorize. Permissions granted by app users with private profiles are valid for 90 days.

Note: Figures here were verified against developers.facebook.com/docs/threads/get-started and /get-started/long-lived-tokens as of September 2026. Platforms change these without notice.

What is the actual publishing sequence?

For a single post:

  1. POST /{threads-user-id}/threads with media_type and your text or media URL. This returns a container ID.
  2. Wait. Meta recommends on average 30 seconds before publishing, to let the server finish processing the media.
  3. POST /{threads-user-id}/threads_publish with that container ID.

For a carousel, insert a step: create a container per child, then create a carousel container referencing them, then publish that.

# 1. create the container
curl -X POST "https://graph.threads.net/v1.0/$USER_ID/threads" \
  -d "media_type=IMAGE" \
  -d "image_url=https://example.com/photo.jpg" \
  -d "text=Shipping notes for this week." \
  -d "access_token=$TOKEN"
# -> {"id":"1789..."}

# 2. wait ~30s for processing, then publish
curl -X POST "https://graph.threads.net/v1.0/$USER_ID/threads_publish" \
  -d "creation_id=1789..." \
  -d "access_token=$TOKEN"

Note that images and videos are passed by public URL, not uploaded as bytes. Meta’s servers fetch them. That means your media has to be publicly reachable, unauthenticated, and still up when the fetch happens, which is a hosting requirement most people do not plan for.

What are the rate limits?

ActionLimit
Published posts250 per 24-hour moving period
Replies1,000 per 24 hours
Deletions100 per 24 hours
Location searches500 per 24 hours
General API calls4800 x number of impressions, per 24 hours (minimum 10 impressions)

The impressions formula is worth reading twice. Your general call budget scales with how much reach the profile actually gets, with a floor. A brand new profile has the minimum budget.

Note: Figures here were verified against developers.facebook.com/docs/threads/overview as of September 2026. Platforms change these without notice.

What will actually cost you three weeks?

App Review. Preparing screencasts, a privacy policy, a working demo path and a business verification, then iterating on rejections. The duration is not published, so plan for it to be a schedule risk rather than a task.

The token refresh job. Long-lived tokens expire in 60 days and are only refreshable once they are 24 hours old. That is a scheduled job, a store of encrypted tokens, an alerting path when refresh fails, and a reconnect flow in your UI.

Asynchronous failure. The container call returning 200 does not mean your media is valid. The publish call is where a bad video surfaces, roughly 30 seconds later, in a different request. Your post model needs a processing state and a way to report a failure that arrived after the user closed the tab.

Public media hosting. Because Meta fetches by URL, you need durable public URLs with sane cache behaviour, and a plan for what happens when the fetch is rate-limited or blocked by your CDN’s bot protection.

Byte-counting for emoji. Cheap to fix, expensive to discover in production.

The short version

  • Two calls to publish: create a container, wait about 30 seconds, publish it. Three for a carousel.
  • Media is passed by public URL. Meta fetches it.
  • 500 characters. Emoji count as UTF-8 bytes.
  • 250 API-published posts per profile per 24 hours.
  • Short-lived tokens last 1 hour, long-lived 60 days, refreshable once 24 hours old.
  • App Review is required per permission before non-testers can connect. No duration is published.

Scheduling Threads alongside everything else

If Threads is one platform in a set rather than the whole product, most of the work above repeats per network with different shapes. X uses OAuth 2.0 PKCE and chunked byte uploads. Bluesky needs no app review at all. LinkedIn needs two separate apps: personal profiles use w_member_social, company pages use r_organization_social, w_organization_social and rw_organization_admin, reviewed separately.

BulkPublish covers 15 platforms behind one REST API, including Threads, with the container sequence, the 60-day refresh and the async status polling handled server-side. The developer docs and the REST API reference list the endpoints, and scheduling Threads posts covers the non-developer path.