# Amounts & Money

Every amount the package sends or returns is an integer number of **centavos**, the smallest unit of the peso, exactly as the PayMongo API uses them. `150050` is PHP 1,500.50, and `10000` is PHP 100.00. The package never converts an amount, so a float or a peso value reaches PayMongo exactly as you passed it.

This applies to every `amount` attribute, checkout `line_items[].amount`, refunds, captures, plans, and every amount on a data object, such as `$payment->amount`, `$payment->fee`, and `$payout->netAmount`.

## Convert pesos to centavos

Store prices as integer centavos, in an `unsignedInteger` or `unsignedBigInteger` column, and you never convert. When a price arrives in pesos, multiply by 100 and round before casting:

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

$price = '1500.50'; // pesos, e.g. from a form or a DECIMAL(10, 2) column

$centavos = (int) round((float) $price * 100); // 150050

$intent = Paymongo::paymentIntents()->create([
    'amount' => $centavos,
    'currency' => 'PHP',
    'payment_method_allowed' => ['card'],
]);

$intent->amount;             // 150050: amounts come back in centavos too
$intent->money()?->format(); // "₱1,500.50"
```

Round before casting to `int`. Floats cannot hold most decimal fractions exactly, and a cast alone drops the fraction: `(int) (19.99 * 100)` is `1998`, while `(int) round(19.99 * 100)` is `1999`.

PayMongo sets a minimum and maximum amount for each endpoint and payment method, and throws an `InvalidRequestException` outside them. A payment intent, for example, must be at least `2000` (PHP 20.00). See PayMongo's [Payment Intent and Payment Method errors](https://docs.paymongo.com/docs/payment-acceptance-errors-pipm).

## Show and add amounts with Money

`Luigel\Paymongo\Support\Money` is an immutable amount in centavos. Every data object with an amount has a `money()` method that returns it, or `null` when the amount is missing (a payout's is its net amount), and you can make your own with `Money::ofCentavos()`:

```php
use Luigel\Paymongo\Support\Money;

$subtotal = Money::ofCentavos(150050);
$shipping = Money::ofCentavos(12000);

$total = $subtotal->add($shipping);

$total->centavos();                   // 162050
$total->toDecimal();                  // "1620.50"
$total->format();                     // "₱1,620.50"
(string) $total;                      // "₱1,620.50"
json_encode(['amount' => $total]);    // {"amount":162050}

$total->subtract($shipping)->equals($subtotal); // true
```

| Method | Returns |
|:-------|:--------|
| `Money::ofCentavos(int $centavos)` | A new `Money` |
| `centavos()` | The amount in centavos, `int` |
| `toDecimal()` | The amount in pesos as an exact string, `"1500.50"`, for a `DECIMAL` column or an export |
| `format(string $symbol = '₱')` | A display string, `"₱1,500.50"`. `(string) $money` gives the same |
| `add(Money $other)`, `subtract(Money $other)` | A new `Money` |
| `equals(Money $other)` | Whether both hold the same amount, `bool` |

`Money` does its arithmetic on integers and never on floats. It is always pesos: PHP is the only currency PayMongo's APIs accept. It serializes to JSON as its centavos, so a `Money` in an array or API response comes out as `150050`.
