diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 5d02000..e7ca613 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "0.6.1"
+ ".": "0.7.0"
}
diff --git a/.stats.yml b/.stats.yml
index 4477ceb..722a8b3 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 122
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/xquik/x-twitter-scraper-26de9a1d18b92c9472fcc289877ba281ae305db846b7b14065142e26c7637d72.yml
-openapi_spec_hash: f90f7016413291fdcbedb986385dc3ae
-config_hash: 17c84052d27489691ee6dd861cc56e24
+configured_endpoints: 123
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/xquik/x-twitter-scraper-323137ebb1ee9824cd9cfb63a325c0839deb81f17244e42e8154d6567e7af954.yml
+openapi_spec_hash: 48da9c2747c1e7c474dd514d39c28c49
+config_hash: dab26921eb273c16e5570c0485c9ac2c
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 85fe493..aaeb01d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,14 @@
# Changelog
+## 0.7.0 (2026-07-29)
+
+Full Changelog: [v0.6.1...v0.7.0](https://github.com/Xquik-dev/x-twitter-scraper-python/compare/v0.6.1...v0.7.0)
+
+### Features
+
+* **api:** api update ([b63b37b](https://github.com/Xquik-dev/x-twitter-scraper-python/commit/b63b37b882b4d227a542f0404604927912b60e99))
+* **api:** api update ([533e09c](https://github.com/Xquik-dev/x-twitter-scraper-python/commit/533e09c3b13682cc872ad9bac273dbc9f3de00ac))
+
## 0.6.1 (2026-07-28)
Full Changelog: [v0.6.0...v0.6.1](https://github.com/Xquik-dev/x-twitter-scraper-python/compare/v0.6.0...v0.6.1)
diff --git a/api.md b/api.md
index c0013a1..7f630d5 100644
--- a/api.md
+++ b/api.md
@@ -460,7 +460,6 @@ Types:
from x_twitter_scraper.types.x import (
XAccount,
XAccountDetail,
- AccountCreateResponse,
AccountListResponse,
AccountDeleteResponse,
AccountBulkRetryResponse,
@@ -470,7 +469,7 @@ from x_twitter_scraper.types.x import (
Methods:
-- client.x.accounts.create(\*\*params) -> AccountCreateResponse
+- client.x.accounts.create(\*\*params) -> object
- client.x.accounts.retrieve(id) -> XAccountDetail
- client.x.accounts.list() -> AccountListResponse
- client.x.accounts.delete(id) -> AccountDeleteResponse
@@ -489,6 +488,18 @@ Methods:
- client.x.account_connection_challenges.submit(id, \*\*params) -> AccountConnectionChallengeSubmitResponse
+## AccountConnectionAttempts
+
+Types:
+
+```python
+from x_twitter_scraper.types.x import AccountConnectionAttemptRetrieveResponse
+```
+
+Methods:
+
+- client.x.account_connection_attempts.retrieve(id) -> AccountConnectionAttemptRetrieveResponse
+
## Bookmarks
Types:
diff --git a/pyproject.toml b/pyproject.toml
index 04a8828..ff63ccb 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "x_twitter_scraper"
-version = "0.6.1"
+version = "0.7.0"
description = "Python library for the Xquik API. Not affiliated with X Corp."
dynamic = ["readme"]
license = "Apache-2.0"
diff --git a/src/x_twitter_scraper/_version.py b/src/x_twitter_scraper/_version.py
index abef8df..d459452 100644
--- a/src/x_twitter_scraper/_version.py
+++ b/src/x_twitter_scraper/_version.py
@@ -5,4 +5,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
__title__ = "x_twitter_scraper"
-__version__ = "0.6.1" # x-release-please-version
+__version__ = "0.7.0" # x-release-please-version
diff --git a/src/x_twitter_scraper/resources/compose.py b/src/x_twitter_scraper/resources/compose.py
index cf5ddd8..37ee572 100644
--- a/src/x_twitter_scraper/resources/compose.py
+++ b/src/x_twitter_scraper/resources/compose.py
@@ -67,10 +67,10 @@ def create(
) -> ComposeCreateResponse:
"""Run one step of Xquik's three-step writing workflow.
- Compose returns questions
- and editorial rules. Refine returns goal-specific guidance. Score applies
- deterministic text checks. It does not predict reach or expose X ranking
- weights.
+ Compose returns questions,
+ editorial rules, and source-specific Radar recommendations. Refine returns
+ goal-specific guidance. Score applies deterministic text checks. It does not
+ predict reach or expose X ranking weights.
Args:
topic: Subject for the post.
@@ -109,10 +109,10 @@ def create(
) -> ComposeCreateResponse:
"""Run one step of Xquik's three-step writing workflow.
- Compose returns questions
- and editorial rules. Refine returns goal-specific guidance. Score applies
- deterministic text checks. It does not predict reach or expose X ranking
- weights.
+ Compose returns questions,
+ editorial rules, and source-specific Radar recommendations. Refine returns
+ goal-specific guidance. Score applies deterministic text checks. It does not
+ predict reach or expose X ranking weights.
Args:
goal: Editorial goal for the guidance.
@@ -154,10 +154,10 @@ def create(
) -> ComposeCreateResponse:
"""Run one step of Xquik's three-step writing workflow.
- Compose returns questions
- and editorial rules. Refine returns goal-specific guidance. Score applies
- deterministic text checks. It does not predict reach or expose X ranking
- weights.
+ Compose returns questions,
+ editorial rules, and source-specific Radar recommendations. Refine returns
+ goal-specific guidance. Score applies deterministic text checks. It does not
+ predict reach or expose X ranking weights.
Args:
draft: Full post text for deterministic editorial checks.
@@ -267,10 +267,10 @@ async def create(
) -> ComposeCreateResponse:
"""Run one step of Xquik's three-step writing workflow.
- Compose returns questions
- and editorial rules. Refine returns goal-specific guidance. Score applies
- deterministic text checks. It does not predict reach or expose X ranking
- weights.
+ Compose returns questions,
+ editorial rules, and source-specific Radar recommendations. Refine returns
+ goal-specific guidance. Score applies deterministic text checks. It does not
+ predict reach or expose X ranking weights.
Args:
topic: Subject for the post.
@@ -309,10 +309,10 @@ async def create(
) -> ComposeCreateResponse:
"""Run one step of Xquik's three-step writing workflow.
- Compose returns questions
- and editorial rules. Refine returns goal-specific guidance. Score applies
- deterministic text checks. It does not predict reach or expose X ranking
- weights.
+ Compose returns questions,
+ editorial rules, and source-specific Radar recommendations. Refine returns
+ goal-specific guidance. Score applies deterministic text checks. It does not
+ predict reach or expose X ranking weights.
Args:
goal: Editorial goal for the guidance.
@@ -354,10 +354,10 @@ async def create(
) -> ComposeCreateResponse:
"""Run one step of Xquik's three-step writing workflow.
- Compose returns questions
- and editorial rules. Refine returns goal-specific guidance. Score applies
- deterministic text checks. It does not predict reach or expose X ranking
- weights.
+ Compose returns questions,
+ editorial rules, and source-specific Radar recommendations. Refine returns
+ goal-specific guidance. Score applies deterministic text checks. It does not
+ predict reach or expose X ranking weights.
Args:
draft: Full post text for deterministic editorial checks.
diff --git a/src/x_twitter_scraper/resources/x/__init__.py b/src/x_twitter_scraper/resources/x/__init__.py
index e40b088..562a792 100644
--- a/src/x_twitter_scraper/resources/x/__init__.py
+++ b/src/x_twitter_scraper/resources/x/__init__.py
@@ -100,6 +100,14 @@
WriteActionsResourceWithStreamingResponse,
AsyncWriteActionsResourceWithStreamingResponse,
)
+from .account_connection_attempts import (
+ AccountConnectionAttemptsResource,
+ AsyncAccountConnectionAttemptsResource,
+ AccountConnectionAttemptsResourceWithRawResponse,
+ AsyncAccountConnectionAttemptsResourceWithRawResponse,
+ AccountConnectionAttemptsResourceWithStreamingResponse,
+ AsyncAccountConnectionAttemptsResourceWithStreamingResponse,
+)
from .account_connection_challenges import (
AccountConnectionChallengesResource,
AsyncAccountConnectionChallengesResource,
@@ -170,6 +178,12 @@
"AsyncAccountConnectionChallengesResourceWithRawResponse",
"AccountConnectionChallengesResourceWithStreamingResponse",
"AsyncAccountConnectionChallengesResourceWithStreamingResponse",
+ "AccountConnectionAttemptsResource",
+ "AsyncAccountConnectionAttemptsResource",
+ "AccountConnectionAttemptsResourceWithRawResponse",
+ "AsyncAccountConnectionAttemptsResourceWithRawResponse",
+ "AccountConnectionAttemptsResourceWithStreamingResponse",
+ "AsyncAccountConnectionAttemptsResourceWithStreamingResponse",
"BookmarksResource",
"AsyncBookmarksResource",
"BookmarksResourceWithRawResponse",
diff --git a/src/x_twitter_scraper/resources/x/account_connection_attempts.py b/src/x_twitter_scraper/resources/x/account_connection_attempts.py
new file mode 100644
index 0000000..c5d31d4
--- /dev/null
+++ b/src/x_twitter_scraper/resources/x/account_connection_attempts.py
@@ -0,0 +1,180 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Any, cast
+
+import httpx
+
+from ..._types import Body, Query, Headers, NotGiven, not_given
+from ..._utils import path_template
+from ..._compat import cached_property
+from ..._resource import SyncAPIResource, AsyncAPIResource
+from ..._response import (
+ to_raw_response_wrapper,
+ to_streamed_response_wrapper,
+ async_to_raw_response_wrapper,
+ async_to_streamed_response_wrapper,
+)
+from ..._base_client import make_request_options
+from ...types.x.account_connection_attempt_retrieve_response import AccountConnectionAttemptRetrieveResponse
+
+__all__ = ["AccountConnectionAttemptsResource", "AsyncAccountConnectionAttemptsResource"]
+
+
+class AccountConnectionAttemptsResource(SyncAPIResource):
+ """Connected X account management"""
+
+ @cached_property
+ def with_raw_response(self) -> AccountConnectionAttemptsResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/Xquik-dev/x-twitter-scraper-python#accessing-raw-response-data-eg-headers
+ """
+ return AccountConnectionAttemptsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AccountConnectionAttemptsResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/Xquik-dev/x-twitter-scraper-python#with_streaming_response
+ """
+ return AccountConnectionAttemptsResourceWithStreamingResponse(self)
+
+ def retrieve(
+ self,
+ id: str,
+ *,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> AccountConnectionAttemptRetrieveResponse:
+ """
+ Get X account connection status
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ if not id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ return cast(
+ AccountConnectionAttemptRetrieveResponse,
+ self._get(
+ path_template("/x/account-connection-attempts/{id}", id=id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=cast(
+ Any, AccountConnectionAttemptRetrieveResponse
+ ), # Union types cannot be passed in as arguments in the type system
+ ),
+ )
+
+
+class AsyncAccountConnectionAttemptsResource(AsyncAPIResource):
+ """Connected X account management"""
+
+ @cached_property
+ def with_raw_response(self) -> AsyncAccountConnectionAttemptsResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/Xquik-dev/x-twitter-scraper-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncAccountConnectionAttemptsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncAccountConnectionAttemptsResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/Xquik-dev/x-twitter-scraper-python#with_streaming_response
+ """
+ return AsyncAccountConnectionAttemptsResourceWithStreamingResponse(self)
+
+ async def retrieve(
+ self,
+ id: str,
+ *,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> AccountConnectionAttemptRetrieveResponse:
+ """
+ Get X account connection status
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ if not id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ return cast(
+ AccountConnectionAttemptRetrieveResponse,
+ await self._get(
+ path_template("/x/account-connection-attempts/{id}", id=id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=cast(
+ Any, AccountConnectionAttemptRetrieveResponse
+ ), # Union types cannot be passed in as arguments in the type system
+ ),
+ )
+
+
+class AccountConnectionAttemptsResourceWithRawResponse:
+ def __init__(self, account_connection_attempts: AccountConnectionAttemptsResource) -> None:
+ self._account_connection_attempts = account_connection_attempts
+
+ self.retrieve = to_raw_response_wrapper(
+ account_connection_attempts.retrieve,
+ )
+
+
+class AsyncAccountConnectionAttemptsResourceWithRawResponse:
+ def __init__(self, account_connection_attempts: AsyncAccountConnectionAttemptsResource) -> None:
+ self._account_connection_attempts = account_connection_attempts
+
+ self.retrieve = async_to_raw_response_wrapper(
+ account_connection_attempts.retrieve,
+ )
+
+
+class AccountConnectionAttemptsResourceWithStreamingResponse:
+ def __init__(self, account_connection_attempts: AccountConnectionAttemptsResource) -> None:
+ self._account_connection_attempts = account_connection_attempts
+
+ self.retrieve = to_streamed_response_wrapper(
+ account_connection_attempts.retrieve,
+ )
+
+
+class AsyncAccountConnectionAttemptsResourceWithStreamingResponse:
+ def __init__(self, account_connection_attempts: AsyncAccountConnectionAttemptsResource) -> None:
+ self._account_connection_attempts = account_connection_attempts
+
+ self.retrieve = async_to_streamed_response_wrapper(
+ account_connection_attempts.retrieve,
+ )
diff --git a/src/x_twitter_scraper/resources/x/accounts.py b/src/x_twitter_scraper/resources/x/accounts.py
index 8efaf97..e2c7a34 100644
--- a/src/x_twitter_scraper/resources/x/accounts.py
+++ b/src/x_twitter_scraper/resources/x/accounts.py
@@ -22,7 +22,6 @@
from ..._base_client import make_request_options
from ...types.x.x_account_detail import XAccountDetail
from ...types.x.account_list_response import AccountListResponse
-from ...types.x.account_create_response import AccountCreateResponse
from ...types.x.account_delete_response import AccountDeleteResponse
from ...types.x.account_reauth_response import AccountReauthResponse
from ...types.x.account_bulk_retry_response import AccountBulkRetryResponse
@@ -57,15 +56,15 @@ def create(
*,
email: str,
password: str,
+ totp_secret: str,
username: str,
- totp_secret: str | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> AccountCreateResponse:
+ ) -> object:
"""
Connect X account
@@ -74,9 +73,9 @@ def create(
password: Account password
- username: X username
+ totp_secret: Authenticator App TOTP secret required for durable login
- totp_secret: TOTP secret for 2FA
+ username: X username
extra_headers: Send extra headers
@@ -92,15 +91,15 @@ def create(
{
"email": email,
"password": password,
- "username": username,
"totp_secret": totp_secret,
+ "username": username,
},
account_create_params.AccountCreateParams,
),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
- cast_to=AccountCreateResponse,
+ cast_to=object,
)
def retrieve(
@@ -232,7 +231,7 @@ def reauth(
email: Email for the X account (updates stored email)
- totp_secret: TOTP secret for 2FA re-authentication
+ totp_secret: Replacement Authenticator App TOTP secret. Omit it to reuse the saved secret.
extra_headers: Send extra headers
@@ -288,15 +287,15 @@ async def create(
*,
email: str,
password: str,
+ totp_secret: str,
username: str,
- totp_secret: str | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> AccountCreateResponse:
+ ) -> object:
"""
Connect X account
@@ -305,9 +304,9 @@ async def create(
password: Account password
- username: X username
+ totp_secret: Authenticator App TOTP secret required for durable login
- totp_secret: TOTP secret for 2FA
+ username: X username
extra_headers: Send extra headers
@@ -323,15 +322,15 @@ async def create(
{
"email": email,
"password": password,
- "username": username,
"totp_secret": totp_secret,
+ "username": username,
},
account_create_params.AccountCreateParams,
),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
- cast_to=AccountCreateResponse,
+ cast_to=object,
)
async def retrieve(
@@ -463,7 +462,7 @@ async def reauth(
email: Email for the X account (updates stored email)
- totp_secret: TOTP secret for 2FA re-authentication
+ totp_secret: Replacement Authenticator App TOTP secret. Omit it to reuse the saved secret.
extra_headers: Send extra headers
diff --git a/src/x_twitter_scraper/resources/x/x.py b/src/x_twitter_scraper/resources/x/x.py
index 8171ec7..041f7ba 100644
--- a/src/x_twitter_scraper/resources/x/x.py
+++ b/src/x_twitter_scraper/resources/x/x.py
@@ -110,6 +110,14 @@
CommunitiesResourceWithStreamingResponse,
AsyncCommunitiesResourceWithStreamingResponse,
)
+from .account_connection_attempts import (
+ AccountConnectionAttemptsResource,
+ AsyncAccountConnectionAttemptsResource,
+ AccountConnectionAttemptsResourceWithRawResponse,
+ AsyncAccountConnectionAttemptsResourceWithRawResponse,
+ AccountConnectionAttemptsResourceWithStreamingResponse,
+ AsyncAccountConnectionAttemptsResourceWithStreamingResponse,
+)
from ...types.x_get_trends_response import XGetTrendsResponse
from .account_connection_challenges import (
AccountConnectionChallengesResource,
@@ -172,6 +180,11 @@ def account_connection_challenges(self) -> AccountConnectionChallengesResource:
"""Connected X account management"""
return AccountConnectionChallengesResource(self._client)
+ @cached_property
+ def account_connection_attempts(self) -> AccountConnectionAttemptsResource:
+ """Connected X account management"""
+ return AccountConnectionAttemptsResource(self._client)
+
@cached_property
def bookmarks(self) -> BookmarksResource:
"""Look up, search, and analyze individual tweets"""
@@ -420,6 +433,11 @@ def account_connection_challenges(self) -> AsyncAccountConnectionChallengesResou
"""Connected X account management"""
return AsyncAccountConnectionChallengesResource(self._client)
+ @cached_property
+ def account_connection_attempts(self) -> AsyncAccountConnectionAttemptsResource:
+ """Connected X account management"""
+ return AsyncAccountConnectionAttemptsResource(self._client)
+
@cached_property
def bookmarks(self) -> AsyncBookmarksResource:
"""Look up, search, and analyze individual tweets"""
@@ -684,6 +702,11 @@ def account_connection_challenges(self) -> AccountConnectionChallengesResourceWi
"""Connected X account management"""
return AccountConnectionChallengesResourceWithRawResponse(self._x.account_connection_challenges)
+ @cached_property
+ def account_connection_attempts(self) -> AccountConnectionAttemptsResourceWithRawResponse:
+ """Connected X account management"""
+ return AccountConnectionAttemptsResourceWithRawResponse(self._x.account_connection_attempts)
+
@cached_property
def bookmarks(self) -> BookmarksResourceWithRawResponse:
"""Look up, search, and analyze individual tweets"""
@@ -757,6 +780,11 @@ def account_connection_challenges(self) -> AsyncAccountConnectionChallengesResou
"""Connected X account management"""
return AsyncAccountConnectionChallengesResourceWithRawResponse(self._x.account_connection_challenges)
+ @cached_property
+ def account_connection_attempts(self) -> AsyncAccountConnectionAttemptsResourceWithRawResponse:
+ """Connected X account management"""
+ return AsyncAccountConnectionAttemptsResourceWithRawResponse(self._x.account_connection_attempts)
+
@cached_property
def bookmarks(self) -> AsyncBookmarksResourceWithRawResponse:
"""Look up, search, and analyze individual tweets"""
@@ -830,6 +858,11 @@ def account_connection_challenges(self) -> AccountConnectionChallengesResourceWi
"""Connected X account management"""
return AccountConnectionChallengesResourceWithStreamingResponse(self._x.account_connection_challenges)
+ @cached_property
+ def account_connection_attempts(self) -> AccountConnectionAttemptsResourceWithStreamingResponse:
+ """Connected X account management"""
+ return AccountConnectionAttemptsResourceWithStreamingResponse(self._x.account_connection_attempts)
+
@cached_property
def bookmarks(self) -> BookmarksResourceWithStreamingResponse:
"""Look up, search, and analyze individual tweets"""
@@ -903,6 +936,11 @@ def account_connection_challenges(self) -> AsyncAccountConnectionChallengesResou
"""Connected X account management"""
return AsyncAccountConnectionChallengesResourceWithStreamingResponse(self._x.account_connection_challenges)
+ @cached_property
+ def account_connection_attempts(self) -> AsyncAccountConnectionAttemptsResourceWithStreamingResponse:
+ """Connected X account management"""
+ return AsyncAccountConnectionAttemptsResourceWithStreamingResponse(self._x.account_connection_attempts)
+
@cached_property
def bookmarks(self) -> AsyncBookmarksResourceWithStreamingResponse:
"""Look up, search, and analyze individual tweets"""
diff --git a/src/x_twitter_scraper/types/compose_create_response.py b/src/x_twitter_scraper/types/compose_create_response.py
index e0c8162..f6c8b2e 100644
--- a/src/x_twitter_scraper/types/compose_create_response.py
+++ b/src/x_twitter_scraper/types/compose_create_response.py
@@ -16,6 +16,7 @@
"ComposePrepareResult",
"ComposePrepareResultContentRule",
"ComposePrepareResultEngagementMultiplier",
+ "ComposePrepareResultRadarRecommendation",
"ComposePrepareResultScorerWeight",
"ComposePrepareResultSavedStyle",
"ComposeRefineResult",
@@ -36,6 +37,19 @@ class ComposePrepareResultEngagementMultiplier(BaseModel):
multiplier: Literal["Production weight not published by X"]
+class ComposePrepareResultRadarRecommendation(BaseModel):
+ endpoint: str
+ """Radar endpoint for this source."""
+
+ guidance: str
+ """Source-specific drafting guidance."""
+
+ source: Literal["reddit", "github", "trustmrr", "hacker_news", "google_trends", "wikipedia", "polymarket"]
+
+ use_for: str = FieldInfo(alias="useFor")
+ """Current-topic research this source supports."""
+
+
class ComposePrepareResultScorerWeight(BaseModel):
context: str
"""Signal direction and publication limit."""
@@ -70,6 +84,9 @@ class ComposePrepareResult(BaseModel):
next_step: str = FieldInfo(alias="nextStep")
+ radar_recommendations: List[ComposePrepareResultRadarRecommendation] = FieldInfo(alias="radarRecommendations")
+ """Sources and guidance for researching a fresh post angle."""
+
scorer_weights: List[ComposePrepareResultScorerWeight] = FieldInfo(alias="scorerWeights")
"""Published signal names with unpublished weights as null."""
diff --git a/src/x_twitter_scraper/types/radar_item.py b/src/x_twitter_scraper/types/radar_item.py
index 99f43e1..b6c358c 100644
--- a/src/x_twitter_scraper/types/radar_item.py
+++ b/src/x_twitter_scraper/types/radar_item.py
@@ -4,7 +4,7 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-from typing import Dict, Optional
+from typing import TYPE_CHECKING, Dict, Optional
from datetime import datetime
from typing_extensions import Literal
@@ -12,7 +12,70 @@
from .._models import BaseModel
-__all__ = ["RadarItem"]
+__all__ = ["RadarItem", "Metadata"]
+
+
+class Metadata(BaseModel):
+ """Source-specific fields.
+
+ Shape varies per source:
+ - reddit: { author, authorId?, subreddit, subredditId?,
+ subredditSubscribers?, sourceFormat, score?, upvoteRatio?,
+ estimatedUpvotes?, estimatedDownvotes?, numberComments?,
+ numberCrossposts?, selftext?, contentUrl?, domain?, postHint?,
+ linkFlairText?, distinguished?, totalAwardsReceived?, viewCount?,
+ editedAt?, galleryImageUrls?, redditVideo?, archived?, contestMode?,
+ isCrosspostable?, isMeta?, isNsfw?, isOriginalContent?,
+ isRobotIndexable?, isSelf?, isSpoiler?, isVideo?, locked?,
+ stickied? }. `score` is Reddit's public net score. Exact public
+ upvote and downvote counts are not available. Estimated counts
+ derive from the public score and upvote ratio, which Reddit may
+ fuzz. Comment bodies are not included. Current items combine
+ public listing discovery with server-rendered post data and use
+ `sourceFormat: html`; `json` and `rss` remain for legacy rows.
+ - github: { starsToday: number }
+ - hacker_news: { points: number, numberComments: number }
+ - google_trends: { approxTraffic: number }
+ - polymarket: { volume24hr: number }
+ - wikipedia: { views: number }
+ - trustmrr: { mrr, growthPercent, last30Days, total, customers, activeSubscriptions, onSale, xHandle?, category?, askingPrice?, country?, foundedDate?, googleSearchImpressionsLast30Days?, growthMrrPercent?, multiple?, paymentProvider?, profitMarginLast30Days?, rank?, revenuePerVisitor?, targetAudience?, visitorsLast30Days? }
+ For the startup growth source, xHandle is the founder's X username
+ without @. The rank field is the source's revenue rank. Result order
+ represents reported 30-day revenue-growth rank.
+ """
+
+ author: Optional[str] = None
+
+ content_url: Optional[str] = FieldInfo(alias="contentUrl", default=None)
+
+ estimated_downvotes: Optional[int] = FieldInfo(alias="estimatedDownvotes", default=None)
+
+ estimated_upvotes: Optional[int] = FieldInfo(alias="estimatedUpvotes", default=None)
+
+ number_comments: Optional[int] = FieldInfo(alias="numberComments", default=None)
+
+ score: Optional[int] = None
+
+ selftext: Optional[str] = None
+
+ source_format: Optional[Literal["html", "json", "rss"]] = FieldInfo(alias="sourceFormat", default=None)
+ """Current items use html. json and rss are retained for legacy rows."""
+
+ subreddit: Optional[str] = None
+
+ upvote_ratio: Optional[float] = FieldInfo(alias="upvoteRatio", default=None)
+
+ if TYPE_CHECKING:
+ # Some versions of Pydantic <2.8.0 have a bug and don’t allow assigning a
+ # value to this field, so for compatibility we avoid doing it at runtime.
+ __pydantic_extra__: Dict[str, object] = FieldInfo(init=False) # pyright: ignore[reportIncompatibleVariableOverride]
+
+ # Stub to indicate that arbitrary properties are accepted.
+ # To access properties that are not valid identifiers you can use `getattr`, e.g.
+ # `getattr(obj, '$type')`
+ def __getattr__(self, attr: str) -> object: ...
+ else:
+ __pydantic_extra__: Dict[str, object]
class RadarItem(BaseModel):
@@ -28,11 +91,23 @@ class RadarItem(BaseModel):
created_at: datetime = FieldInfo(alias="createdAt")
language: str
+ """BCP-47 language code. und means the source did not identify a language."""
- metadata: Dict[str, object]
+ metadata: Metadata
"""Source-specific fields. Shape varies per source:
- - reddit: { subreddit: string, author: string }
+ - reddit: { author, authorId?, subreddit, subredditId?, subredditSubscribers?,
+ sourceFormat, score?, upvoteRatio?, estimatedUpvotes?, estimatedDownvotes?,
+ numberComments?, numberCrossposts?, selftext?, contentUrl?, domain?,
+ postHint?, linkFlairText?, distinguished?, totalAwardsReceived?, viewCount?,
+ editedAt?, galleryImageUrls?, redditVideo?, archived?, contestMode?,
+ isCrosspostable?, isMeta?, isNsfw?, isOriginalContent?, isRobotIndexable?,
+ isSelf?, isSpoiler?, isVideo?, locked?, stickied? }. `score` is Reddit's
+ public net score. Exact public upvote and downvote counts are not available.
+ Estimated counts derive from the public score and upvote ratio, which Reddit
+ may fuzz. Comment bodies are not included. Current items combine public
+ listing discovery with server-rendered post data and use `sourceFormat: html`;
+ `json` and `rss` remain for legacy rows.
- github: { starsToday: number }
- hacker_news: { points: number, numberComments: number }
- google_trends: { approxTraffic: number }
@@ -40,7 +115,12 @@ class RadarItem(BaseModel):
- wikipedia: { views: number }
- trustmrr: { mrr, growthPercent, last30Days, total, customers,
activeSubscriptions, onSale, xHandle?, category?, askingPrice?, country?,
- growthMrrPercent?, multiple?, paymentProvider?, rank? }
+ foundedDate?, googleSearchImpressionsLast30Days?, growthMrrPercent?,
+ multiple?, paymentProvider?, profitMarginLast30Days?, rank?,
+ revenuePerVisitor?, targetAudience?, visitorsLast30Days? } For the startup
+ growth source, xHandle is the founder's X username without @. The rank field
+ is the source's revenue rank. Result order represents reported 30-day
+ revenue-growth rank.
"""
published_at: datetime = FieldInfo(alias="publishedAt")
@@ -59,5 +139,6 @@ class RadarItem(BaseModel):
description: Optional[str] = None
image_url: Optional[str] = FieldInfo(alias="imageUrl", default=None)
+ """Source image. Startup growth items return the logo here."""
url: Optional[str] = None
diff --git a/src/x_twitter_scraper/types/x/__init__.py b/src/x_twitter_scraper/types/x/__init__.py
index d96125f..a2de5e3 100644
--- a/src/x_twitter_scraper/types/x/__init__.py
+++ b/src/x_twitter_scraper/types/x/__init__.py
@@ -27,7 +27,6 @@
from .profile_update_params import ProfileUpdateParams as ProfileUpdateParams
from .tweet_create_response import TweetCreateResponse as TweetCreateResponse
from .tweet_delete_response import TweetDeleteResponse as TweetDeleteResponse
-from .account_create_response import AccountCreateResponse as AccountCreateResponse
from .account_delete_response import AccountDeleteResponse as AccountDeleteResponse
from .account_reauth_response import AccountReauthResponse as AccountReauthResponse
from .community_create_params import CommunityCreateParams as CommunityCreateParams
@@ -80,6 +79,9 @@
from .account_connection_challenge_submit_params import (
AccountConnectionChallengeSubmitParams as AccountConnectionChallengeSubmitParams,
)
+from .account_connection_attempt_retrieve_response import (
+ AccountConnectionAttemptRetrieveResponse as AccountConnectionAttemptRetrieveResponse,
+)
from .account_connection_challenge_submit_response import (
AccountConnectionChallengeSubmitResponse as AccountConnectionChallengeSubmitResponse,
)
diff --git a/src/x_twitter_scraper/types/x/account_connection_attempt_retrieve_response.py b/src/x_twitter_scraper/types/x/account_connection_attempt_retrieve_response.py
new file mode 100644
index 0000000..7f8592f
--- /dev/null
+++ b/src/x_twitter_scraper/types/x/account_connection_attempt_retrieve_response.py
@@ -0,0 +1,82 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Union, Optional
+from datetime import datetime
+from typing_extensions import Literal, TypeAlias
+
+from pydantic import Field as FieldInfo
+
+from ..._models import BaseModel
+
+__all__ = [
+ "AccountConnectionAttemptRetrieveResponse",
+ "XAccountConnectionAttemptPending",
+ "XAccountConnectionAttemptSuccess",
+ "XAccountConnectionAttemptFailed",
+ "XAccountConnectionChallenge",
+]
+
+
+class XAccountConnectionAttemptPending(BaseModel):
+ """The connection is still in progress."""
+
+ id: str
+
+ object: Literal["x_account_connection_attempt"]
+
+ poll_after_ms: int = FieldInfo(alias="pollAfterMs")
+
+ status: Literal["pending"]
+
+
+class XAccountConnectionAttemptSuccess(BaseModel):
+ """The account connected successfully."""
+
+ id: str
+
+ object: Literal["x_account_connection_attempt"]
+
+ status: Literal["success"]
+
+
+class XAccountConnectionAttemptFailed(BaseModel):
+ """The connection reached a final failure."""
+
+ id: str
+
+ error: str
+
+ object: Literal["x_account_connection_attempt"]
+
+ retryable: bool
+
+ status: Literal["failed"]
+
+ reason: Optional[str] = None
+
+
+class XAccountConnectionChallenge(BaseModel):
+ """Resumable account connection challenge.
+
+ Submit the email code to finish the same connection attempt.
+ """
+
+ id: str
+
+ expires_at: datetime = FieldInfo(alias="expiresAt")
+
+ message: str
+
+ object: Literal["x_account_connection_challenge"]
+
+ status: Literal["requires_email_code"]
+
+ username: str
+
+
+AccountConnectionAttemptRetrieveResponse: TypeAlias = Union[
+ XAccountConnectionAttemptPending,
+ XAccountConnectionAttemptSuccess,
+ XAccountConnectionAttemptFailed,
+ XAccountConnectionChallenge,
+]
diff --git a/src/x_twitter_scraper/types/x/account_create_params.py b/src/x_twitter_scraper/types/x/account_create_params.py
index 885e079..834f6f4 100644
--- a/src/x_twitter_scraper/types/x/account_create_params.py
+++ b/src/x_twitter_scraper/types/x/account_create_params.py
@@ -18,8 +18,8 @@ class AccountCreateParams(TypedDict, total=False):
password: Required[str]
"""Account password"""
+ totp_secret: Required[str]
+ """Authenticator App TOTP secret required for durable login"""
+
username: Required[str]
"""X username"""
-
- totp_secret: str
- """TOTP secret for 2FA"""
diff --git a/src/x_twitter_scraper/types/x/account_create_response.py b/src/x_twitter_scraper/types/x/account_create_response.py
deleted file mode 100644
index 26efad3..0000000
--- a/src/x_twitter_scraper/types/x/account_create_response.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# SPDX-FileCopyrightText: 2026 Xquik contributors
-#
-# SPDX-License-Identifier: Apache-2.0
-
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from datetime import datetime
-from typing_extensions import Literal
-
-from pydantic import Field as FieldInfo
-
-from ..._models import BaseModel
-
-__all__ = ["AccountCreateResponse"]
-
-
-class AccountCreateResponse(BaseModel):
- """Sanitized X account summary returned by connect and reauth."""
-
- id: str
-
- created_at: datetime = FieldInfo(alias="createdAt")
-
- health: Literal["healthy", "locked", "needsReauth", "recovering", "suspended", "temporaryIssue"]
-
- status: str
-
- x_user_id: str = FieldInfo(alias="xUserId")
-
- x_username: str = FieldInfo(alias="xUsername")
diff --git a/src/x_twitter_scraper/types/x/account_reauth_params.py b/src/x_twitter_scraper/types/x/account_reauth_params.py
index 5cb6225..e5158f6 100644
--- a/src/x_twitter_scraper/types/x/account_reauth_params.py
+++ b/src/x_twitter_scraper/types/x/account_reauth_params.py
@@ -19,4 +19,4 @@ class AccountReauthParams(TypedDict, total=False):
"""Email for the X account (updates stored email)"""
totp_secret: str
- """TOTP secret for 2FA re-authentication"""
+ """Replacement Authenticator App TOTP secret. Omit it to reuse the saved secret."""
diff --git a/src/x_twitter_scraper/types/x/x_account.py b/src/x_twitter_scraper/types/x/x_account.py
index 43bcbed..01ffda7 100644
--- a/src/x_twitter_scraper/types/x/x_account.py
+++ b/src/x_twitter_scraper/types/x/x_account.py
@@ -27,10 +27,11 @@ class XAccount(BaseModel):
health: Literal["healthy", "locked", "needsReauth", "recovering", "suspended", "temporaryIssue"]
"""Derived connection health.
- `healthy` = session active. `needsReauth` = user must submit fresh credentials.
+ `healthy` = ready to use. `needsReauth` = user must submit fresh credentials.
`locked` = X locked the account; unlock on x.com first. `suspended` = X banned
- the account. `recovering` = past cooldown, will auto-retry on next use.
- `temporaryIssue` = temporary connection problem; retry shortly.
+ the account. `recovering` = cooldown ended; the account can reconnect on its
+ next use. `temporaryIssue` = temporary connection problem; wait before the next
+ use.
"""
status: str
diff --git a/tests/api_resources/x/test_account_connection_attempts.py b/tests/api_resources/x/test_account_connection_attempts.py
new file mode 100644
index 0000000..e72ae2f
--- /dev/null
+++ b/tests/api_resources/x/test_account_connection_attempts.py
@@ -0,0 +1,108 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import os
+from typing import Any, cast
+
+import pytest
+
+from tests.utils import assert_matches_type
+from x_twitter_scraper import XTwitterScraper, AsyncXTwitterScraper
+from x_twitter_scraper.types.x import AccountConnectionAttemptRetrieveResponse
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestAccountConnectionAttempts:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_retrieve(self, client: XTwitterScraper) -> None:
+ account_connection_attempt = client.x.account_connection_attempts.retrieve(
+ "xatt_0123456789abcdef0123456789abcdef",
+ )
+ assert_matches_type(AccountConnectionAttemptRetrieveResponse, account_connection_attempt, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_retrieve(self, client: XTwitterScraper) -> None:
+ response = client.x.account_connection_attempts.with_raw_response.retrieve(
+ "xatt_0123456789abcdef0123456789abcdef",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ account_connection_attempt = response.parse()
+ assert_matches_type(AccountConnectionAttemptRetrieveResponse, account_connection_attempt, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_retrieve(self, client: XTwitterScraper) -> None:
+ with client.x.account_connection_attempts.with_streaming_response.retrieve(
+ "xatt_0123456789abcdef0123456789abcdef",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ account_connection_attempt = response.parse()
+ assert_matches_type(AccountConnectionAttemptRetrieveResponse, account_connection_attempt, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_path_params_retrieve(self, client: XTwitterScraper) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ client.x.account_connection_attempts.with_raw_response.retrieve(
+ "",
+ )
+
+
+class TestAsyncAccountConnectionAttempts:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_retrieve(self, async_client: AsyncXTwitterScraper) -> None:
+ account_connection_attempt = await async_client.x.account_connection_attempts.retrieve(
+ "xatt_0123456789abcdef0123456789abcdef",
+ )
+ assert_matches_type(AccountConnectionAttemptRetrieveResponse, account_connection_attempt, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_raw_response_retrieve(self, async_client: AsyncXTwitterScraper) -> None:
+ response = await async_client.x.account_connection_attempts.with_raw_response.retrieve(
+ "xatt_0123456789abcdef0123456789abcdef",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ account_connection_attempt = await response.parse()
+ assert_matches_type(AccountConnectionAttemptRetrieveResponse, account_connection_attempt, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_streaming_response_retrieve(self, async_client: AsyncXTwitterScraper) -> None:
+ async with async_client.x.account_connection_attempts.with_streaming_response.retrieve(
+ "xatt_0123456789abcdef0123456789abcdef",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ account_connection_attempt = await response.parse()
+ assert_matches_type(AccountConnectionAttemptRetrieveResponse, account_connection_attempt, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_path_params_retrieve(self, async_client: AsyncXTwitterScraper) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ await async_client.x.account_connection_attempts.with_raw_response.retrieve(
+ "",
+ )
diff --git a/tests/api_resources/x/test_accounts.py b/tests/api_resources/x/test_accounts.py
index 493525e..c3d34b5 100644
--- a/tests/api_resources/x/test_accounts.py
+++ b/tests/api_resources/x/test_accounts.py
@@ -16,7 +16,6 @@
from x_twitter_scraper.types.x import (
XAccountDetail,
AccountListResponse,
- AccountCreateResponse,
AccountDeleteResponse,
AccountReauthResponse,
AccountBulkRetryResponse,
@@ -34,20 +33,10 @@ def test_method_create(self, client: XTwitterScraper) -> None:
account = client.x.accounts.create(
email="account@example.invalid",
password="",
- username="your_x_username",
- )
- assert_matches_type(AccountCreateResponse, account, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_method_create_with_all_params(self, client: XTwitterScraper) -> None:
- account = client.x.accounts.create(
- email="account@example.invalid",
- password="",
- username="your_x_username",
totp_secret="",
+ username="your_x_username",
)
- assert_matches_type(AccountCreateResponse, account, path=["response"])
+ assert_matches_type(object, account, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -55,13 +44,14 @@ def test_raw_response_create(self, client: XTwitterScraper) -> None:
response = client.x.accounts.with_raw_response.create(
email="account@example.invalid",
password="",
+ totp_secret="",
username="your_x_username",
)
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
account = response.parse()
- assert_matches_type(AccountCreateResponse, account, path=["response"])
+ assert_matches_type(object, account, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -69,13 +59,14 @@ def test_streaming_response_create(self, client: XTwitterScraper) -> None:
with client.x.accounts.with_streaming_response.create(
email="account@example.invalid",
password="",
+ totp_secret="",
username="your_x_username",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
account = response.parse()
- assert_matches_type(AccountCreateResponse, account, path=["response"])
+ assert_matches_type(object, account, path=["response"])
assert cast(Any, response.is_closed) is True
@@ -288,20 +279,10 @@ async def test_method_create(self, async_client: AsyncXTwitterScraper) -> None:
account = await async_client.x.accounts.create(
email="account@example.invalid",
password="",
- username="your_x_username",
- )
- assert_matches_type(AccountCreateResponse, account, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- async def test_method_create_with_all_params(self, async_client: AsyncXTwitterScraper) -> None:
- account = await async_client.x.accounts.create(
- email="account@example.invalid",
- password="",
- username="your_x_username",
totp_secret="",
+ username="your_x_username",
)
- assert_matches_type(AccountCreateResponse, account, path=["response"])
+ assert_matches_type(object, account, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -309,13 +290,14 @@ async def test_raw_response_create(self, async_client: AsyncXTwitterScraper) ->
response = await async_client.x.accounts.with_raw_response.create(
email="account@example.invalid",
password="",
+ totp_secret="",
username="your_x_username",
)
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
account = await response.parse()
- assert_matches_type(AccountCreateResponse, account, path=["response"])
+ assert_matches_type(object, account, path=["response"])
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
@@ -323,13 +305,14 @@ async def test_streaming_response_create(self, async_client: AsyncXTwitterScrape
async with async_client.x.accounts.with_streaming_response.create(
email="account@example.invalid",
password="",
+ totp_secret="",
username="your_x_username",
) as response:
assert not response.is_closed
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
account = await response.parse()
- assert_matches_type(AccountCreateResponse, account, path=["response"])
+ assert_matches_type(object, account, path=["response"])
assert cast(Any, response.is_closed) is True
diff --git a/tests/mock_api_routes.py b/tests/mock_api_routes.py
index ebc5829..fba94ce 100644
--- a/tests/mock_api_routes.py
+++ b/tests/mock_api_routes.py
@@ -19,6 +19,7 @@
class ResponseKind(Enum):
EMPTY = "empty"
BINARY = "binary"
+ JSON_OBJECT = "json_object"
ResponseType = type[BaseModel] | ResponseKind
@@ -74,6 +75,8 @@ def _response_type(module_name: str, name: str) -> ResponseType:
return ResponseKind.EMPTY
if name in {"BinaryAPIResponse", "AsyncBinaryAPIResponse"}:
return ResponseKind.BINARY
+ if name == "object":
+ return ResponseKind.JSON_OBJECT
module = importlib.import_module(module_name)
response_type = getattr(module, name, None)
diff --git a/tests/mock_api_server.py b/tests/mock_api_server.py
index ade40af..01d4a97 100644
--- a/tests/mock_api_server.py
+++ b/tests/mock_api_server.py
@@ -69,6 +69,9 @@ def _handle(self) -> None:
if route.response_type is ResponseKind.BINARY:
self._write_response(HTTPStatus.OK, b"fixture", "application/octet-stream")
return
+ if route.response_type is ResponseKind.JSON_OBJECT:
+ self._write_response(HTTPStatus.OK, b"{}", "application/json")
+ return
self._write_response(
HTTPStatus.OK,
self.model_payloads[route.response_type],
diff --git a/uv.lock b/uv.lock
index 568c5c9..ad6c6f1 100644
--- a/uv.lock
+++ b/uv.lock
@@ -1571,7 +1571,7 @@ wheels = [
[[package]]
name = "x-twitter-scraper"
-version = "0.6.1"
+version = "0.7.0"
source = { editable = "." }
dependencies = [
{ name = "anyio" },