# @prood/payment-easypay (https://prood.com/docs/packages/payments/easypay)

`@prood/payment-easypay` implements the `PaymentProvider` interface for [Easypay](https://www.easypay.pt/) — a Portuguese payment provider supporting Multibanco references, MB WAY, and credit card.

## Installation [#installation]

Workspace package. Available from the source repo for now.

## Usage [#usage]

```ts
import { EasypayPaymentProvider } from '@prood/payment-easypay'

const provider = new EasypayPaymentProvider({
  accountId: config.accountId,
  apiKey: config.apiKey,
  baseUrl: config.baseUrl,
})
```

## Configuration [#configuration]

| Field | Description |
| --- | --- |
| `accountId` | Easypay account ID |
| `apiKey` | API key |
| `baseUrl` | API base URL. Optional, defaults to live |

Each store enters these under Integrations in the dashboard. There is no environment fallback.

### Environments [#environments]

| Environment | Base URL |
| --- | --- |
| Production | `https://api.prod.easypay.pt` |
| Sandbox | `https://api.test.easypay.pt` |

## Payment methods [#payment-methods]

| Method | Flow | UI |
| --- | --- | --- |
| **Multibanco** | Reference-based | Entity + reference displayed; customer pays at ATM/homebanking |
| **MB WAY** | Push notification | Phone number input; customer confirms on phone |
| **Credit card** | Redirect | Redirect to Easypay hosted payment page |

## Selecting a method [#selecting-a-method]

Pass `method` on `createSession()` (defaults to `multibanco`):

| `method` | Flow |
| --- | --- |
| `multibanco` | Multibanco reference (entity + reference, 3-day deadline) |
| `mbway` | MB WAY push notification; needs a Portuguese mobile number |
| `card` | Redirect to Easypay hosted card page |

```ts
const session = await provider.createSession({
  amount: 29.99,
  currency: 'EUR',
  orderId: 'ord_456',
  method: 'multibanco',
})
```

Easypay confirms payments asynchronously via notifications. Use `confirmSession()` after redirect, but treat webhooks as the authoritative completion signal for reference payments.

## Refunds [#refunds]

`refund()` posts to `/2.0/refund/{captureId}`, using the capture of the payment, with a 20 second deadline. MB WAY and card payments can be refunded this way. Multibanco can't: Easypay needs the shopper's IBAN, so those orders use the manual refund path.

Two guards keep a retry from paying twice:

- The `Idempotency-Key` header. Easypay documents it for every POST, not on the refund operation itself, and forgets keys after 24 hours.
- The capture's status. A capture already marked `refunded` sends nothing.

`transaction_key` is only Easypay's internal reference for the refund. It doesn't deduplicate anything.

Easypay's refund notification carries the refund's id, not the payment's, so `verifyWebhook` reads `/2.0/refund/{id}` to find the payment and its order. Only a refund with status `success` changes the order: a value below the capture is `payment.partially_refunded`, anything else `payment.refunded`.

## Factory usage [#factory-usage]

```ts
import { getTenantPaymentProvider } from '@prood/commerce'

const { provider } = await getTenantPaymentProvider(orgId, 'easypay')
```

## Payment flow [#payment-flow]

```mermaid
flowchart TD
  A[createSession] --> B{method?}
  B -->|mb / mbw| C[Reference or MB WAY UI]
  B -->|cc| D[Redirect to Easypay]
  C --> E[Customer pays async]
  D --> F[confirmSession on return]
  E --> G[Webhook notifies API]
  F --> G
  G --> H[Order confirmed]
```

## Webhook setup [#webhook-setup]

Configure in Easypay merchant panel:

```
URL: https://prood.com/pay/api/webhooks/easypay/{orgId}
```

## Related pages [#related-pages]

<Cards>
  <Card title="Payment integration" href="/docs/guides/payment-integration" description="Setup guide." />
  <Card title="Checkout payments" href="/docs/apps/checkout/payments" description="Reference payment UI." />
</Cards>
