# Twitter API PHP Client with cURL Canonical: https://www.twitterapis.com/sdk/php Description: A complete PHP client for the TwitterAPIs X data API on the built-in curl extension: typed responses, timeouts, error handling and cursor pagination. Generated: 2026-08-20T19:53:35.783Z ---[Pricing](/pricing)[Docs](https://docs.twitterapis.com)[Blog](/blogs) Compare and Tools [MCP Server](/mcp)[Integrations](/integrations)[Language Clients](/sdk)[Free Tools](/tools)[Twitter ID Finder](/tools/twitter-id-finder)[Twitter API Cost Calculator](/twitter-api-cost-calculator)[Twitter Search API](/twitter-search-api)[Twitter Followers API](/twitter-followers-api)[Twitter Scraper](/twitter-scraper)[Twitter API Use Cases](/twitter-api-usecases)[Twitter API Rate Limits](/twitter-api-rate-limits)[Twitter Unofficial API](/twitter-unofficial-api)[Twitter Free API](/twitter-free-api)[Twitter API Alternatives](/twitter-api-alternatives)[TwitterAPIs vs Tweepy](/twitterapis-vs-tweepy)[TwitterAPIs vs RapidAPI](/twitterapis-vs-rapidapi)[TwitterAPIs vs GetXAPI](/twitterapis-vs-getxapi) Company [About](/about)[Status](/status)[Affiliates](/affiliates)[Trust](/privacy-and-data-handling)[Changelog](/changelog)[Contact](/contact) [Start Free](/signup) 1. [Home](/) 2. /[Language clients](/sdk) 3. /PHP PHP # Twitter API PHP client The PHP client for TwitterAPIs is the built-in curl extension and json\_decode, both shipped with most PHP builds. Authentication is a single static header, so there is no credential machinery to build and no Composer package to add. One method on a small class covers every read endpoint, with a typed array result and an explicit timeout you control. No dependency. curl ships with most PHP builds. twitterapis.php Copy ``` 1 true,9 CURLOPT_HTTPHEADER => ["Authorization: Bearer " . getenv("TWITTERAPIS_KEY")],10 CURLOPT_TIMEOUT => 30,11 ]);12 $body = curl_exec($ch);13 $status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);14 curl_close($ch);15 if ($status !== 200) {16 throw new RuntimeException("twitterapis: status $status");17 }18 return json_decode($body, true);19}2021$profile = twitterapis_get("user/info", ["username" => "naval"]);22echo $profile["user"]["id"], " ", $profile["user"]["followers_count"], PHP_EOL; ``` ## A reusable client class Wrapping the key and a timeout in a class gives you one place to configure both, one place to add retry logic later, and a single get() method every call site shares instead of repeating the curl boilerplate. TwitterApisClient.php Copy ``` 1final class TwitterApisClient2{3 private string $key;4 private int $timeout;56 public function __construct(string $key, int $timeout = 30)7 {8 $this->key = $key;9 $this->timeout = $timeout;10 }1112 public function get(string $path, array $params = []): array13 {14 $url = "https://api.twitterapis.com/twitter/" . $path15 . "?" . http_build_query($params);1617 $ch = curl_init($url);18 curl_setopt_array($ch, [19 CURLOPT_RETURNTRANSFER => true,20 CURLOPT_HTTPHEADER => ["Authorization: Bearer " . $this->key],21 CURLOPT_TIMEOUT => $this->timeout,22 ]);23 $body = curl_exec($ch);24 if ($body === false) {25 $err = curl_error($ch);26 curl_close($ch);27 throw new RuntimeException("twitterapis: transport error: $err");28 }29 $status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);30 curl_close($ch);3132 if ($status !== 200) {33 throw new RuntimeException("twitterapis: status $status: $body");34 }35 return json_decode($body, true, flags: JSON_THROW_ON_ERROR);36 }37} ``` ## Walking a cursor-paginated endpoint A do-while loop reads next\_cursor from each page and feeds it back as the next request's cursor parameter, stopping when it comes back empty. The callback lets the caller abort early, which matters when each page is a separate billed call. followers.php Copy ``` 1/**2 * Walks every page of a cursor-paginated endpoint, calling $fn once per page.3 * Each page is one billed call, so the caller controls the loop by having4 * $fn return false to stop early.5 */6function followers(TwitterApisClient $client, string $username, callable $fn): void7{8 $cursor = null;9 do {10 $params = ["username" => $username];11 if ($cursor !== null) {12 $params["cursor"] = $cursor;13 }14 $page = $client->get("user/followers", $params);15 if ($fn($page) === false) {16 return;17 }18 $cursor = $page["next_cursor"] ?? "";19 } while ($cursor !== "");20} ``` ## Where to go next The same client shape in [Python](/sdk/python) and [Go](/sdk/go), or all six languages on the [language clients](/sdk) page. The [REST API reference](/twitter-rest-api) covers the paging model and the status codes this client branches on, and [the rate limits page](/twitter-api-rate-limits) covers what concurrency you can actually run. ## Frequently Asked Questions Is there a PHP SDK for the Twitter API? There is no Composer package to install here, and the client above shows why one would add little. curl handles the request, json\_decode handles the response, and the only credential work is setting a single header. That is the entire surface a package would wrap, so writing it yourself gives you a client you can read in one file and change without waiting on a maintainer. How should I handle curl errors versus HTTP error statuses? They are two different failure modes and curl reports them differently. curl\_exec returns false on a transport failure (DNS, TLS, connection reset, timeout), which curl\_error explains. A non-200 HTTP status is a successful transport with an application-level rejection, read from curl\_getinfo's CURLINFO\_RESPONSE\_CODE. Check both, in that order, or a transport failure gets misread as a bad response body. Can I make concurrent requests in PHP? Yes, with curl\_multi\_init, which runs several handles on one event loop without needing threads or an async framework. There is one ceiling to design around, 600 requests a minute and 20 concurrent per key, so cap the multi-handle's running count at or under 20 rather than adding every request at once. How do I set a timeout in PHP's curl extension? Set CURLOPT\_TIMEOUT on the handle, in seconds, before calling curl\_exec. It bounds the whole request including DNS and TLS setup. If you need to bound just the connect phase separately, CURLOPT\_CONNECTTIMEOUT does that; most single-region API calls only need the one overall timeout. How do I paginate follower lists in PHP? Read next\_cursor from each response and pass it as the cursor parameter on the next request, stopping when it comes back empty. The helper on this page uses a do-while loop with a callback so the caller can stop early, which matters when each page is a separate billed call and a large account has a lot of them. What does a call cost from PHP? $0.0008 for a standard read, the same everywhere, billed per call rather than per plan. The client makes exactly one request per get(), so your bill is the number of times your code calls it. A pagination loop or an unbounded retry is where a count grows without anybody deciding it should. [Quickstart](/quickstart)[Start Free](/signup?utm_source=aio&utm_medium=organic&utm_campaign=aeo-sdk-php) [ TwitterAPIs](/) The cheapest pay-as-you-go Twitter and X API. $0.0008 per call, which works out to $0.04 per 1,000 tweets on a full 20-tweet page. No subscriptions and no developer account. ## Product / API - [Pricing](/pricing) - [Pay-Per-Use Pricing](/pay-per-use-pricing) - [Cost Calculator](/twitter-api-cost-calculator) - [Rate Limits](/twitter-api-rate-limits) - [MCP Server](/mcp) - [Integrations](/integrations) - [Language Clients](/sdk) - [Changelog](/changelog) - [Status](/status) ## Developers - [Documentation](https://docs.twitterapis.com) - [API Reference](https://docs.twitterapis.com/docs/reference/search/tweet-advanced-search) - [User Info](https://docs.twitterapis.com/docs/reference/user-reads/user-info) - [User Tweets](https://docs.twitterapis.com/docs/reference/user-reads/user-tweets) - [Advanced Search](https://docs.twitterapis.com/docs/reference/search/tweet-advanced-search) - [Verified Followers](https://docs.twitterapis.com/docs/reference/follower-graph/user-verified-followers) ## Resources / Compare - [Answers](/answers) - [Reviews](/reviews) - [Free Tools](/tools) - [Twitter ID Finder](/tools/twitter-id-finder) - [Get a Twitter API Key](/twitter-api-key) - [Official X API Comparison](/twitter-api-pricing) - [Twitter API Use Cases](/twitter-api-usecases) - [Twitter API Alternatives](/twitter-api-alternatives) - [Twitter Unofficial API](/twitter-unofficial-api) - [Twitter Free API](/twitter-free-api) - [TwitterAPIs vs twitterapi.io](/twitterapis-vs-twitterapi-io) - [TwitterAPIs vs GetXAPI](/twitterapis-vs-getxapi) - [TwitterAPIs vs TweetAPI](/twitterapis-vs-tweetapi) - [TwitterAPIs vs TwexAPI](/twitterapis-vs-twexapi) - [TwitterAPIs vs RapidAPI](/twitterapis-vs-rapidapi) ## Legal - [About](/about) - [Security](/security) - [Trust](/privacy-and-data-handling) - [Terms of Service](/terms-of-service) - [Affiliates](/affiliates) - [Contact](/contact) - [Jobs](/jobs) © 2026 TwitterAPIs. All rights reserved. TwitterAPIs is an independent third-party API for developers and researchers. Not affiliated with, endorsed by, or sponsored by X Corp. All systems operational