league/omnipay
Omnipay is a consistent, gateway-agnostic PHP payment processing library. Use one clean API for many providers (Stripe, PayPal, etc.), handle purchases, redirects, and responses uniformly, and switch gateways without rewriting your checkout code.
Installation:
composer require omnipay/common omnipay/stripe # Example with Stripe
Replace stripe with your gateway (e.g., paypal, authorize_net).
First Use Case: Process a credit card payment via Stripe:
use Omnipay\Omnipay;
$gateway = Omnipay::create('Stripe');
$gateway->setApiKey(config('services.stripe.key'));
$response = $gateway->purchase([
'amount' => '10.00',
'currency' => 'USD',
'card' => [
'number' => '4111111111111111',
'expiryMonth' => '12',
'expiryYear' => '2030',
'cvv' => '123'
]
])->send();
if ($response->isSuccessful()) {
// Success: $response->getTransactionReference()
} else {
// Failure: $response->getMessage()
}
Where to Look First:
vendor/omnipay/common/src/Omnipay/Common/ for core classes.vendor/omnipay/stripe/README.md).Gateway Initialization:
$gateway = Omnipay::create('PayPal_Express');
$gateway->setUsername(config('services.paypal.username'));
$gateway->setPassword(config('services.paypal.password'));
$gateway->setSignature(config('services.paypal.signature'));
Store credentials in .env or Laravel config.
Transaction Types:
$response = $gateway->purchase($params)->send();
$response = $gateway->authorize($params)->send();
$response = $gateway->capture($transactionId)->send();
$response = $gateway->refund($transactionId)->send();
Handling Responses:
if ($response->isSuccessful()) {
$transaction = $response->getTransaction();
// Log $transaction->getId(), $transaction->getReference()
} elseif ($response->isRedirect()) {
return $response->redirect(); // For gateways like PayPal
} else {
throw new \Exception($response->getMessage());
}
Webhook Handling (e.g., Stripe events):
use Omnipay\Omnipay;
$gateway = Omnipay::create('Stripe');
$gateway->setApiKey(config('services.stripe.webhook_secret'));
$response = $gateway->completePurchase()->fromArray($_POST);
// Validate signature and process event.
Service Provider: Bind the gateway to Laravel’s container for dependency injection:
$this->app->singleton('omnipay.stripe', function ($app) {
$gateway = Omnipay::create('Stripe');
$gateway->setApiKey(config('services.stripe.key'));
return $gateway;
});
Use in controllers:
use Illuminate\Support\Facades\App;
$gateway = App::make('omnipay.stripe');
Request Validation:
Use Laravel’s FormRequest to validate payment data before processing:
public function rules() {
return [
'card_number' => 'required|digits_between:13,19',
'expiry_month' => 'required|integer|min:1|max:12',
'expiry_year' => 'required|integer|min:' . date('Y'),
'cvv' => 'required|digits:3|digits_between:3,4',
];
}
Logging: Log raw responses for debugging:
\Log::debug('Payment Response', [
'data' => $response->getData(),
'message' => $response->getMessage(),
]);
Testing:
Use the Omnipay\Tests\TestCase base class or mock gateways:
$gateway = $this->getMockGateway('Stripe');
$gateway->setTestMode(true);
Gateway-Specific Quirks:
amount in cents (e.g., 1000 for $10.00).PayerID and Token for Express Checkout; ensure you handle redirects properly.customerEmail or customerId for some transactions.Test Mode: Always test in sandbox mode first:
$gateway->setTestMode(true);
Use test card numbers (e.g., 4111111111111111 for Stripe).
Idempotency: Some gateways (e.g., Stripe) support idempotency keys to avoid duplicate charges:
$gateway->setIdempotencyKey(Str::uuid()->toString());
Currency Codes:
Ensure currency codes match the gateway’s supported list (e.g., USD, EUR). Some gateways reject US or usd.
Redirects:
For gateways like PayPal, always check $response->isRedirect() and handle the redirect URL:
if ($response->isRedirect()) {
return redirect()->to($response->getRedirectUrl());
}
Webhook Verification:
Gateways like Stripe require signature verification for webhooks. Use the gateway’s completePurchase() or similar methods to validate:
$response = $gateway->completePurchase()->fromArray($_POST);
if (!$response->isValid()) {
abort(403, 'Invalid webhook signature');
}
Enable Debug Mode:
$gateway->setDebug(true); // Logs raw requests/responses
Check logs for omnipay or omnipay.* channels.
Inspect Raw Data: Dump the response object:
dd($response->getData(), $response->getMessage());
Gateway-Specific Docs: Cross-reference Omnipay’s docs with the gateway’s official documentation (e.g., Stripe PHP API).
Custom Gateways:
Extend Omnipay\Common\AbstractGateway to create a new gateway:
namespace App\Omnipay;
use Omnipay\Common\AbstractGateway;
use Omnipay\Common\Message\AbstractRequest;
class CustomGateway extends AbstractGateway {
public function getName() {
return 'Custom';
}
public function purchase(array $parameters = []) {
return $this->createRequest('\App\Omnipay\Message\CustomPurchaseRequest', $parameters);
}
}
Message Classes:
Override gateway behavior by extending AbstractRequest:
namespace App\Omnipay\Message;
use Omnipay\Common\Message\AbstractRequest;
use Omnipay\Common\Message\NotificationInterface;
class CustomPurchaseRequest extends AbstractRequest implements NotificationInterface {
public function getData() {
// Custom logic
}
public function sendData($data) {
// Custom API call
}
}
Middleware: Use Laravel middleware to validate requests or transform data before reaching the gateway:
public function handle($request, Closure $next) {
$request->merge([
'amount' => $request->amount * 100, // Convert to cents
]);
return $next($request);
}
Events:
Dispatch Laravel events for payment lifecycle hooks (e.g., payment.processing, payment.success):
event(new PaymentProcessing($gateway, $params));
if ($response->isSuccessful()) {
event(new PaymentSuccess($response->getTransaction()));
}
How can I help you explore Laravel packages today?