# Tank Track — Gas Station Wallet Pay (Frontend Guide)

Pay a **registered** gas station from the driver’s wallet. Money moves on the platform ledger (driver debit → station owner credit). Digital receipts go to both parties (in-app + email).

Full backend contract: [`gas-station-payment-README.md`](./gas-station-payment-README.md)

## Auth

```http
Authorization: Bearer <jwt>
Content-Type: application/json
Idempotency-Key: <uuid>   # required on pay (also accepted as body.idempotencyKey)
```

---

## Station ID (important)

Use the MongoDB id from listing APIs:

| API | Field |
|-----|--------|
| `GET /api/v1/gas-stations` | `id` / `_id` |
| `GET /api/v1/gas-stations/nearest?source=registered` | `id` |
| `GET /api/v1/gas-stations/along-route?...` | `_id` |

**Do not** use Google `place_id` for pay.

---

## 1. Pay

```http
POST /api/v1/gas-stations/:gasStationId/pay
```

```json
{
  "amount": 10.0,
  "note": "Pump 3",
  "tripId": "optional",
  "idempotencyKey": "239e9196-7d18-49f1-801a-a8d38a139da2"
}
```

Prefer header: `Idempotency-Key: <uuid>`.

### Success (only when really paid)

```json
{
  "status": 200,
  "success": true,
  "message": "Payment completed successfully",
  "data": {
    "_id": "...",
    "receiptNumber": "TT-20260722-AB12CD",
    "amount": 10,
    "amountCents": 1000,
    "status": "completed",
    "paidAt": "...",
    "gasStation": { "_id": "...", "name": "...", "address": "..." },
    "walletBalance": 50,
    "walletBalanceCents": 5000
  }
}
```

**Frontend rule:** treat as success only if `success == true` **and** `data.status == "completed"`. Do not trust the message string alone.

### Errors

| HTTP | Message | FE action |
|------|---------|-----------|
| 400 | Please top up your wallet first | Open top-up; after top-up use a **new** Idempotency-Key |
| 400 | You cannot pay your own gas station | Show error |
| 400 | Gas station is not available for payments | Show error |
| 400 | Idempotency-Key header is required | Send UUID |
| 400 | This payment already failed. Use a new Idempotency-Key… | New UUID + retry |
| 404 | Gas station / trip not found | Show error |
| 500 | Payment could not be completed… | Retry with **same** key (resume) |

---

## 2. Idempotency (must follow)

| Situation | Key |
|-----------|-----|
| User taps Pay (new attempt) | **New** UUID |
| Timeout / network retry of same attempt | **Same** UUID |
| After insufficient funds + top-up | **New** UUID |
| After a failed/refunded payment | **New** UUID |

- Same key + already `completed` → same payment (no double charge)
- Same key + interrupted `pending` → backend **resumes** and completes
- Same key + `failed` (e.g. insufficient funds) → **400 again** (not a fake success)

---

## 3. UX checklist

1. Load wallet: `GET /api/v1/wallet` → show `balance` / `balanceCents`
2. If `amount > balance` → disable Pay / warn (API will still return 400)
3. On Pay → generate UUID → call pay API
4. On success → show receipt (`receiptNumber`, amount, station)
5. Optional detail: `GET /api/v1/payments/:paymentId`

---

## 4. Other APIs

```http
GET /api/v1/payments?page=1&limit=20          # payments I made
GET /api/v1/payments/:paymentId              # receipt detail (payer or station owner)
GET /api/v1/gas-stations/my-payments         # payments my station received
```

---

## Dart sketch

```dart
Future<void> payStation({
  required String stationId,
  required double amount,
  required String idempotencyKey,
  String? note,
}) async {
  final res = await api.post(
    '/gas-stations/$stationId/pay',
    headers: {'Idempotency-Key': idempotencyKey},
    body: {'amount': amount, 'note': note},
  );

  if (res.statusCode == 400 &&
      (res.message ?? '').toLowerCase().contains('top up')) {
    // navigate to wallet top-up; next pay = new UUID
    return;
  }

  final data = res.data;
  if (res.success == true && data['status'] == 'completed') {
    // show receiptNumber, amount, gasStation
  }
}
```

---

## Out of scope (v1)

- Instant Stripe bank transfer on pay (owner withdraws later via Connect)
- PDF receipt file
