Library / SDK
stripe/stripe-php avatar
stripe/stripe-php

stripe-php: the curl client is a static, so the timeout is process wide

PHP library for the Stripe API.

4,031 stars900 forksPHPMIT

At a glance

What is it?
Stripe's PHP bindings, whose resource classes initialise themselves from API responses so the library tolerates a wide range of API versions, whose HTTP client and logger are both installed through static setters, and whose Makefile announces its own deletion while the replacement justfile imports a file from outside the repository.
Who is it for?
Use it if you are on PHP 7.4 or later and want the service object pattern, and read the timeout section before you tune anything, because the request timeout is a static on the API requestor rather than a property of a client object, so a process that serves more than one integration configures it once for all of them.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly PHP, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • stripe/stripe-php4,031 ★ · +13
Star history
Repository2026-09-242026-11-14
stripe/stripe-php4k4k

13 Stars in the last 51 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

Three tags in eleven minutes, with the alpha after the beta

The release list is worth reading as a sequence rather than as three separate items. v22.0.0 was published at 00:43:15 on 2026-10-01, v22.1.0-beta.1 at 00:50:09 the same morning, and v22.1.0-alpha.1 at 00:54:40, which is after the beta. The last push to the master branch is 2026-10-02.

So a major version went out in the morning, followed within twelve minutes by two pre-releases of the next minor, and the pre-release tagged alpha was created last. If you pin a pre-release, the order of those two tags is not the order a version comparison would suggest, and the naming, beta then alpha, is inverted relative to the usual convention.

That is the packaging side of the library. The versioning itself is handled in the repository by two files rather than by the tag: a `VERSION` file at the top level, and a version constant inside `lib/Stripe.php`. The build tooling rewrites both, writing the version into the file and running a substitution against the constant, so a release is two edits in step rather than one.

The resource classes take their shape from the response

The compatibility claim in the introduction is mechanical, not aspirational. The library ships a pre-defined set of classes for API resources, and those classes initialise themselves dynamically from the API responses they receive, which is what makes the bindings compatible with a wide range of versions of the Stripe API.

That design has two consequences. A property the installed version of the library does not know about still arrives, because the object is populated from the response rather than from a fixed local shape. And the typed surface can lag the API, since what a method guarantees is what the local class knows, not what the API can send.

The current way to call the API is a service object, `new \Stripe\StripeClient('sk_test_...')` followed by `$stripe->customers->create([...])`, with the created object printable directly. That pattern replaced the older global style in version 7.33.0, dated 2020-05-14 in the changelog, and the README keeps the legacy patterns supported with a migration guide describing the changes as backwards compatible. Six years later both styles are still documented.

Timeouts live on a static requestor, not on the client

Changing a request timeout means building your own HTTP client and installing it globally:

php
// set up your tweaked Curl client
$curl = new \Stripe\HttpClient\CurlClient();
$curl->setTimeout(10); // default is \Stripe\HttpClient\CurlClient::DEFAULT_TIMEOUT
$curl->setConnectTimeout(5); // default is \Stripe\HttpClient\CurlClient::DEFAULT_CONNECT_TIMEOUT

echo $curl->getTimeout(); // 10
echo $curl->getConnectTimeout(); // 5

// tell Stripe to use the tweaked client
\Stripe\ApiRequestor::setHttpClient($curl);

The defaults are named constants on the client class, so they are readable without reading the source. What matters more is the installation step: `ApiRequestor::setHttpClient` is a static call, so the HTTP client is a property of the process rather than of the `StripeClient` object. There is no per-client transport configuration.

The logger is set the same way, with `\Stripe\Stripe::setLogger($logger)` taking any PSR-3 compatible logger so messages land there instead of in `error_log`, and the library is described as doing minimal logging by default. Two global switches, transport and logging, both installed with static calls, is the shape to keep in mind for anything long running.

Do not shorten the timeout on a call that moves money

The timeout section opens with a warning that is more useful than the recipe that follows. Decreasing the timeout for non-read-only calls, charge creation being the example given, is not recommended, because even if you time out locally the request on Stripe's side can still complete. The client gives up; the server does not.

That leaves you with a charge that may or may not exist and an application that thinks it failed. The mitigation the README names is idempotency tokens, so that a retry after a timeout does not execute the same transaction twice. In other words the timeout is not a cancellation mechanism, and treating it as one is how a timeout retry logic turns into a duplicate.

Read together with the previous section, the practical rule is that timeouts are set process wide and are safe to shorten only on calls that do not change state, and everything else needs an idempotency key before you touch the number.

Proxy options are defaults the client then overrides

For a proxy, the array of `CURLOPT_*` values goes into the CurlClient constructor, using the same syntax as `curl_setopt_array()`; the README spells that function name slightly wrong in the text, which is worth knowing if you go looking for it in your own code. What you get is a set of defaults applied to every HTTP request the SDK makes.

Those defaults have a documented precedence problem. Many more common options, timeouts among them, are overridden by the client even if you set them in the array, which is why the timeout section insists you set timeouts on the client object rather than in the option array. The two mechanisms are not layered in the order you would guess.

