# SPECIFICATIONS/06_API/06_05_PAYMENTS_ENDPOINTS.md

**PURPOSE:** Specifies the payment recording, modification, and deletion API surface.

>  **Business rules enforced by these endpoints:** `../01_BUSINESS_CONTEXT/03_BUSINESS_RULES.md` → BR-004-*
> **Algorithms:** `../05_ALGORITHMS/03_PAYMENT_ENGINE.md` → Sections 3.2, 3.3, 3.4
> **Narrative generation:** `../05_ALGORITHMS/05_NARRATIVE_GENERATION.md`

---

## POST /api/v1/contracts/{id}/payments

**Permission:** `payments.create`

**Inputs:**

| Field | Type | Required | Validation |
|:---|:---|:---|:---|
| `amount` | decimal | Yes | — |
| `payment_date` | date | Yes | — |
| `notes` | string | No | nullable |

**Outputs (standard payment):**
```json
{
    "success": true,
    "message": "string",
    "data": {
        "payment": {
            "id": 1,
            "amount": "400.00",
            "payment_date": "2026-07-18",
            "type": "installment_payment",
            "notes": "string|null",
            "created_at": "timestamp"
        },
        "updated_installment": {
            "id": 21,
            "installment_number": 1,
            "status": "paid",
            "paid_amount": "400.00",
            "paid_at": "timestamp"
        },
        "contract_status_changed": false
    }
}
```

**Outputs (when contract completes):**
```json
{
    "success": true,
    "message": "string",
    "data": {
        "payment": { "..." : "..." },
        "updated_installment": { "..." : "..." },
        "contract_status_changed": true,
        "new_contract_status": "completed"
    }
}
```

**Behavior:**
1. Verifies contract is `active`
2. Finds next due installment by sequential order
3. Verifies exact amount match — reject any mismatch
4. Creates payment with explicit installment link
5. Creates audit log with self-contained narrative
6. Updates installment to `paid`
7. If no pending or overdue installments remain: sets contract to `completed`

**Errors:**

| Condition | Key | HTTP |
|:---|:---|:---|
| Contract not active | `errors/payment.contract_not_active` | 403 |
| No pending installments | `errors/payment.no_pending_installments` | 409 |
| Amount mismatch | `errors/payment.amount_mismatch` | 422 |

---

## PATCH /api/v1/contracts/{id}/payments/{paymentId}

**Permission:** `payments.update`

**Inputs:**

| Field | Type | Required | Validation |
|:---|:---|:---|:---|
| `payment_date` | date | No | — |
| `notes` | string | No | nullable |

**Outputs:**
```json
{
    "success": true,
    "message": "string",
    "data": {
        "id": 1,
        "amount": "400.00",
        "payment_date": "2026-07-20",
        "type": "installment_payment",
        "notes": "string|null",
        "updated_at": "timestamp"
    }
}
```

**Behavior:**
- LIFO guard: must be the most recent payment
- `amount` field MUST NOT be included — amount modification is prohibited
- Updates only `payment_date` and/or `notes`
- Creates audit log with `old_values` and `new_values`

**Errors:**

| Condition | Key | HTTP |
|:---|:---|:---|
| Not the latest payment | `errors/payment.lifo_violation` | 403 |
| Amount field present | `errors/payment.cannot_modify_amount` | 422 |

---

## DELETE /api/v1/contracts/{id}/payments/{paymentId}

**Permission:** `payments.delete`

**Inputs:** None

**Outputs:**
```json
{
    "success": true,
    "message": "string",
    "data": {
        "restored_installment": {
            "id": 21,
            "installment_number": 1,
            "status": "pending|overdue",
            "paid_amount": 0,
            "paid_at": null
        }
    }
}
```

**Behavior:**
1. Verifies contract is `active` (not `completed`)
2. LIFO guard: must be the most recent payment
3. Creates audit log entry before deletion (capturing the amount in the narrative)
4. Physically removes the payment record
5. Restores linked installment to `pending` or `overdue` (based on whether its due date has passed)

**Errors:**

| Condition | Key | HTTP |
|:---|:---|:---|
| Contract completed | `errors/payment.cannot_modify_completed` | 403 |
| Not the latest payment | `errors/payment.lifo_violation` | 409 |