# QR Ph

QR Ph is the Philippine national QR code standard. A customer scans a QR Ph code with the app of any participating bank or e-wallet, such as GCash, Maya, or BPI, and pays. Nobody is redirected.

The package covers three uses of it:

| Use | For | Call | Confirmed by |
|:----|:----|:-----|:-------------|
| [At checkout](#take-a-qr-ph-payment-at-checkout) | An online payment for a known amount | `paymentIntents()` with the `qrph` method | `payment.paid` |
| [In store](#print-a-static-code-for-your-store) | A permanent code at a counter; the customer types the amount | `qrph()->generateStatic()` | Your PayMongo dashboard, and an SMS |
| [Wallet QR](#move-money-with-wallet-qr) | Moving money into or out of your PayMongo Wallet | `qrph()->generate()`, `execute()` | Your PayMongo dashboard |

To take payments, use the first two. Wallet QR is not a payment method: it moves money like a bank transfer.

## Take a QR Ph payment at checkout

A QR Ph payment at checkout is a [payment intent](/payment-intents.md) paid with the `qrph` payment method. Attaching the method returns a QR code for the intent's exact amount:

```php
use Luigel\Paymongo\Facades\Paymongo;

$intent = Paymongo::paymentIntents()->create([
    'amount' => 150050, // PHP 1,500.50, in centavos
    'currency' => 'PHP',
    'payment_method_allowed' => ['qrph'],
    'description' => 'Order ORDER-1234',
]);

$method = Paymongo::paymentMethods()->create(['type' => 'qrph']);

$intent = Paymongo::paymentIntents()->attach($intent->id, $method->id);

$image = $intent->attribute('next_action.code.image_url'); // show it in an <img src="...">
```

1. Show the image in `next_action.code.image_url` on your page. It is a base64 image, ready for an `<img>` tag.
2. The customer scans it in their banking or e-wallet app and pays.
3. PayMongo sends `payment.paid`, dispatched as `Luigel\Paymongo\Events\PaymentPaid`.

The code is single-use and expires 30 minutes after you attach it, or after the payment method's `expiry_seconds` (60 to 9000). If it expires unpaid, PayMongo sends `qrph.expired`, dispatched as `QrphExpired`, and the intent is back to `awaiting_payment_method`, so you can attach a new code.

With a [Checkout Session](/checkout-sessions.md), add `qrph` to `payment_method_types` instead, and PayMongo's page shows the code.

## Print a static code for your store

`generateStatic()` creates a permanent code to print and put at a counter. The customer scans it and types in the amount they owe:

```php
use Luigel\Paymongo\Facades\Paymongo;

$code = Paymongo::qrph()->generateStatic([
    'kind' => 'instore',                // the only kind PayMongo accepts
    'mobile_number' => '+639171234567', // gets an SMS for every payment
    'notes' => 'Counter 1',             // for you; customers do not see it
]);

$code->qrImage; // print this and put it on the counter
```

Payments to it show up in your PayMongo dashboard, and PayMongo texts each one to `mobile_number` if you set it. It returns a [`StaticQr`](/data-objects.md#staticqr).

## Move money with Wallet QR

Wallet QR codes move money into or out of your PayMongo Wallet over QR Ph. They run on PayMongo's v3 QR API, which the package calls for you. See PayMongo's [Wallet QR](https://docs.paymongo.com/docs/money-movement-wallet-qr) guide.

### Receive money

`generate()` creates a code anyone can scan to send money to your Wallet. It returns an [`MpmQr`](/data-objects.md#mpmqr):

```php
use Luigel\Paymongo\Enums\QrMode;
use Luigel\Paymongo\Enums\QrType;
use Luigel\Paymongo\Facades\Paymongo;

$qr = Paymongo::qrph()->generate([
    'nation' => 'ph',
    'mode' => QrMode::P2p,
    'type' => QrType::Dynamic,
    'transaction_currency' => 'PHP',
    'transaction_amount' => 50000, // PHP 500.00, in centavos; dynamic QRs only
    'expiry_seconds' => 600,       // 60 to 9000, default 1800; dynamic QRs only
    'qr_image' => true,
    'metadata' => ['top_up_id' => '1234'],
]);

$qr->id;        // "qr_..."
$qr->qrString;  // render this with any QR library...
$qr->qrImage;   // ...or show this base64 PNG, since qr_image was true
$qr->expiresAt; // ?CarbonImmutable
```

- A `dynamic` code carries a fixed `transaction_amount` in centavos, can be paid once, and expires after `expiry_seconds`.
- A `static` code has no amount: whoever scans it types one in. It never expires unless you expire it.
- `mode` takes a `Luigel\Paymongo\Enums\QrMode` case: `P2p`, `P2b`, `P2m`, or `P2micro`. To receive into your Wallet, PayMongo expects `p2p`.

`retrieve()` fetches a code, leaving out the QR string and image unless you ask for them. `expire()` stops a code from being paid:

```php
use Luigel\Paymongo\Facades\Paymongo;

$qr = Paymongo::qrph()->retrieve('qr_2vDcPuS9tsAZzVPFGwGe31eR', qrString: true, qrImage: true);

$qr->status; // ?QrStatus: Active or Expired

$qr = Paymongo::qrph()->expire('qr_2vDcPuS9tsAZzVPFGwGe31eR');
```

### Send money

`execute()` pays a scanned QR Ph code from your Wallet. It returns a [`QrExecution`](/data-objects.md#qrexecution):

```php
use Luigel\Paymongo\Facades\Paymongo;

$execution = Paymongo::qrph()->execute([
    'qr_string' => '00020101021127580012com.p2pqrpay...', // decoded from the scanned code
    'amount' => 50000, // centavos; required even when the QR encodes the amount
    'reference_number' => 'PAYOUT-1234',
]);

$execution->id;     // "qrx_..."
$execution->status; // ?string, an acknowledgement only: the outcome arrives by webhook
```

**This moves real money out of your Wallet.** The response only acknowledges the request, and PayMongo settles the transfer afterwards. PayMongo has no webhook event for it, so check the outcome in your PayMongo dashboard.
