API Module

class pythreads.api.API(credentials: Credentials, session: ClientSession | None = None)

Bases: object

async account(user_id: str = 'me') Any

Retrieve a Threads User’s Profile Information

https://developers.facebook.com/docs/threads/threads-profiles

Raises:
async container(container_id: str)

Retrieve an individual Threads media object (aka container)

https://developers.facebook.com/docs/threads/threads-media#retrieve-a-single-threads-media-object

Parameters:

container_id – The id of the container you want to retrieve

Returns:

The JSON response as a dict

Raises:
async container_status(media_id: str) ContainerStatus

Gets the container’s publishing status

https://developers.facebook.com/docs/threads/troubleshooting#publishing-does-not-return-a-media-id

Parameters:

media_id – The id of the container you want to know the status of

Returns:

A ContainerStatus object

Raises:
async conversation(thread_id: str, before: str | None = None, after: str | None = None)

Returns a paginated and flattened list of all top-level and nested replies of the requested thread_id

Applicable to specific use cases that do not focus on the knowledge of the depthness of the replies. This endpoint is only intended to be used on the root-level threads with replies. To paginate through the replies, you use the before and after cursors returned in the response to request the next page. The after value that is returned in the response can be supplied to the after argument and it will retrieve the next page in the paginated list. The reverse direction is true for the before value.

https://developers.facebook.com/docs/threads/reply-management#conversations

Parameters:
  • thread_id – The id of the thread whose replies you want to retrieve

  • before – [optional] A before cursor for pagination that was returned from a previous request

  • after – [optional] An after cursor for pagination that was returned from a previous request

Returns:

The JSON response as a dict

Raises:

Creates a carousel container.

Parameters:
  • containers – A list of previously-created media containers that are to make up the carousel. You may provide between 2-10 media containers.

  • text – [optional] The thread’s text

  • reply_control – [optional] The ReplyControl policy to apply to the thread. Defaults to “everyone”.

  • reply_to_id – [optional] The id of an existing thread to make this thread in reply to.

Returns:

The id of the published container https://developers.facebook.com/docs/threads/posts#step-2–publish-a-threads-media-container https://developers.facebook.com/docs/threads/posts#step-3–publish-the-carousel-container

Raises:
async create_container(text: str | None = None, media: Media | None = None, reply_control: ReplyControl = ReplyControl.EVERYONE, reply_to_id: str | None = None, is_carousel_item: bool = False) str

Creates a media container.

While text and media are both optional, you must provide at least one or the other.

Parameters:
  • text – [optional] The thread’s text

  • media – [optional] The Media object

  • reply_control – [optional] The ReplyControl policy to apply to the thread. Defaults to ReplyControl.EVERYONE.

  • reply_to_id – [optional] The id of an existing thread to make this thread in reply to.

  • is_carousel_item – A boolean indicating whether this is a media container that will be added to a carousel container

Returns:

The id of the published container

https://developers.facebook.com/docs/threads/posts#step-2–publish-a-threads-media-container

https://developers.facebook.com/docs/threads/posts#step-3–publish-the-carousel-container

Raises:
async insights(thread_id: str)

Retrieve the available insights metrics

Returned metrics do not capture nested replies’ metrics.

https://developers.facebook.com/docs/threads/insights#media-insights

Parameters:

thread_id – The thread media id whose metrics you’re requesting

Returns:

The JSON response as a dict. Requests all available metrics.

Raises:
async manage_reply(reply_id: str, hide: bool)

Hide/unhide any top-level replies.

This will automatically hide/unhide all the nested replies. Note: Replies nested deeper than the top-level reply cannot be targeted in isolation to be hidden/unhidden.

https://developers.facebook.com/docs/threads/reply-management#hide-replies

Parameters:
  • reply_id – The id of the reply whose visibility you want to change

  • hide – Whether to hide the reply or not

Returns:

The JSON response as a dict

Raises:
async publish_container(container_id: str) Dict[Any, Any]

Publish a container that has already been created.

Parameters:

container_id – The id of the container to publish. ids are returned from create_container and create_carousel_container

