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.