serendipity_hq/stripe-bundle
Symfony bundle that simplifies integrating Stripe payments into PHP applications. It wires up Stripe's SDK as a service, exposes configuration options, and helps reduce boilerplate for payment processing, subscriptions, and webhook handling.
This package is a Symfony bundle, not a Laravel package. There is no service provider, no config/stripe.php publish tag, and no facade. If you are working in Laravel, the realistic first step is to confirm whether you actually need it at all — you almost certainly do not. The underlying value is a thin DI wiring around the official stripe/stripe-php SDK; in Laravel you would get the same result by requiring stripe/stripe-php directly and binding a configured StripeClient in a service provider.
If you are in a Symfony app (or maintaining one that already pulls this in), the minimal path is:
composer require serendipity_hq/stripe-bundleconfig/bundles.phpserendipity_hq_stripe or similarly namespaced key — verify against DependencyInjection/Configuration.php)$stripe->customers->create([...]))Where to look first, in order:
README.md — likely thin, but check for the config key name and the service IDDependencyInjection/Configuration.php — the authoritative list of config options (keys, API version, etc.)Resources/config/services.* — the actual service IDs and constructor arguments you will injectcomposer.json — pinned Symfony and stripe/stripe-php version rangesFirst use case worth validating: create a customer and a PaymentIntent on test keys, then confirm the bundle's configured API version matches what your account/dashboard expects. Treat that as a smoke test before building anything else.
Treat it as a configured Stripe client, nothing more. The bundle’s job is to hold your keys and hand you an SDK instance. Do not let bundle-specific types leak into your domain code. Wrap it:
final class StripeGateway
{
public function __construct(private \Stripe\StripeClient $client) {}
public function charge(int $amountCents, string $currency, string $customerId): \Stripe\PaymentIntent
{
return $this->client->paymentIntents->create([
'amount' => $amountCents,
'currency' => $currency,
'customer' => $customerId,
'automatic_payment_methods' => ['enabled' => true],
]);
}
}
Bind your gateway interface in your own service config and inject that everywhere. This gives you a single seam to swap in stripe/stripe-php directly when you drop the bundle — which, given it is archived, you should plan for.
Config-driven keys per environment. Keep test and live keys in environment variables, not in committed YAML. Symfony’s %env(STRIPE_SECRET_KEY)% resolves cleanly into the bundle config. Never read the key back out of the container in application code; let the bundle hold it.
Webhook handling belongs outside the bundle. The bundle will not verify signatures for you. Implement a dedicated controller/route that reads the raw body, calls \Stripe\Webhook::constructEvent($payload, $sigHeader, $secret), and dispatches to your own handlers. Keep the webhook secret as a separate env var from the API key.
Idempotency and persistence. Every mutating call should carry an Idempotency-Key derived from your own order/attempt record. Store the Stripe object ID (pi_..., cus_...) alongside your local row in the same transaction boundary where possible, and reconcile via webhook rather than trusting the synchronous response alone.
Testing. Point the bundle at test keys and use Stripe test card numbers. For unit tests, do not boot the bundle — mock your StripeGateway interface. For integration tests, hit the Stripe test API in a dedicated CI job, or use a recorded-HTTP approach against the SDK’s Guzzle client if the bundle exposes it.
If you are actually on Laravel: skip this package. Require stripe/stripe-php, register a singleton in AppServiceProvider:
$this->app->singleton(\Stripe\StripeClient::class, fn () => new \Stripe\StripeClient(
config('services.stripe.secret')
));
You lose nothing except a layer of indirection you did not want, and you gain a supported dependency.
stripe/stripe-php majors. Check the composer.json constraints; a stripe/stripe-php major bump will likely break installs. Pin both and budget for removal.Configuration.php and the service definitions say, not what a blog post says. Read those files rather than guessing.stripe/stripe-php release, not by your Stripe dashboard. If the bundle lets you set an API version, set it explicitly; otherwise expect occasional shape changes on upgrade.debug:container) can expose constructor arguments. Ensure the secret key comes from env and that you are not logging the client object or its config in dev.debug:container --show-private to confirm the service ID, and Symfony’s HTTP client profiler if the SDK’s Guzzle client is wired through it. If requests fail silently, check that the configured key is not an empty string from a missing env var — the bundle will happily construct a client with null.stripe/stripe-php directly, replace the injected bundle service with your own configured StripeClient, and delete the bundle registration. Do that migration before you build significant surface area on top of it.How can I help you explore Laravel packages today?