Skip to main content
Version: Latest

5. Controllers & Endpoints

All three controllers live in Shumoul.Framework.EInvoicing.Api (the variant consumed by Shumoul.Saas.Api), inherit VersionNeutralApiController ([ApiController], [ApiVersionNeutral]), and are mounted into the host process via the IncludeApi() MVC Application Part mechanism — no controller code exists inside Shumoul.Api itself. [ApiVersionNeutral] also means these routes live outside the platform's api/v{version}/... scheme entirely, at bare /api/EInvoicing/....

Convention deviation: none of these 12 endpoints use the platform's [MustHavePermission] attribute — the only authorization present is class-level [Authorize] (authentication only, no permission gate). This is a deviation from every other Shumoul controller convention.

5.1 EInvoicingController — [Authorize], api/EInvoicing

MethodRouteAuthRequestResponseDelegates to
POSTapi/EInvoicing/Generate[Authorize] onlyUblInvoiceDtoResult<SubmittedInvoiceResult> (200) / InvalidModelResult<List<ValidationRule>> (400) / ErrorResult (500)IInvoiceProcessFlowService.GenerateAndSubmit(invoice)
GETapi/EInvoicing/download-file?fileName=[Authorize] onlyquery fileNameraw byte[] (application/xml) or 400Reads ./Files/Invoices/Signed/{fileName}.xml

The download-file endpoint's fileName handling was hardened in Phase 0.2 — see Chapter 7 — Security § Path Traversal.

5.2 EInvoicingSettingsController — [Authorize], api/EInvoicing/Settings

MethodRouteAuthRequestResponseDelegates to
GET.../VatRegistration[Authorize] onlynoneResult<VatRegistrationSettings>GetAppSetting<VatRegistrationSettings>()
POST.../VatRegistration[Authorize] onlyVatRegistrationSettingsResultValidated, then SetAppSetting<T>
GET.../Integration[Authorize] onlynoneResult<IntegrationSettings> (OTP field redacted, Phase 0.2)GetAppSetting<IntegrationSettings>()
POST.../Integration[Authorize] onlyIntegrationSettingsResultSetAppSetting<IntegrationSettings>() — no validator call, unlike the other setters
GET.../ConfigrationMode (sic)[Authorize] onlynoneResult<ConfigModeSettings>GetAppSetting<ConfigModeSettings>()
POST.../ConfigrationMode (sic)[Authorize] onlyConfigModeSettingsResultIMediator.Publish(new SwitchToProductionModeEvent(request))
GET.../Address-Details[Authorize] onlynoneResult<AddressDetailsSettings>GetAppSetting<AddressDetailsSettings>()
POST.../Address-Details[Authorize] onlyAddressDetailsSettingsResultValidated, then SetAppSetting<T>
GET.../Additional-Info[Authorize] onlynoneResult<AdditionalInfoSettings>GetAppSetting<AdditionalInfoSettings>()
POST.../Additional-Info[Authorize] onlyAdditionalInfoSettingsResultValidated, then SetAppSetting<T>

ConfigrationMode (missing the "u" in "Configuration") is the actual, live route string — not a documentation typo. See Chapter 11 — Technical Debt.

The six secret-bearing/state-bearing settings classes (ComplianceChecksSettings, ComplianceCsidSettings, ConfigModeSettings (read-write above but not validated), FatooraSecretSettings, ProductionCsidSettings, X509CertifcateSettings) have no controller endpoint at all — read/written only internally by SDK services.

5.3 EInvoicingOnboardingController — [Authorize], api/EInvoicing/Onboarding

MethodRouteAuthRequestResponseDelegates to
POSTapi/EInvoicing/Onboarding[Authorize] onlyHeaders: type (OnboardingRequestType), Otp (string) — no body DTOResult (200) / ErrorResult (406)IOnboardingProcessFlowService.Initialize(type, Otp)

See Chapter 9 — Onboarding for the full onboarding sequence this endpoint drives.

5.4 Mounting Mechanism (Recap)

Startup.cs in .Api: AddEInvoicingControllers() calls services.AddMvc().AddApplicationPart(Assembly.Load(new AssemblyName("Shumoul.Framework.EInvoicing.Api"))), invoked from the .IncludeApi() fluent-chain step (see Chapter 2 — Architecture). No route prefix, area, or API versioning is applied beyond each controller's own hardcoded [Route] attribute.

5.5 TenancyApi Variant — Near-Identical Duplication, Not Parameterized Multi-Tenant Admin

Shumoul.Framework.EInvoicing.TenancyApi exposes the same three controllers under api/Saas/EInvoicing/* (SaasEInvoicingController, SaasEInvoicingSettingsController, SaasEInvoicingOnboardingController) — line -for-line identical business logic, differing only in route prefix, ApiExplorerSettings GroupName, namespace, and which Tenancy-suffixed types are imported. Neither variant accepts a tenant identifier as a route or body parameter — the real difference is entirely in DI wiring (which IEInvoicingAppSettingService implementation is resolved in which host process), not in the controller surface itself.

5.6 SignalR

None. No Hub class or IHubContext usage exists anywhere in the EInvoicing projects, and none of the platform's three existing Hubs (WhatsAppHub, NotificationHub, BackgroundJobsHub) is connected to invoices or e-invoicing in any way.

5.7 Confirmation — No ERP Controller Calls Into the SDK

A repository-wide search of every Shumoul.Api controller and every Shumoul.Application service for ZATCA-related types returned zero matches. SalesInvoiceService.cs contains no reference to IInvoiceProcessFlowService, GenerateAndSubmit, or any EInvoicing type. The only way to reach the SDK today is the standalone /api/EInvoicing/Generate endpoint.