Returns:

The id of the published container

https://developers.facebook.com/docs/threads/posts#step-2–publish-a-threads-media-container

https://developers.facebook.com/docs/threads/posts#step-3–publish-the-carousel-container

Raises:
async publishing_limit() Any

The user’s current Threads API usage total

https://developers.facebook.com/docs/threads/troubleshooting#retrieve-publishing-quota-limit

Returns:

The JSON response as a dict

Raises:
async replies(thread_id: str)

Returns the immediate replies of the requested thread_id

https://developers.facebook.com/docs/threads/reply-management#replies

Parameters:

thread_id – The id of the thread whose immediate replies you want to retrieve

Returns:

The JSON response as a dict

Raises:
property session: ClientSession | None
async thread(thread_id: str)

Retrieve an individual thread

https://developers.facebook.com/docs/threads/threads-media#retrieve-a-single-threads-media-object

Parameters:

thread_id – The id of the thread you want to retrieve

Returns:

The JSON response as a dict

Raises:
async threads(since: date | str | None = None, until: date | str | None = None, limit: int | None = None, before: str | None = None, after: str | None = None)

A paginated list of all threads created by the user

Returns a paginated list of threads made by the user, including reposts. The number of threads returned is controlled by limit. The window of threads being queried is controlled by since and until. To paginate through that window, you use the before and after cursors returned in the response to request the next page. The after value that is returned in the response can be supplied to the after argument and it will retrieve the next page in the paginated list. The reverse direction is true for the before value.

https://developers.facebook.com/docs/threads/threads-media#retrieve-a-list-of-all-a-user-s-threads

Parameters:
  • since – [optional] The starting date of the time window you are requesting

  • until – [optional] The ending date of the time window you are requesting

  • limit – [optional] The maximum number of threads to return. Defaults to 25.

  • before – [optional] A before cursor for pagination that was returned from a previous request

  • after – [optional] An after cursor for pagination that was returned from a previous request

Returns:

The JSON response as a dict

Raises:
async user_insights(metrics: Literal['views', 'likes', 'replies', 'reposts', 'quotes', 'followers_count', 'follower_demographics'] | List[Literal['views', 'likes', 'replies', 'reposts', 'quotes', 'followers_count', 'follower_demographics']], since: datetime | None = None, until: datetime | None = None, breakdown: Literal['age', 'city', 'country', 'gender'] | None = None) Any

Retrieve the available user insights metrics

https://developers.facebook.com/docs/threads/insights#user-insights

Parameters:
  • metrics – The metric or metrics you want to retrieve (see linked official docs)

  • since – [optional] The starting datetime of the time window you are requesting

  • until – [optional] The ending datetime of the time window you are requesting

  • breakdown – [optional] Required when requesting follower_demographic metrics

Returns:

The JSON response as a dict

Raises:
class pythreads.api.ContainerStatus(id: str, status: pythreads.api.PublishingStatus, error: pythreads.api.PublishingError | None = None)

Bases: object

error: PublishingError | None = None
id: str
status: PublishingStatus
class pythreads.api.Media(type: pythreads.api.MediaType, url: str)

Bases: object

type: MediaType
url: str
class pythreads.api.MediaType(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)

Bases: str, Enum

CAROUSEL = 'CAROUSEL'
IMAGE = 'IMAGE'
TEXT = 'TEXT'
VIDEO = 'VIDEO'
class pythreads.api.PublishingError(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)

Bases: str, Enum

FAILED_DOWNLOADING_VIDEO = 'FAILED_DOWNLOADING_VIDEO'
FAILED_PROCESSING_AUDIO = 'FAILED_PROCESSING_AUDIO'
FAILED_PROCESSING_VIDEO = 'FAILED_PROCESSING_VIDEO'
INVALID_ASPEC_RATIO = 'INVALID_ASPEC_RATIO'
INVALID_AUDIO_CHANNELS = 'INVALID_AUDIO_CHANNELS'
INVALID_AUDIO_CHANNEL_LAYOUT = 'INVALID_AUDIO_CHANNEL_LAYOUT'
INVALID_BIT_RATE = 'INVALID_BIT_RATE'
INVALID_DURATION = 'INVALID_DURATION'
INVALID_FRAME_RATE = 'INVALID_FRAME_RATE'
UNKNOWN = 'UNKNOWN'
class pythreads.api.PublishingStatus(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)

