Skip to main content
Version: Latest

4. Frontend Prerequisite APIs

Every one of these endpoints is [AllowAnonymous] — the signup form calls them before the user has any account or JWT. All are hosted on Shumoul.Api under VersionedApiController's api/v{version:apiVersion}/[controller] convention unless noted otherwise.

4.1 Countries

GET api/v1/Country/GetRegistrationList
  • Input: none.
  • Output: Result<List<CountryViewDto>> where CountryViewDto { Guid Value, string Text, string Code }.
  • Source: RegistrationReferenceServiceSharedDbContext.Countries filtered to IsActive && !Is_Deleted.
  • Purpose: populates the Country dropdown. Value is the CountryId to submit at registration.

4.2 Regions (by country)

GET api/v1/Region/GetRegistrationListByCountryId/{countryId}
  • Input: countryId (route, GUID) — the Value selected from 4.1.
  • Output: Result<List<RegionRegistrationViewDto>> where RegionRegistrationViewDto { Guid Value, string Text, Guid CountryId }.
  • Purpose: populates the Region dropdown, filtered by the already-selected country. Value is the RegionId to submit.

4.3 Cities (by region, or by country)

GET api/v1/City/GetRegistrationListByRegionId/{regionId}
GET api/v1/City/GetRegistrationListByCountryId/{countryId}
  • Input: regionId or countryId (route, GUID).
  • Output: Result<List<SelectListItem>> where SelectListItem { string Value, string Text }note: Value here is a string, unlike Country/Region where Value is a Guid. Frontend code must parse it to a GUID before submitting CityId.
  • Purpose: populates the City dropdown. Prefer GetRegistrationListByRegionId once a region is selected — it is the tighter filter and matches what registration itself validates against (region → city relationship, see Chapter 6).
GET api/Subscription/Packages/pricing
  • Input: none (returns all active packages across all active plans/billing cycles).
  • Output: Result<List<SubscriptionPricingDto>> — each entry nests SubscriptionPackagePricingDetailsDto.Id, which is the exact value to submit as RegisterNewTenantRequest.PlanPackageId. This Id is the SubscriptionPlanPackage join-table row's own Idnot PackageId and not PlanId. Submitting PackageId or PlanId instead will fail package resolution at registration.
  • Purpose: single call that already carries the plan/billing-cycle/package combination (e.g. "باقة البداية" / Starter, Monthly, 99 SAR) needed to pick the right PlanPackageId.

4.5 Subscription plans and package list (alternative, 2-step)

GET api/Subscription/Plans/GetActive
GET api/Subscription/PlanPackages/GetActive?planId={id}

Use only if the UI needs to present Plan (billing cycle) and Package as two separate pickers instead of one combined pricing grid. SubscriptionPlanPackage rows (from either path) carry the same Id that becomes PlanPackageId.

4.6 Billing cycle

There is no separate billing-cycle enumeration endpoint. BillingCycleEnum (Monthly/Quarterly/ Annually) exists in the domain but is dead code — it is not read anywhere in the registration or pricing path. Billing cadence is represented by separate SubscriptionPlan rows (e.g. a "Monthly"/"شهريا" plan and an "Annually"/"سنويا" plan), each producing its own SubscriptionPlanPackage rows and therefore its own PlanPackageId per package. Selecting "Monthly" vs "Annually" in the UI means selecting a different PlanPackageId, not a separate billing-cycle field.

4.7 Language / culture

There is no language/culture enumeration endpoint. RegisterNewTenantRequest.Language is a free-text string ("ar" / "en") that the frontend hardcodes based on its own UI locale, normalized server-side (NormalizeLanguageCode in TenantService). Document any additional supported codes with the frontend team directly if they are needed — the backend does not currently publish a canonical list.

4.8 Public config (captcha / terms / registration toggle)

No dedicated "public signup config" endpoint was found. Whether self-registration is even open is controlled server-side by SubscriptionSettings.Enable_Tenant_Registration — checked inside TenantService.RegisterAsync itself, returned as a registration-time error if disabled, not exposed as a separate pre-flight flag today. There is no captcha or terms-acceptance field on RegisterNewTenantRequest in the current contract (see Chapter 5) — if the production frontend collects a terms checkbox, it is currently a frontend-only concern with no backend field to receive it.

4.9 Sample values used in the verified dev scenario

FieldPrerequisite callResolved value used
CountryGetRegistrationListSaudi Arabia (CountryId resolved from this dev environment's own dataset — see Chapter 6 §6.8 for why the literal Riyadh/Riyadh region/city pair could not be used in this environment)
RegionGetRegistrationListByCountryIdEastern Province (substituted for Riyadh — see Chapter 6 §6.8)
CityGetRegistrationListByRegionIdDammam
Package/PlanPackages/pricingMonthly + باقة البداية (Starter), 99 SAR — PlanPackageId matched exactly between direct SQL inspection and the live pricing API