# API conventions (read before writing or consuming any contract)

These hold for **every** Balinyaar endpoint. Per-domain contract docs assume them and don't restate them.

## Base & versioning
- Base URL from `NEXT_PUBLIC_API_URL` (client) / `https://localhost:5002` (server default).
- Versioned routes: `api/v{version}/...` (Asp.Versioning). Default `v1`.
- **All URL segments are `snake_case`** (server `SnakeCaseParameterTransformer`). Controllers use
  `[controller]`/`[action]` tokens, so `GetNurseProfile` → `.../get_nurse_profile`.

## Response envelope (`OperationResult` → `ApiResult`)
Every response is the server's standard envelope, not a bare body. Success and failure share the shape;
the frontend's `clientFetch`/`serverFetch` already unwrap it and throw `ApiError` on failure. Document
each endpoint's **payload** (the `data`/result) and its failure cases. The envelope carries at least:
a success flag, an HTTP-aligned status, a user-safe message, and the typed `data` (or validation errors).
The canonical shape is defined by `Baya.Application/Models/ApiResult` + `OperationResult<T>` on the
server — mirror that, don't invent a new envelope.

## Status codes
- `200` success (payload in `data`).
- `400` validation/business-rule failure (field-level errors included).
- `401` unauthenticated (missing/expired token) · `403` unauthorized (lacks permission).
- `404` not found.
- `409` conflict (idempotency / duplicate / state-machine violation) where applicable.
- `5xx` unexpected (generic safe message; details only in server logs).

## Auth
- Bearer JWE in `Authorization: Bearer <token>` (access token, ~15 min). Refresh via the refresh
  endpoint; rotation + reuse-detection apply. The client attaches the header automatically in
  `clientFetch`. State which policy/role each endpoint needs.

## Localisation
- The client sends the active locale (`Accept-Language` / `x-app-locale`, `fa` default). Server-produced
  user-facing messages should honour it. Reference data that has `name_fa`/`name_en` returns both;
  the client picks by locale.

## Pagination (mandatory on lists)
- Query params: `page` (1-based) + `pageSize` (cap it server-side, e.g. ≤100). Response payload carries
  `items` + `total` (+ `page`/`pageSize`). Document the default and max `pageSize` per endpoint.

## Idempotency (money & side-effecting POSTs)
- Where stated, the client sends an idempotency key (header or body field) and the server dedups. Webhook
  endpoints dedup on the provider's `external_event_id`. Document which endpoints require a key.

## Naming
- JSON properties are the server's serialized casing (follow what NSwag/Swagger emits — typically
  `snake_case` to match routing, or the project's configured policy; **derive the exact casing from the
  published `swagger.json`, don't assume**). The frontend types match the wire exactly.

> When in doubt about an envelope/casing detail, the published `openapi/swagger.json` is authoritative.
