Skip to main content
Version: Latest

9. Onboarding

9.1 Device (Solution Unit) Onboarding — OTP Flow

The OTP itself is obtained by the tenant admin directly from ZATCA's own portal, out of band — it arrives at the ERP only as an HTTP header on the POST api/EInvoicing/Onboarding call, never from configuration. A Otp: 123345 value present in appsettings.Development.json/appsettings.production.json's ZatcaPortalSettings section is a leftover fixed testing value, not a live onboarding mechanism — confirmed by the absence of any code path that reads a ZatcaPortalSettings.Otp property (no such property exists on the class at all).

9.2 Onboarding / Certificate Lifecycle Services

ServiceResponsibility
OnboardingProcessFlowServiceOrchestrates Compliance CSID → Compliance checks → Production CSID, sequentially, for Initialize(type, otp)
OnboardingValidatorServiceTenantIsOnboarded()/CheckOnboardingStatus() — reads FatooraSecretSettings.Onboarded, throws BadRequestException if not onboarded
OnboardingComplianceCsidServiceRequests the Compliance CSID from ZATCA (via ClientCsidService.Compliance)
OnboardingProductionCsidServiceRequests/renews the Production CSID (via ClientCsidService.Production); throws if FatooraSecretSettings.Onboarded == false
OnboardingComplianceCheckServiceRuns the "compliance checks" step (SimplifiedInvoiceCompliance, StandardInvoiceCompliance — the file StandardTaxInvoiceCompliance.cs actually declares a class named StandardInvoiceCompliance, a filename/class-name mismatch)
X509CertificateServiceGenerates the CSR, generates/imports the EC key pair, caches the resulting certificate in the Windows certificate store
ECKeyPairHelperGenerates the EC key pair (SecObjectIdentifiers.SecP256k1)

9.3 Authentication During Onboarding

The Compliance CSID request (the very first onboarding step) correctly does not attach Basic-Auth — this matches ZATCA's spec, since the caller doesn't have a CSID yet at that point; it authenticates with the CSR and OTP only.

Every step after that — the Production CSID request (both initial issuance and renewal) — does require ZATCA-side Basic-Auth. This is exactly the call path the Phase 0/0.1/0.2 authentication finding and fix covered — see Chapter 7 — Security § 7.2. Before the Phase 0.2 fix, any onboarding attempt that reached the Production CSID step would have received an unauthenticated request rejection from ZATCA.

9.4 Onboarding Events (MediatR)

All 8 events use MediatR (INotification/INotificationHandler<T>), not the platform's generic Notification Framework:

EventPublished fromHandler action
OnboardingCompletedEventClientCsidServicePersists ProductionCsidSettings/FatooraSecretSettings. Logging only
OnboardingRenewalEventOnboarding.ProcessFlowServiceRemoves the X.509 cert from the certificate store
SwitchToProductionModeEventController, via IMediator.PublishValidates the mode transition, clears/sets app settings
SingleComplianceCheckDoneEventClientComplianceServiceFlips a boolean flag per invoice type in ComplianceChecksSettings
CompilanceChecksFailureEventClientComplianceServiceMarks OTP Invalid = true, clears settings to restart onboarding
OtpIsProvidedEventOnboarding.ProcessFlowServiceValidates OTP format/expiry; throws BadRequestException on failure
OtpIsRejectedEventClientCsidServiceSets Invalid = true in settings
OnboardingStartOverEventOnboarding.ProcessFlowServiceRevokes/removes the X.509 cert; throws if not revoked on the ZATCA portal first

Every handler does only state persistence, certificate-store operations, logging, or throws a validation exception — none call any communication/notification interface. See Chapter 12 — Known Limitations for what this means practically (no alert if onboarding fails or a certificate is about to expire).

9.5 No ERP Workflow Triggers Onboarding

Onboarding, like invoice submission, is reachable only via its dedicated controller endpoint — no ERP business workflow initiates it automatically. A tenant admin (or whatever caller has the OTP) drives the process manually, one HTTP call at a time.