Import
use Native\Mobile\Facades\MobileWallet;
Methods
isAvailable()
Check if Apple Pay (iOS) or Google Pay (Android) is available on the device.
use Native\Mobile\Facades\MobileWallet;
$available = MobileWallet::isAvailable();
if ($available) {
// Show payment button
}
True if Apple Pay or Google Pay is available, false otherwise
createPaymentIntent()
Create a Stripe payment intent for the transaction.
Amount in smallest currency unit (cents for USD)
Three-letter ISO currency code (lowercase)
Additional metadata to attach to the payment
use Native\Mobile\Facades\MobileWallet;
$paymentIntent = MobileWallet::createPaymentIntent(
amount: 2999, // $29.99
currency: 'usd',
metadata: [
'order_id' => '12345',
'customer_id' => auth()->id(),
]
);
$clientSecret = $paymentIntent->client_secret;
Payment intent data including client_secret, or null if failed
presentPaymentSheet()
Present the native payment sheet (Apple Pay or Google Pay) for card selection.
The client secret from the payment intent
The merchant name to display on the payment sheet
The Stripe publishable key
The Apple Pay merchant ID (e.g., “merchant.com.yourapp”)
Additional options for the payment sheet
use Native\Mobile\Facades\MobileWallet;
$result = MobileWallet::presentPaymentSheet(
clientSecret: $clientSecret,
merchantDisplayName: 'My Store',
publishableKey: config('services.stripe.key'),
merchantId: config('services.stripe.apple_merchant_id'),
merchantCountryCode: 'US'
);
Result of presenting the payment sheet, or null if failed
Events: Triggers PaymentCompleted, PaymentFailed, or PaymentCancelled events.
confirmPayment()
Confirm the payment with the selected payment method.
The payment intent ID to confirm
use Native\Mobile\Facades\MobileWallet;
$confirmation = MobileWallet::confirmPayment($paymentIntentId);
Confirmation result, or null if failed
getPaymentStatus()
Get the current payment status.
The payment intent ID to check
use Native\Mobile\Facades\MobileWallet;
$status = MobileWallet::getPaymentStatus($paymentIntentId);
Payment status information, or null if unavailable
Events
PaymentCompleted
Dispatched when payment is successfully completed.
use Native\Mobile\Events\Wallet\PaymentCompleted;
use Illuminate\Support\Facades\Event;
Event::listen(PaymentCompleted::class, function (PaymentCompleted $event) {
$paymentIntentId = $event->paymentIntentId;
$amount = $event->amount;
$currency = $event->currency;
$status = $event->status;
$metadata = $event->metadata;
});
Event Properties:
paymentIntentId (string) - The payment intent ID
amount (int) - Payment amount in smallest currency unit
currency (string) - Currency code
status (string) - Payment status
metadata (array|null) - Payment metadata
PaymentFailed
Dispatched when payment fails.
Event Properties:
paymentIntentId (string) - The payment intent ID
errorCode (string) - Error code
errorMessage (string) - Error message
metadata (array|null) - Payment metadata
PaymentCancelled
Dispatched when user cancels the payment.
Event Properties:
paymentIntentId (string) - The payment intent ID
reason (string|null) - Cancellation reason
Examples
Basic Payment Flow
use Native\Mobile\Facades\MobileWallet;
use Native\Mobile\Facades\Dialog;
use Native\Mobile\Events\Wallet\PaymentCompleted;
use Native\Mobile\Events\Wallet\PaymentFailed;
use Livewire\Component;
use Livewire\Attributes\On;
class CheckoutComponent extends Component
{
public $total = 2999; // $29.99
public $orderId;
public function checkout()
{
// Check if wallet payment is available
if (!MobileWallet::isAvailable()) {
Dialog::alert(
'Payment Unavailable',
'Apple Pay or Google Pay is not available on this device.',
['OK']
);
return;
}
// Create payment intent
$paymentIntent = MobileWallet::createPaymentIntent(
amount: $this->total,
currency: 'usd',
metadata: [
'order_id' => $this->orderId,
'user_id' => auth()->id(),
]
);
if (!$paymentIntent) {
Dialog::toast('Failed to initialize payment');
return;
}
// Present payment sheet
MobileWallet::presentPaymentSheet(
clientSecret: $paymentIntent->client_secret,
merchantDisplayName: config('app.name'),
publishableKey: config('services.stripe.key'),
merchantId: config('services.stripe.apple_merchant_id')
);
}
#[On('native:Native\\Mobile\\Events\\Wallet\\PaymentCompleted')]
public function handlePaymentCompleted($data)
{
// Update order status
Order::where('id', $data['metadata']['order_id'])
->update(['status' => 'paid']);
Dialog::toast('Payment successful!');
return redirect()->route('orders.confirmation', $this->orderId);
}
#[On('native:Native\\Mobile\\Events\\Wallet\\PaymentFailed')]
public function handlePaymentFailed($data)
{
Dialog::alert(
'Payment Failed',
$data['errorMessage'],
['OK']
);
}
}
In-App Purchases
use Native\Mobile\Facades\MobileWallet;
class SubscriptionPurchase extends Component
{
public $plan;
public function purchaseSubscription()
{
if (!MobileWallet::isAvailable()) {
$this->showAlternativePayment();
return;
}
$paymentIntent = MobileWallet::createPaymentIntent(
amount: $this->plan->price_cents,
currency: $this->plan->currency,
metadata: [
'type' => 'subscription',
'plan_id' => $this->plan->id,
'user_id' => auth()->id(),
]
);
MobileWallet::presentPaymentSheet(
clientSecret: $paymentIntent->client_secret,
merchantDisplayName: config('app.name'),
publishableKey: config('services.stripe.key'),
merchantId: config('services.stripe.apple_merchant_id')
);
}
#[On('native:Native\\Mobile\\Events\\Wallet\\PaymentCompleted')]
public function activateSubscription($data)
{
if ($data['metadata']['type'] === 'subscription') {
Subscription::create([
'user_id' => $data['metadata']['user_id'],
'plan_id' => $data['metadata']['plan_id'],
'stripe_payment_intent' => $data['paymentIntentId'],
'status' => 'active',
'started_at' => now(),
]);
Dialog::toast('Subscription activated!');
}
}
}
Tip Jar
use Native\Mobile\Facades\MobileWallet;
class TipJar extends Component
{
public $tipAmounts = [100, 300, 500, 1000]; // $1, $3, $5, $10
public function sendTip(int $amount)
{
if (!MobileWallet::isAvailable()) {
Dialog::alert('Payment Unavailable', 'Mobile payments not available', ['OK']);
return;
}
$paymentIntent = MobileWallet::createPaymentIntent(
amount: $amount,
currency: 'usd',
metadata: [
'type' => 'tip',
'creator_id' => $this->creator->id,
'tipper_id' => auth()->id(),
]
);
MobileWallet::presentPaymentSheet(
clientSecret: $paymentIntent->client_secret,
merchantDisplayName: $this->creator->name,
publishableKey: config('services.stripe.key'),
merchantId: config('services.stripe.apple_merchant_id')
);
}
#[On('native:Native\\Mobile\\Events\\Wallet\\PaymentCompleted')]
public function handleTipSent($data)
{
if ($data['metadata']['type'] === 'tip') {
Tip::create([
'creator_id' => $data['metadata']['creator_id'],
'tipper_id' => $data['metadata']['tipper_id'],
'amount' => $data['amount'],
'currency' => $data['currency'],
]);
Dialog::toast('Thank you for your support!');
}
}
}
One-Click Checkout
use Native\Mobile\Facades\MobileWallet;
class QuickCheckout extends Component
{
public $cart;
public function quickPay()
{
$total = $this->cart->total_cents;
$paymentIntent = MobileWallet::createPaymentIntent(
amount: $total,
currency: 'usd',
metadata: [
'cart_id' => $this->cart->id,
'items' => $this->cart->items->pluck('id')->toArray(),
]
);
MobileWallet::presentPaymentSheet(
clientSecret: $paymentIntent->client_secret,
merchantDisplayName: config('app.name'),
publishableKey: config('services.stripe.key'),
merchantId: config('services.stripe.apple_merchant_id'),
options: [
'applePay' => [
'merchantCapabilities' => ['3DS'],
],
]
);
}
}
Event Ticket Purchase
use Native\Mobile\Facades\MobileWallet;
class TicketPurchase extends Component
{
public $event;
public $quantity = 1;
public function purchaseTickets()
{
$total = $this->event->price_cents * $this->quantity;
$paymentIntent = MobileWallet::createPaymentIntent(
amount: $total,
currency: 'usd',
metadata: [
'event_id' => $this->event->id,
'quantity' => $this->quantity,
'user_id' => auth()->id(),
]
);
MobileWallet::presentPaymentSheet(
clientSecret: $paymentIntent->client_secret,
merchantDisplayName: $this->event->name,
publishableKey: config('services.stripe.key'),
merchantId: config('services.stripe.apple_merchant_id')
);
}
#[On('native:Native\\Mobile\\Events\\Wallet\\PaymentCompleted')]
public function issueTickets($data)
{
$eventId = $data['metadata']['event_id'];
$quantity = $data['metadata']['quantity'];
for ($i = 0; $i < $quantity; $i++) {
Ticket::create([
'event_id' => $eventId,
'user_id' => auth()->id(),
'code' => Str::uuid(),
'purchased_at' => now(),
]);
}
Dialog::toast('Tickets purchased!');
}
}
Multi-Currency Support
use Native\Mobile\Facades\MobileWallet;
class MultiCurrencyCheckout extends Component
{
public $amount;
public $currency;
public function detectCurrency()
{
// Detect user's currency based on location
$info = Device::getInfo();
$decoded = json_decode($info);
$this->currency = match($decoded->country ?? 'US') {
'US' => 'usd',
'GB' => 'gbp',
'EU' => 'eur',
'JP' => 'jpy',
default => 'usd',
};
}
public function pay()
{
$paymentIntent = MobileWallet::createPaymentIntent(
amount: $this->convertToSmallestUnit($this->amount, $this->currency),
currency: $this->currency
);
MobileWallet::presentPaymentSheet(
clientSecret: $paymentIntent->client_secret,
merchantDisplayName: config('app.name'),
publishableKey: config('services.stripe.key'),
merchantId: config('services.stripe.apple_merchant_id'),
merchantCountryCode: $this->getCountryCode()
);
}
private function convertToSmallestUnit(float $amount, string $currency): int
{
// JPY doesn't use decimals
if ($currency === 'jpy') {
return (int) $amount;
}
return (int) ($amount * 100);
}
}