1. Go to this page and download the library: Download a7my/payment-hub library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
a7my / payment-hub example snippets
use Mifatoyeh\LaravelPaymentFramework\Facades\Payment;
// Explicitly pick a provider...
$payment = Payment::driver('stripe'); // -> ->driver('paypal') once available, etc.
// ...or omit driver() entirely and use whatever's configured as the
// default (PAYMENT_DRIVER env var, or payment.default in config/payment.php).
// Payment::charge([...]) works the same way.
$response = $payment->charge([
'amount' => 1000, // $10.00
'currency' => 'USD',
'customer' => [
'name' => 'Mohamed Azmy',
'email' => '[email protected]',
],
// To charge a specific, already-created Stripe payment method,
// pass its PaymentMethod ID under 'token' — NOT 'payment_method'.
// ('payment_method' selects a method *category* — card, wallet,
// bank_transfer, etc. — not a specific Stripe object. Passing a
// Stripe ID like 'pm_...' under 'payment_method' will throw.)
'token' => 'pm_1N...',
'metadata' => ['order_id' => 123],
]);
if ($response->isSuccessful()) {
// $response->getTransactionId(), $response->getStatus(), ...
} elseif ($response->
// Reserve $10.00 without capturing yet (capture_method: manual).
$response = $payment->authorize(['amount' => 1000, 'currency' => 'USD', /* ... */]);
$transactionId = $response->getTransactionId()->toString();
// Later: capture the hold (full or partial amount).
$payment->capture(['transaction_id' => $transactionId, 'amount' => 1000]);
// Or release it without ever charging the customer.
$payment->void(['transaction_id' => $transactionId, 'reason' => 'Order cancelled']);
// Full refund.
$payment->refund(['transaction_id' => $transactionId, 'amount' => 1000]);
// Partial refund — same call shape, smaller amount. The response's
// getStatus() tells you Refunded vs. PartiallyRefunded based on how much
// of the original charge has now been refunded in total.
$payment->partialRefund(['transaction_id' => $transactionId, 'amount' => 300]);
// verify(): "can I trust this transaction to fulfil an order?" — a boolean.
$verification = $payment->verify(['transaction_id' => $transactionId]);
$verification->isVerified(); // bool
// lookup(): the full canonical status, for reconciliation/dashboards.
$status = $payment->lookup(['transaction_id' => $transactionId]);
$status->getStatus(); // PaymentStatus enum
// Step 1 — save a card the customer entered client-side (via Stripe.js/
// Elements), which gives you a `pm_...` PaymentMethod id.
$saved = $payment->saveCard([
'token' => 'pm_1N...', // from Stripe.js on the client
'customer_id' => (string) $user->id, // YOUR OWN customer reference
]);
$stripeCustomerId = $saved->getProviderReference(); // 'cus_...' — SAVE THIS
// e.g. $user->update(['stripe_customer_id' => $stripeCustomerId]);
// Step 2 — charge that saved card later (renewal, off-session purchase, ...).
$response = $payment->chargeToken([
'token' => 'pm_1N...', // the SAME pm_... from step 1
'amount' => 1000,
'currency' => 'USD',
'customer' => ['name' => $user->name, 'email' => $user->email],
'provider_customer_reference' => $user->stripe_customer_id, // from step 1
]);
$response = $payment->createSubscription([
'amount' => 2000,
'currency' => 'USD',
'interval' => 'monthly',
'plan_id' => 'price_1N...', // a Stripe Price ID you created beforehand
'customer' => ['name' => $user->name, 'email' => $user->email],
'provider_customer_reference' => $user->stripe_customer_id, // from saveCard(), same as above
'token' => 'pm_1N...', // optional — omit to bill the customer's stored default card
'trial_days' => 14, // optional
]);
$subscriptionId = $response->getSubscriptionId();
// Cancel immediately:
$payment->cancelSubscription(['subscription_id' => $subscriptionId]);
// Or let it run until the current billing period ends:
$payment->cancelSubscription([
'subscription_id' => $subscriptionId,
'cancel_at_period_end' => true,
]);
$response = Payment::driver('stripe')->createPaymentLink([
'amount' => 10000, // amount in smallest unit (cents) → $100.00
'currency' => 'USD',
'description' => 'Sandbox test payment',
'customer' => [
'name' => 'Mohamed Azmy',
'email' => '[email protected]',
],
'return_url' => url('/payment/success'),
'cancel_url' => url('/payment/cancel'),
'metadata' => [
'order_id' => 123,
],
]);
// Redirect the browser to the hosted Stripe Checkout page
return redirect($response->getPaymentUrl());
use Illuminate\Database\Eloquent\Model;
use Illuminate\Contracts\Auth\Authenticatable;
use Mifatoyeh\LaravelPaymentFramework\Concerns\IsPayable;
use Mifatoyeh\LaravelPaymentFramework\Contracts\Payable;
class Order extends Model implements Payable
{
use IsPayable;
// Tell the trait which columns hold the amount/currency — it reads
// them for you, no accessor methods to write. Both are optional
// (default to 'amount'/'currency' if omitted) and can be typed or
// untyped — either works, e.g. `protected $paymentAmountColumn = '...'`
// is equally fine if you prefer matching Eloquent's own untyped-
// property style ($table, $fillable, etc.).
protected string $paymentAmountColumn = 'total_cents';
protected string $paymentCurrencyColumn = 'currency_code';
// Which drivers THIS model may be paid through — checked even if a
// driver is otherwise configured and enabled application-wide.
public function getSupportedPaymentDrivers(): array
{
return ['stripe', 'paymob'];
}
// Called unconditionally by the endpoint's own controller, regardless
// of route middleware — this is your real security boundary, not
// whatever middleware you do or don't attach to the route.
public function authorizePayment(?Authenticatable $payer): bool
{
return $payer?->id === $this->user_id;
}
}
use Mifatoyeh\LaravelPaymentFramework\Contracts\Payable;
use Mifatoyeh\LaravelPaymentFramework\Concerns\IsPayable;
use Mifatoyeh\LaravelPaymentFramework\Enums\Currency;
use Mifatoyeh\LaravelPaymentFramework\ValueObjects\Money;
class Package extends Model implements Payable
{
use IsPayable;
public function getPaymentAmount(): Money
{
// price is stored in major units (e.g. 40.00 SAR) — convert to halalas
$minor = (int) round((float) $this->price * 100);
return Money::ofMinor(max($minor, 1), Currency::SAR);
}
public function getPaymentCurrency(): Currency
{
return Currency::SAR;
}
public function getSupportedPaymentDrivers(): array
{
return ['stripe', 'paymob', 'myfatoorah'];
}
public function authorizePayment(?Authenticatable $payer): bool
{
return $payer !== null;
}
}
use Mifatoyeh\LaravelPaymentFramework\Contracts\CapturesCheckoutContext;
use Mifatoyeh\LaravelPaymentFramework\Checkout\CheckoutContext;
use Mifatoyeh\LaravelPaymentFramework\Enums\PaymentStatus;
use Mifatoyeh\LaravelPaymentFramework\Responses\StatusResponse;
class Package extends Model implements Payable, CapturesCheckoutContext
{
// ... getPaymentAmount(), etc.
public function captureCheckoutContext(): array
{
return [
'price' => $this->price,
// JSON-serialisable scalars/arrays only — not Eloquent models
];
}
public function onPaymentCompleted(StatusResponse $status, CheckoutContext $context): void
{
if (! $status->isSuccessful() || $status->getStatus() !== PaymentStatus::Captured) {
return;
}
$transactionId = $status->getTransactionId()->toString();
// Idempotent — webhooks and confirm() can both fire
if (Transaction::where('transaction_id', $transactionId)->exists()) {
return;
}
$payer = $context->payer();
if ($payer === null) {
return;
}
Transaction::create([
'transaction_id' => $transactionId,
'user_id' => $payer->getAuthIdentifier(),
'package_id' => $this->id,
'amount' => $context->get('price', $this->price),
'payment_method' => $context->driver,
]);
}
}
// config/payment.php
'payables' => [
'order' => \App\Models\Order::class,
'package' => \App\Models\Package::class,
],
'checkout' => [
'enabled' => env('PAYMENT_CHECKOUT_ENABLED', true),
'route' => env('PAYMENT_CHECKOUT_ROUTE', 'payment/checkout'),
// Default is ['web', 'auth'] — use API auth for SPA/mobile backends:
'middleware' => ['api', 'auth:api'],
],