Bases: str, Enum

ERROR = 'ERROR'
EXPIRED = 'EXPIRED'
FINISHED = 'FINISHED'
IN_PROGRESS = 'IN_PROGRESS'
PUBLISHED = 'PUBLISHED'
class pythreads.api.ReplyControl(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)

Bases: str, Enum

ACCOUNTS_YOU_FOLLOW = 'accounts_you_follow'
EVERYONE = 'everyone'
MENTIONED_ONLY = 'mentioned_only'
exception pythreads.api.ThreadsInvalidParameter

Bases: ValueError

exception pythreads.api.ThreadsResponseError(response: dict)

Bases: Exception

Configuration Module

class pythreads.configuration.Configuration(scopes: List[str], app_id: str, api_secret: str, redirect_uri: str)

Bases: object

api_secret: str
app_id: str
redirect_uri: str
scopes: List[str]
scopes_str()

Credentials Module

class pythreads.credentials.Credentials(user_id: 'str', scopes: 'List[str]', short_lived: 'bool', access_token: 'str', expiration: 'datetime')

Bases: object

access_token: str
expiration: datetime
expired() bool
expires_in() int

Number of seconds before these credentials’ access token expires.

static from_json(json_str: str) Credentials
scopes: List[str]
short_lived: bool
to_json() str
user_id: str

Threads Module

class pythreads.threads.Threads

Bases: object

ALL_SCOPES = ['threads_basic', 'threads_content_publish', 'threads_manage_insights', 'threads_manage_replies', 'threads_read_replies']
static authorization_url(config: Configuration | None = None) Tuple[str, str]

Constructs an authorization_url and opaque state value.

You must store the state value in the user’s session so that you can retrieve it later and redirect the user to the authorization_url. When the user is redirected back to your redirect_uri, you will validate the authentication using complete_authentication.

If you do not pass a Threads.Configuration instance, this method will load with the default configuration of all scopes and the THREADS_APP_ID, THREADS_API_SECRET, and THREADS_REDIRECT_URI environment variables.

Parameters:

config – [optional] A Threads.Configuration instance

Returns:

A tuple of (authorization_url, state), both being strings.

Raises:

OAuth2Error – An error occured in the OAuth2 flow. Check the error and description fields for more info.

static build_graph_api_url(path, params: dict | None = None, access_token=None, base_url=None)
static complete_authorization(callback_url: str, state: str, long_lived_token: bool = True, config: Configuration | None = None) Credentials

state: the state string that was returned from the authorization_url method

static fetch_long_lived_token(access_token: str, expiration: datetime, config: Configuration | None = None) Tuple[str, datetime]
static fetch_user_id_and_token(request_url: str, state: str, config: Configuration | None = None) Tuple[str, str, datetime]

Exchanges authorization code for a short-lived OAuth2 API token (valid for 1 hour).

Once you have redirected the user to the URL generated by the authorization_url method, Threads will redirect the user back to your redirect_uri, appending several request parameters to the URL. Call this method with that full request URL. It will extract the authorization code and state parameters, verify the state parameter to protect against CSRF attacks, and then call the Threads API to exchange the authorization code for a token.

Parameters:

request_url – the full request URL made by Threads to your redirect_uri

Returns:

A tuple of (user_id, access_token, access_token_expiration)

Raises:

OAuth2Error – An error occured in the OAuth2 flow. Check the error and description fields for more info.

static load_configuration(scopes: List[str] | None = None, app_id: str | None = None, api_secret: str | None = None, redirect_uri: str | None = None) Configuration
static refresh_long_lived_token(credentials: Credentials) Tuple[str, datetime]
exception pythreads.threads.ThreadsAccessTokenExpired

Bases: RuntimeError

exception pythreads.threads.ThreadsAuthenticationError

Bases: RuntimeError