There is a second form for per-request values: a callable can be passed to the constructor, and it returns that array based on the request inputs. The README points at `testDefaultOptions()` in `tests/CurlClientTest.php` as the worked example, and notes that the callable runs at the beginning of every API request, before the request is sent, so it is on the hot path for every call rather than a one-time setup.

The SDK prints notices harder when it thinks it is inside an agent

Stripe sends notices to the client in a response header called `Stripe-Notice`, and the SDK prints them. When it runs in what the README calls an agent environment, it always prints them. For calls against test accounts or sandboxes, it also prints them when it runs outside such an environment.

The suppression switch is an environment variable, `STRIPE_SUPPRESS_NOTICES`, set to `true` before the integration runs, and its scope is explicit: it suppresses notices when the SDK runs outside an agent environment. In the agent case the printing is unconditional and the variable does not apply. So the same build behaves differently depending on how it was launched, which is a detail to know before you conclude that a notice went missing.

For correlating a call with Stripe's side, the supported route is the response object. Any object returned by the API exposes the last response through `getLastResponse()`, and the headers on it include the request id, which is the identifier to quote when opening a support ticket.

A Makefile that announces its own deletion

The first line of the repository's Makefile says the file is deprecated and slated for deletion, and points at the equivalent just commands. The replacement is the justfile, and it has two details worth reading before you run anything in a fresh clone.

It begins with an optional import of `../sdk-codegen/utils.just`, a file that lives in a sibling directory rather than in this repository, so the import resolves only inside Stripe's own checkout layout and is skipped elsewhere. And the test recipe states its own prerequisite in a comment: the full unit test suite needs stripe-mock running. The continuous integration recipe goes further and carries an interactive confirmation, because it modifies local files.

The rest of the tooling is duplicated between the two files, which is the cost of the transition. Both have a phpstan analysis over `lib` and `tests` with a raised memory limit, both have a php-cs-fixer format target, and the justfile adds a strict level 9 analysis of a single example file. There is a baseline file for phpstan, two phpunit configurations, one of them named for running without autoloading, and a phpdoc recipe marked private with a comment asking whether it still works. Separately, `CODEGEN_VERSION` and `OPENAPI_VERSION` sit at the top level as markers for generated code, and `update_certs.php` is a script of its own.

Editorial conclusion

Use it if you are on PHP 7.4 or later and want the service object pattern, and read the timeout section before you tune anything, because the request timeout is a static on the API requestor rather than a property of a client object, so a process that serves more than one integration configures it once for all of them. The compatibility story is the library's real strength: the resource classes take their shape from the API response, which is why the same code keeps working across API versions, and why the legacy global pattern from before 7.33.0 remains supported rather than removed. In the repository itself, expect to use the just commands and to have stripe-mock available before the test suite will run.

Frequently asked questions

How do I install the stripe php sdk?

With Composer: run composer require stripe/stripe-php, then require Composer's autoload file with require_once 'vendor/autoload.php'. If you would rather not use Composer, download the latest release and include the init.php file with require_once '/path/to/stripe-php/init.php'. Either way you need PHP 7.4.0 or later, and the curl, json and mbstring extensions, which Composer handles automatically and a manual install has to provide.

Which PHP versions does stripe-php support, and what about old ones?

PHP 7.4.0 and later, with a note that additional PHP versions will be dropped in future major versions under Stripe's language version support policy. For older environments the README points at archived releases: PHP 5.4 and 5.5 users can use v6.43.1, which will work but might not support features added since, and PHP 5.3 users can use v5.9.2, which the README says will continue to work with new API versions for common uses.

How do I set a request timeout in stripe-php?

Construct a CurlClient, call setTimeout and setConnectTimeout on it, and install it with the static call \Stripe\ApiRequestor::setHttpClient($curl). The defaults are the CurlClient DEFAULT_TIMEOUT and DEFAULT_CONNECT_TIMEOUT constants. Because the setter is static, the transport is configured for the whole process. The README also warns against lowering timeouts on non-read-only calls such as charge creation, since the request can still complete server side, and points at idempotency tokens for retries.

How do I configure a proxy in stripe-php?

Pass the array of CURLOPT_* values to the CurlClient constructor, using the same syntax as curl_setopt_array. Those become defaults for every request the SDK makes, but common options including the timeouts are overridden by the client even when set in the array, which is why timeouts are configured on the client object instead. A callable can be passed instead of a fixed array to compute the options per request, and it is invoked at the start of every API request.

How do I log from stripe-php, and how do I stop the notices?

Logging is minimal by default and goes to error_log; pass any PSR-3 compatible logger to \Stripe\Stripe::setLogger($logger) to redirect it. Notices come from Stripe in the Stripe-Notice response header. They are always printed when the SDK runs in an agent environment, and for test accounts or sandboxes they are also printed outside one, where setting the STRIPE_SUPPRESS_NOTICES environment variable to true before the integration runs suppresses them.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. stripe/stripe-php on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/stripe-stripe-php.svg)](https://hysenlabs.com/projects/stripe-stripe-php)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/stripe-stripe-php.svg)](https://hysenlabs.com/projects/stripe-stripe-php)

Was this useful?