stripe/stripe-php
Official Stripe PHP SDK for accessing the Stripe API. Install via Composer, configure your API key, and use resource classes that map to Stripe objects and endpoints. Supports PHP 7.2+ (older versions being phased out).
## Getting Started
### Minimal Setup
1. **Installation**:
```bash
composer require stripe/stripe-php
Ensure vendor/autoload.php is included in your project.
Initialize Client:
require_once 'vendor/autoload.php';
\Stripe\Stripe::setApiKey('sk_test_...'); // Set API key globally
// OR
$stripe = new \Stripe\StripeClient('sk_test_...'); // Per-request client
First Use Case: Create a customer and charge them:
$customer = \Stripe\Customer::create([
'email' => 'user@example.com',
'name' => 'John Doe',
'payment_method' => 'pm_123', // Pre-created payment method
]);
$charge = \Stripe\Charge::create([
'amount' => 1000, // $10.00
'currency' => 'usd',
'customer' => $customer->id,
]);
Legacy vs. Modern:
Prefer \Stripe\StripeClient (v7.33.0+) over legacy \Stripe\Stripe for new projects.
Example:
$client = new \Stripe\StripeClient('sk_test_...');
$customer = $client->customers->create([...]);
Service Objects:
Use $client->customers, $client->charges, etc., for type-safe interactions.
Workflow:
StripeService class to encapsulate Stripe logic.class StripeService {
private $client;
public function __construct() {
$this->client = new \Stripe\StripeClient(config('stripe.key'));
}
public function createSubscription($userId, $planId) {
$customer = $this->client->customers->create([
'email' => $userId . '@example.com',
]);
return $this->client->subscriptions->create([
'customer' => $customer->id,
'items' => [['price' => $planId]],
]);
}
}
Laravel-Specific:
StripeClient:
// app/Providers/StripeServiceProvider.php
public function register() {
$this->app->singleton(\Stripe\StripeClient::class, function ($app) {
return new \Stripe\StripeClient(config('stripe.key'));
});
}
Workflow:
route:webhook or a dedicated controller.use Stripe\Webhook;
Route::post('/stripe/webhook', function (Request $request) {
$payload = $request->getContent();
$sigHeader = $request->header('Stripe-Signature');
$event = Webhook::constructEvent($payload, $sigHeader, config('stripe.webhook_secret'));
// Handle the event
switch ($event->type) {
case 'payment_intent.succeeded':
$paymentIntent = $event->data->object;
// Fulfill the purchase...
break;
}
return response('OK');
});
Tip:
.env:
STRIPE_WEBHOOK_SECRET=whsec_...
Pattern:
\Stripe\Stripe::setMaxNetworkRetries(3); // Global setting
// OR per-request
$charge = \Stripe\Charge::create([
'amount' => 1000,
'currency' => 'usd',
'customer' => 'cus_123',
'idempotency_key' => 'unique_key_for_this_request',
]);
Mocking Stripe:
stripe-mock for unit tests:
composer require stripe/mock
Example test:
use Stripe\Mock\WebhookTestHelper;
public function testWebhook() {
$payload = file_get_contents(__DIR__ . '/fixtures/payment_intent_succeeded.json');
$sig = 'whsec_...';
$event = Webhook::constructEvent($payload, $sig, config('stripe.webhook_secret'));
$this->assertEquals('payment_intent.succeeded', $event->type);
}
Integration Tests:
HttpTests with a test Stripe account (e.g., sk_test_...).Pattern:
\Stripe\Exception\ApiErrorException for API errors:
try {
$charge = \Stripe\Charge::create([...]);
} catch (\Stripe\Exception\ApiErrorException $e) {
Log::error('Stripe error: ' . $e->getMessage());
return response()->json(['error' => 'Payment failed'], 402);
}
Common Errors:
invalid_request_error: Validate input data.authentication_error: Check API keys/secrets.rate_limit_error: Implement exponential backoff.Gotcha: Hardcoding keys in code violates security best practices.
Fix: Use Laravel's .env and config('stripe.key').
Example .env:
STRIPE_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
Tip: Use Stripe Connect for multi-account setups:
$client = new \Stripe\StripeClient('sk_test_...', [
'stripe_account' => 'acct_123',
]);
Gotcha: Mixing legacy (\Stripe\Stripe) and modern (\Stripe\StripeClient) APIs can cause issues.
Fix: Stick to one pattern per project. Migrate using the official guide.
Tip: Modern API supports dependency injection:
$client = new \Stripe\StripeClient($apiKey, [
'httpClient' => $customHttpClient,
]);
pm_123) require re-attachment.
Fix: Attach before use:
$paymentMethod = \Stripe\PaymentMethod::attach('pm_123', [
'customer' => 'cus_123',
]);
rawRequest for beta/undocumented endpoints (v16+):
$response = $client->rawRequest('post', '/v1/beta_endpoint', [
'data' => '...',
], [
'stripe_version' => '2023-10-16',
]);
Tip: Reuse StripeClient instances (they are thread-safe).
Example in Laravel:
// app/Providers/AppServiceProvider.php
public function boot() {
\Stripe\Stripe::setApiKey(config('stripe.key'));
}
Gotcha: Avoid creating new clients per request in high-traffic apps.
Tip: Enable logging for API requests:
\Stripe\Stripe::setLogger(new \Monolog\Logger('stripe', [
new \Monolog\Handler\StreamHandler(storage_path('logs/stripe.log')),
]));
Common Debug Commands:
$customers = \Stripe\Customer::all(['limit' => 10]);
$customer = \Stripe\Customer::create([...]);
$response = $customer->getLastResponse();
How can I help you explore Laravel packages today?