# partner-center — nursing companies > Client seam `client/src/services/partnerCenter/` · `USE_PARTNER_MOCK = true` (**mock is primary**) · 9 server ops > Last verified: 2026-07-30 against commit `d3ec723` and swagger.v1.json (2026-07-29). Nursing companies («مراکز») that sponsor nurses onto the platform. The domain with the **widest gap between what the client wants and what the server serves** — 6 of its client calls are phantom. ## Endpoints | Method | Path | Verdict | | --- | --- | --- | | GET | `/api/v1/admin/partner-centers` | wired · paginated | | POST | `/api/v1/admin/partner-centers` | wired | | GET | `/api/v1/admin/partner-centers/{id}` | wired | | PATCH | `/api/v1/admin/partner-centers/{id}` | wired | | POST | `/api/v1/admin/partner-centers/{id}/set-active` | wired — REQ-032's delivered half | | POST | `/api/v1/admin/partner-centers/{id}/sponsor-nurse` | wired | | POST | `/api/v1/admin/partner-centers/{id}/verify` | wired | | GET | `/api/v1/centers/{id}/dashboard` | **unwired** — the client wants `centers/me/*` splits instead | | GET | `/api/v1/internal/bookings/{bookingId}/center` | **unwired** — the MoR resolver, server-internal | The seven `admin/partner-centers` routes are `DynamicPermission` + `sensitive`; `centers` is `[Authorize]`; `internal/bookings` is `DynamicPermission`. This domain owns **three of the four route-shape exceptions** in the API: hyphens (`partner-centers`, `set-active`, `sponsor-nurse`), a nested `admin/` segment, and an `internal/` namespace. It also has one of only two `PATCH` verbs. See [index.md](index.md#route-shape-exceptions). ### Phantom — 6 | Client call | REQ | Note | | --- | --- | --- | | `GET /api/v1/centers/me` | REQ-032 | The portal's own-center read | | `GET /api/v1/centers/me/nurses` | REQ-032 | Split read — the server serves one aggregate instead | | `GET /api/v1/centers/me/bookings` | REQ-032 | Split read | | `GET /api/v1/centers/me/bookings/{id}` | REQ-064 | Partner-scoped booking detail | | `GET /api/v1/centers/me/settlement` | REQ-033 | Per-booking commission invoices | | `GET /api/v1/admin/partner-centers/{id}/nurses` | REQ-032 | The admin-side sponsored-nurse list | **The shape mismatch is the point.** The server serves **one aggregate**, `GET centers/{id}/dashboard` → `CenterDashboardDto` with `sponsoredNurses` inline. The portal wants **`/me` plus paginated splits** — it cannot page an inline array, and it does not know its own center id without REQ-038. Until REQ-032 lands, the portal is mock-only. ## Merchant of record The one business rule that changes where money goes: - **`isMerchantOfRecord = true`** → the *center* is the seller. It invoices the customer, holds the commercial relationship, and Balinyaar's cut is a commission **against the center**. - **`isMerchantOfRecord = false`** → the nurse is the seller and the center is a sponsor only. `GET internal/bookings/{bookingId}/center` is the **MoR resolver** the invoice pipeline calls to decide which entity issues the invoice — which is why `InvoiceDto.issuingEntityType` exists. See [payment.md](payment.md). `commissionRate` on the center is a **per-center override** of the platform default, snapshotted at compute time like every other rate. ## Shape rules the JSON does not express - **The settlement IBAN is write-then-masked.** `settlementIbanMasked` is the only form on every read model; the full value never comes back after the write that set it. Same pattern as [nurse.md](nurse.md). - **`verify` is a licence check behind a seam.** `ILicenseVerificationService` checks the eNamad code and the MoH establishment permit; by default it returns `NeedsManualReview`, so `verify` records a **human admin decision**. `Seams:LicenseVerification:AutoApprove` makes the mock return `Valid` to test the auto-approve path. A real eNamad/MoH registry adapter ignores the knob. - **`technicalDirectorNurseUserId` links to a real verified nurse**, not a free-text name — Iranian regulation requires a named technical director («مدیر فنی») with a valid licence. - **`set-active` is suspend/activate, not delete.** A suspended center's sponsored nurses and past bookings stay resolvable. - `sponsoredNurseCount` is denormalised onto both the list item and the detail so the queue needs no per-row count. - `legalEntityType` and `mohEstablishmentPermitNo` are the regulatory identity; `enamadCode` is the e-commerce trust seal. All three are distinct and none substitutes for another. ## Enums | Vocabulary | Values | | --- | --- | | `CenterOnboardingState` | `draft` `pending_verification` `verified` `suspended` | | `MoadianStatus` *(on the center's invoices)* | `pending` `submitted` `registered` `failed` | `MoadianStatus` is shared with [payment.md](payment.md) — it is the سامانه مودیان submission state, and it is the same vocabulary on both sides. > `CenterOnboardingState` is the client's model of the center's position in onboarding. On the wire the > server carries the **facts** it is derived from — `isActive` and `verifiedAt` on both > `PartnerCenterListItemDto` and `PartnerCenterDetailDto` — not the state string itself. Derive, do not > expect a field. ## Open REQs | REQ | Status | Effect | | --- | --- | --- | | REQ-032 | partially delivered | `set-active` landed. The `/me` split reads and the IBAN write-then-masked flow are deferred → 5 phantom routes. **The main reason this seam is mocked** | | REQ-033 | partially delivered | `totalIrr` is on `InvoiceDto`; the per-booking commission invoice list is deferred → 1 phantom | | REQ-064 | open | No partner-scoped booking detail → 1 phantom | | REQ-038 | open | `/me` carries no signal that the caller administers a center, so the portal cannot auto-route or discover its own center id. See [auth.md](auth.md) |