Published June 2026: reflects X's current pay-per-use pricing (including the April 2026 write-cost changes) and the state of PHP tooling, where X ships official SDKs only for Python and TypeScript, not PHP.
Key Takeaway: There is no official X (Twitter) API SDK for PHP in 2026; X ships official SDKs only for Python and TypeScript. The practical routes in PHP are a community library such as twitteroauth, plain cURL or Guzzle with a bearer token, or a read-only third-party REST API.
If you searched "twitter api php" expecting an official, supported package, there is not one. X shipped first-party SDKs for Python and TypeScript in late 2025 and left PHP to the community. Most PHP tutorials that rank for this query teach posting through OAuth, or use the old v1.1 endpoints that X retired, against pricing that no longer exists.
We build and run Sorsa API, an alternative Twitter/X API, and the read-only path fits PHP cleanly: it returns profiles, tweets, search results, and followers as JSON that json_decode turns into a plain array, with one API key in the ApiKey header, no OAuth flow, and no developer-account approval to wait on. On read-heavy work it runs up to roughly 50x cheaper than the official X API, holds a flat 20 requests per second on every plan, and starts at $49 a month for 10,000 requests. Not every project fits that mold: some need to post, and some need the official API for compliance. This guide covers every PHP route with working code (cURL, Guzzle, and WordPress), current pricing, and a collector that paginates and retries. You can also test calls without writing code in the playground.
Table of contents
- What changed: the X API and PHP tooling in 2026
- The best PHP library for the X API
- Which approach should you use?
- Method 1: a community library (twitteroauth)
- Method 2: plain cURL or Guzzle with a bearer token
- Method 3: a read-only REST API
- Is there an official PHP SDK for the X API?
- Calling the X API from WordPress
- Building a data collector in PHP
- Comparison: three routes, side by side
- How to get your API credentials
- In practice: cutting the cost of a PHP integration
- FAQ
- Getting started
What Changed: the X API and PHP Tooling in 2026
Three things changed for PHP developers since the old tutorials were written. The X API moved to pay-per-use billing with no free tier and charges per resource read. Writing got more expensive after the April 2026 update. And X shipped its first official SDKs, but only for Python and TypeScript, so PHP developers still rely on community libraries or raw HTTP.
Pay-per-use is the default. There is no free tier and no monthly Basic plan for new signups. You buy credits and pay per resource: $0.005 per post read, $0.010 per user profile, and $0.010 per follower or following record. Reading your own account's data costs $0.001 per resource, and standard accounts are capped at 2 million post reads per month. The numbers behind a real budget are in our X API pricing breakdown and the explainer on why X API pricing climbed.
Writing got more expensive. After the April 2026 update, a standard post costs $0.015 per request and a post that contains a URL costs $0.20. Follow, like, and quote-post actions were pulled from the self-serve tiers and now require an Enterprise contract.
Official SDKs landed for Python and TypeScript only. In late 2025 X announced first-party SDKs for those two languages. There is no official PHP SDK. The community libraries fill the gap, and the most widely used remains twitteroauth, which supports the v2 endpoints once you set the API version.
Most PHP examples online are stale. A large share teach v1.1 calls like statuses/update or search/tweets, which X retired, or focus only on posting. Reading public data through v2 is a different path, and it is the one this guide takes.
The Best PHP Library for the X API
For most PHP projects, twitteroauth is still the default: it is the most widely used PHP client, installs through Composer, and reaches the v2 endpoints with setApiVersion('2') plus generic get and post calls. It is in maintenance mode (no new feature development), but it works. For a v2-native wrapper, community packages such as twitter-api-v2-php and bird-elephant target the v2 API directly. For read-only data collection, many teams skip libraries and call a third-party REST API with plain cURL or Guzzle, which removes OAuth entirely.
Here is how the main options compare.
| Library / tool | API version | Best for | Notes |
|---|---|---|---|
| twitteroauth | v1.1 and v2 | Most projects, widest usage | Composer install. Reaches v2 through setApiVersion and generic get/post. In maintenance mode, but functional. |
| twitter-api-v2-php | v2 | Modern v2-native access | Wrapper focused on v2 endpoints. Smaller community than twitteroauth. |
| bird-elephant | v2 | v2 endpoint coverage | Community PHP client for the v2 API. |
| cURL or Guzzle (no wrapper) | any | Minimal dependencies, full control | You build requests and pagination. Pairs well with a third-party API. |
| Read-only REST API | n/a | Read-heavy data collection | One key in a header, no OAuth, flat per-request billing. Read-only. |
Whichever library you pick for the official API, the cost is identical, because X bills per resource on its side, not per library. The variable you control is how many resources you pull, which is where batch endpoints and a flat-rate API change the math.
Which Approach Should You Use?
Pick the route before writing code. For read and write against the v2 API with the most common library, use twitteroauth. For read-only data at volume with minimal setup, a third-party REST API removes OAuth and the approval queue. For full control with no wrapper, plain cURL or Guzzle is enough. The decision is mostly read versus write, and how much volume you pull.
| If you need... | Use... |
|---|---|
| Read and write with a popular library | twitteroauth |
| Read-only data at scale, minimal setup | A read-only third-party REST API |
| Full control, no wrapper | Plain cURL or Guzzle with a bearer token |
| To post, like, or follow | twitteroauth or the official API (OAuth required) |
If your project only reads public data, a third-party API removes the OAuth flow: one key in a header and you start pulling data, with no developer-account application and no credit purchase. If you need to post or run write actions, the official API through twitteroauth is the path; no third-party provider posts on your behalf. Working in another language? See the Python version of this guide.
Method 1: a Community Library (twitteroauth)
twitteroauth is the most widely used PHP client for the X API. It installs through Composer, handles authentication, and reaches the v2 endpoints once you call setApiVersion('2'). For reading public data, an application-only bearer token is enough.
Install it:
composer require abraham/twitteroauth
Build an app-only connection and search the last seven days:
<?php
require 'vendor/autoload.php';
use Abraham\TwitterOAuth\TwitterOAuth;
// App-only auth: API key, API secret, null, bearer token
$connection = new TwitterOAuth(
getenv('X_API_KEY'),
getenv('X_API_SECRET'),
null,
getenv('X_API_BEARER_TOKEN')
);
$connection->setApiVersion('2');
$tweets = $connection->get('tweets/search/recent', [
'query' => 'php lang:en',
'max_results' => 20,
'tweet.fields' => 'created_at,public_metrics',
]);
foreach ($tweets->data as $tweet) {
echo $tweet->text . "\n";
}
Look up a profile through the same generic get call:
$user = $connection->get('users/by/username/elonmusk', [
'user.fields' => 'public_metrics,created_at',
]);
printf(
"@%s has %d followers\n",
$user->data->username,
$user->data->public_metrics->followers_count
);
twitteroauth returns decoded objects, so a tweet's text is $tweet->text and a profile's metrics are $user->data->public_metrics. The same get and post methods reach any v2 endpoint by path, including followers (users/:id/followers) and timelines (users/:id/tweets). It is the right pick when you want the most documented PHP option and may also write. The tradeoffs: it is in maintenance mode rather than actively developed, you still need a paid X developer account, and you pay X's per-resource pricing on every call.
Method 2: plain cURL or Guzzle With a Bearer Token
No library, no wrapper. PHP's built-in cURL extension, or the Guzzle HTTP client, can call the X API v2 directly with a bearer token in the Authorization header. This route suits developers who want full control over requests, or who prefer to avoid a Twitter-specific dependency.
Look up a profile with cURL:
<?php
$ch = curl_init('https://api.x.com/2/users/by/username/elonmusk?user.fields=public_metrics');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . getenv('X_API_BEARER_TOKEN'),
]);
$response = curl_exec($ch);
curl_close($ch);
$user = json_decode($response, true);
printf(
"@%s has %d followers\n",
$user['data']['username'],
$user['data']['public_metrics']['followers_count']
);
The official API paginates search with a next_token in the response meta. Page through every result with a guard so a broad query does not exhaust your quota:
<?php
function searchRecent(string $token, string $query, int $maxPages = 10): array
{
$all = [];
$nextToken = null;
$pages = 0;
do {
$params = [
'query' => $query,
'max_results' => 100,
'tweet.fields' => 'created_at,public_metrics',
];
if ($nextToken) {
$params['next_token'] = $nextToken;
}
$url = 'https://api.x.com/2/tweets/search/recent?' . http_build_query($params);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Authorization: Bearer ' . $token]);
$response = curl_exec($ch);
curl_close($ch);
$body = json_decode($response, true);
$all = array_merge($all, $body['data'] ?? []);
$nextToken = $body['meta']['next_token'] ?? null;
$pages++;
} while ($nextToken && $pages < $maxPages);
return $all;
}
This works when you want minimal dependencies or you are debugging API behavior. The downside is that you own pagination, status-code handling, rate limiting, and retries. For a one-off script that is fine; for a production integration you end up writing a small client. This route still requires a developer account and pay-per-use credits.
Method 3: a Read-Only REST API
If a PHP application only reads public Twitter data, a third-party REST API skips the official API entirely: no OAuth, no application step, no credit-purchase workflow, just one key in a header and JSON that decodes straight into an array.
This is the practical route to getting X data without a developer account. Here is what it looks like with Sorsa, using nothing but cURL.
Get a user profile:
<?php
$ch = curl_init('https://api.sorsa.io/v3/info?username=elonmusk');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['ApiKey: ' . getenv('SORSA_API_KEY')]);
$response = curl_exec($ch);
curl_close($ch);
$user = json_decode($response, true);
echo "@{$user['username']} ({$user['display_name']}): {$user['followers_count']} followers\n";
Search tweets with the full web operator set. The search endpoint returns about 20 tweets per page and a next_cursor for the next page:
<?php
$ch = curl_init('https://api.sorsa.io/v3/search-tweets');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'ApiKey: ' . getenv('SORSA_API_KEY'),
'Content-Type: application/json',
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'query' => 'php lang:en',
'order' => 'latest',
]));
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
foreach ($data['tweets'] as $tweet) {
echo "{$tweet['likes_count']} likes: {$tweet['full_text']}\n";
}
Pull a follower list. One request returns up to 200 profiles, so a 1,000-follower account is five requests instead of ten paginated pages:
<?php
$ch = curl_init('https://api.sorsa.io/v3/followers?username=elonmusk');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['ApiKey: ' . getenv('SORSA_API_KEY')]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
echo 'Got ' . count($data['users']) . " followers in one request\n";
If your project already uses Guzzle, the same calls are shorter. Fetch up to 100 tweets in one request with the bulk endpoint, which counts as a single request and returns complete tweet objects:
<?php
$client = new GuzzleHttp\Client();
$res = $client->post('https://api.sorsa.io/v3/tweet-info-bulk', [
'headers' => ['ApiKey' => getenv('SORSA_API_KEY')],
'json' => ['tweet_links' => ['1782368585664626774', '1782368585664626775']],
]);
$data = json_decode((string) $res->getBody(), true);
For complex queries, combine operators the way you would in advanced search; the full list is in our search operator reference, and the endpoint searches the full tweet archive. Each tweet response carries the author profile and the public metrics, so reading tweet metrics via API and fetching follower lists adds no extra calls. The header is ApiKey, the base URL is https://api.sorsa.io/v3, and the field names match the API documentation exactly. There is also a step-by-step guide to searching tweets via API.
Is There an Official PHP SDK for the X API?
No. As of 2026 X publishes official SDKs only for Python and TypeScript; there is no official PHP SDK. X's own tools-and-libraries page lists those two first-party SDKs plus developer tools, and its open-source SDK generator currently ships templates only for Python and TypeScript.
For PHP, that leaves the options covered above: twitteroauth as the most widely used client (v2 through setApiVersion), v2-native community packages such as twitter-api-v2-php and bird-elephant, plain cURL or Guzzle for full control, or a read-only third-party API for read-heavy work. There is no first-party package to prefer over these, and twitteroauth itself is in maintenance mode, so weigh long-term maintenance when you choose.
If a PHP SDK ever lands, it would likely be generated from the same OpenAPI specification as the Python and TypeScript ones. Until then, treat any tutorial claiming an "official PHP SDK" as inaccurate.
Calling the X API from WordPress
A large share of PHP that touches the X API runs inside WordPress, and you do not need a plugin or an external library. WordPress ships its own HTTP API, so wp_remote_get can call any REST endpoint and pass the auth header directly. For read-only data, that means one function and no OAuth.
<?php
// In a theme's functions.php or a small plugin
$response = wp_remote_get('https://api.sorsa.io/v3/info?username=elonmusk', [
'headers' => ['ApiKey' => getenv('SORSA_API_KEY')],
'timeout' => 15,
]);
if (is_wp_error($response)) {
return;
}
$user = json_decode(wp_remote_retrieve_body($response), true);
echo esc_html("@{$user['username']}: {$user['followers_count']} followers");
The same pattern works against the official API by swapping the URL and using an Authorization header with a bearer token instead of the ApiKey header. Cache the result with the WordPress Transients API (set_transient) so a page load does not hit the API on every view, which both speeds up the page and keeps request volume down. For a read-only widget such as a follower count or a recent-tweets block, this is the whole integration.
Building a Data Collector in PHP
A production collector needs three things beyond a single call: cursor pagination to walk past the first page, a page guard so a broad query does not exhaust your quota, and a retry on rate limits. Here is a complete read-only collector against the search endpoint, paginating with next_cursor and backing off on a 429.
<?php
function collectTweets(string $apiKey, string $query, int $maxPages = 20): array
{
$collected = [];
$cursor = null;
$pages = 0;
while ($pages < $maxPages) {
$payload = ['query' => $query, 'order' => 'latest'];
if ($cursor) {
$payload['next_cursor'] = $cursor;
}
$ch = curl_init('https://api.sorsa.io/v3/search-tweets');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'ApiKey: ' . $apiKey,
'Content-Type: application/json',
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
// Flat 20 requests per second limit: on a 429, wait a second and retry
if ($status === 429) {
sleep(1);
continue;
}
$data = json_decode($response, true);
$collected = array_merge($collected, $data['tweets'] ?? []);
$cursor = $data['next_cursor'] ?? null;
$pages++;
if (!$cursor) {
break;
}
}
return $collected;
}
When we rebuilt our own collectors, a flat per-second limit turned out simpler to pace against than per-endpoint windows: you wait one second on a 429 instead of tracking a reset timestamp per endpoint. The mechanics of cursors are covered in the pagination guide, and the official side is in our X API rate limits reference. If you need parallel reads, Guzzle's pool lets you run several requests at once while you cap concurrency to stay inside the limit. The same loop swaps onto /user-tweets or /followers by changing the endpoint and payload.
Comparison: Three Routes, Side by Side
The three PHP routes split on two axes: whether you can write, and how you are billed. Both official-API routes need a developer account and bill per resource. A read-only API trades write access for a single key and flat per-request billing.
| Route | Setup | Auth | Reads | Writes | Billing |
|---|---|---|---|---|---|
| twitteroauth (community lib) | Developer account, credits | Bearer / OAuth | Yes | Yes | Per resource |
| Plain cURL or Guzzle | Developer account, credits | Bearer / OAuth | Yes | Yes | Per resource |
| Read-only REST API | API key, about 3 minutes | Single ApiKey header | Yes | No (read-only) | Flat per request |
The split tells you which to pick: if you need to post or run write actions, that is the official API's territory through twitteroauth. For read-heavy access at a flat, predictable price, a read-only API is the cheaper and simpler route, and it returns the same public data.
The cost gap on reads comes from the billing unit. The official API charges for every post and every author profile in a response; a flat-rate API charges one request regardless of how many items it returns.
| Workload | Official X API | Read-only API (Sorsa Pro) |
|---|---|---|
| Search returning 20 tweets, with author data | $0.30 (20 x $0.005 plus 20 x $0.010) | One request, about $0.002 (authors included) |
| 1,000 follower profiles | About $10 (per profile) | About $0.01 (5 requests at 200 per page) |
| 100 tweets by ID, with author data | $1.50 (100 x $0.005 plus 100 x $0.010) | One request, about $0.002 (bulk endpoint) |
| Monthly cap | 2 million post reads | Plan based (10,000 to 500,000 requests) |
| Rate limit | 300 to 900 per 15 minutes (varies) | 20 requests per second, flat |
For read-heavy work the per-resource model is the expensive way to do a simple job, which is why a flat per-request rate wins once you cross roughly 10,000 reads a month. Writes are the exception: posting and DMs live only on the official API, so a write-heavy integration belongs there regardless of read cost.
How to Get Your API Credentials
For the official API, create a developer account at developer.x.com, agree to the developer terms, describe your use case, and create a Project and App to generate an API key, an API secret, and a bearer token. Buy credits before your first call, since there is no free tier. For a read-only third-party API, sign up, generate a key, and pass it in a header, with no application or approval step.
Read either credential from the environment, never from source:
# .env or your server environment
X_API_KEY=your-x-api-key
X_API_SECRET=your-x-api-secret
X_API_BEARER_TOKEN=your-x-bearer-token
SORSA_API_KEY=your-sorsa-api-key
In PHP, read them with getenv as shown above, or load a .env file in development with a package like vlucas/phpdotenv. If you are porting existing official-API code, the migration guide maps the official endpoints and field names to their flat-rate equivalents so you can change the transport without rewriting the logic.
In Practice: Cutting the Cost of a PHP Integration
A roughly 12-person agency came to us running a WordPress-based client dashboard that pulled tracked-account data through twitteroauth on the official API. The code worked, but every dashboard refresh paid per post read and per author profile, the OAuth token handling added moving parts, and the 2-million-post-reads monthly cap meant they watched volume as they onboarded clients.
The fix was a transport swap, not a rewrite. They kept the WordPress side and the rendering, pointed the requests at the search and /followers endpoints, and dropped OAuth for a single ApiKey header read through wp_remote_get. Because each request returns up to 20 tweets or 200 follower profiles instead of billing per resource, the same refresh cost a fraction of what it had, roughly 30 to 50 times less on the read-heavy parts, and a per-second limit replaced the monthly cap as the only thing to pace against. They cached responses with transients, so most page loads hit no API at all. For a read-only workload, the per-resource model had been the expensive way to do a simple job.
FAQ
Is there an official X (Twitter) API SDK for PHP?
No. As of 2026 X publishes official SDKs only for Python and TypeScript; there is no official PHP SDK. The most widely used PHP client is twitteroauth, which reaches the v2 endpoints through setApiVersion and generic get and post methods, though it is in maintenance mode. Newer v2-native community packages such as twitter-api-v2-php and bird-elephant also exist, so treat any "official PHP SDK" claim as inaccurate.
What is the best PHP library for the Twitter API?
For most projects, twitteroauth is the practical default: it is the most widely used PHP client, installs through Composer, and supports v2 once you set the API version, although it is in maintenance mode. For v2-native code, twitter-api-v2-php and bird-elephant target the v2 endpoints directly. For read-only data at volume, many PHP teams skip libraries and call a third-party REST API with plain cURL or Guzzle.
How do you get tweets in PHP without a developer account?
Call a read-only third-party REST API. With Sorsa, you sign up, get an API key, pass it in the ApiKey header, and send a cURL or Guzzle request; json_decode turns the response into a plain array. There is no OAuth flow, no app review, and no credit purchase, and each tweet response includes the author profile and public metrics, so a single request returns complete data.
How much does the X API cost for a PHP app in 2026?
On the official X API you pay per resource: $0.005 per post read, $0.010 per user profile, $0.015 per standard post, and $0.20 for a post with a URL, with a 2 million post reads monthly cap. A search returning 20 tweets costs $0.30 once author profiles are included. Sorsa bills per request on flat plans from $49 a month for 10,000 requests, and each request returns up to 20 tweets or 200 follower profiles.
Can you call the X API from WordPress?
Yes, and you do not need a plugin. WordPress ships an HTTP API, so wp_remote_get can call the X API or a third-party API and pass the auth header directly: a bearer token for the official API, or an ApiKey header for a read-only provider. Decode the body with json_decode and cache it with the Transients API so a page load does not hit the API on every view.
How do you handle X API rate limits in PHP?
The official API limits requests per 15-minute window (typically 300 to 900 depending on the endpoint) and returns a 429 when you hit one. With cURL or Guzzle you check the status code and wait before retrying. A flat-rate API like Sorsa uses a per-second limit of 20 requests, so on a 429 you wait one second and retry the same call, and Guzzle's pool lets you cap concurrency for parallel reads.
Does twitteroauth support the X API v2?
Yes. twitteroauth reaches the v2 endpoints once you call setApiVersion with the value 2, then use the generic get and post methods with v2 paths such as tweets/search/recent. An application-only bearer token is enough for reading public data. It does require a paid X developer account, and the library is in maintenance mode, so no new features are planned.
Getting Started
Pick a route and run one of the examples above.
- Read-only data: grab a key from the Sorsa dashboard, set it as
SORSA_API_KEY, and run any Method 3 example. Structured X data lands in your script in under a minute, and the quickstart walks through the first call. Plans and limits are on the pricing page. - Read and write: create a developer account at developer.x.com, buy credits, and run the twitteroauth or cURL examples with your bearer token.
- Comparing providers: for a broader look at read-only options, see the Twitter API alternatives comparison, and for managed scraping tradeoffs, our guide to scraping X.
Reviewed by Keksich, founder of Sorsa, marketer and X API researcher.
How We Verified This Guide
We wrote and verified this guide in June 2026 while operating the API daily. The absence of an official PHP SDK and the existence of the Python and TypeScript SDKs were confirmed against X's tools and libraries documentation. The twitteroauth v2 usage (application-only bearer construction, setApiVersion, and generic get/post against v2 paths) and its maintenance-mode status were checked against its project repository. X API pricing reflects the current pay-per-use model including the April 2026 write-cost changes. Sorsa endpoint behavior, per-request batching, and plan pricing come from the Sorsa API documentation; more about the team is on our About page. Library version numbers move, so they are described rather than pinned; for a current price the in-product docs are the source of truth.