Skip to main content
Version: Latest

6. API Reference — Preview / Apply / Internal Endpoint

6.1 Root-admin controller (MultiTenancyApi)

POST api/Saas/TenantOperationalDefaults/Preview { "tenantId": "...", "correlationId": "..." }
POST api/Saas/TenantOperationalDefaults/Apply { "tenantId": "...", "correlationId": "..." }
GET api/Saas/TenantOperationalDefaults/Tenants/{tenantId}/DefaultPlan
  • Controller: TenantOperationalDefaultsController (ApiExplorerSettings(GroupName = "MultiTenancy")).
  • Every action requires a permission — TenancyPermissions.TenantOperationalDefaults.Apply (Preview and Apply) or .View (the DefaultPlan read-only alias for Preview).
  • Preview never writes anything (no tenant DB write, no apply log). Apply writes tenant records through the bridge and always writes a TenantOperationalDefaultApplyLog row (Saas schema), identical convention to every sibling apply flow.

6.2 Response shape

{
"succeeded": true,
"dryRun": false,
"tenantId": "247360",
"correlationId": "3b3f3243-74ea-4cb1-81aa-5c296a89b10c",
"totalRequestedKinds": 3,
"createdCount": 2,
"skippedExistingCount": 1,
"entitlementSkippedCount": 1,
"failedCount": 0,
"items": [
{ "kind": "Warehouse", "code": "DefaultWarehouse", "status": "SkippedExisting", "resolvedId": "..." },
{ "kind": "CashAccount", "code": "DefaultCashAccount", "status": "Created", "resolvedId": "..." },
{ "kind": "SalesInvoiceTemplate", "code": "DefaultSalesInvoiceTemplate", "status": "Created", "resolvedId": "..." }
],
"warnings": ["BankAccount default was skipped — tenant does not have any of the required subscription feature entitlements (Features.AccountManagement)."],
"error": null
}

status is one of WouldCreate/Created/SkippedExisting/Failed (plain string, not a shared enum — same forward-compatibility reasoning as every sibling apply contract).

6.3 Internal bridge (SaaS → BackEnd)

POST {BackEndBaseUrl}/api/internal/tenant-operational-defaults/apply
Header: X-Shumoul-Internal-Key: {shared secret}
Header: X-Correlation-Id: {guid}
Header: TenantId: {tenant identifier}
  • MultiTenancyApi side: TenantOperationalDefaultsApplyBridgeSettings (Enabled, BackEndBaseUrl, ApplyPath, InternalApiKey, TimeoutSeconds) — sibling of OnboardingApplyBridgeSettings, own dedicated named HttpClient ("tenant-operational-defaults-apply-bridge"), since this is a genuinely new trust boundary (spans both POS and Finance concerns, not one accounting-setup capability).
  • BackEnd side: TenantOperationalDefaultsApplyInternalController ([AllowAnonymous][ApiExplorerSettings(IgnoreApi = true)], hidden from Swagger) — validates X-Shumoul-Internal-Key against InternalServiceAuthSettings.TenantOperationalDefaultsApplyApiKey (a dedicated key, not reused from any sibling endpoint): missing key → 401; wrong key → 403; missing TenantId/empty Items400; success → 200; service-reported failure → 502. Identical sequence to every sibling internal endpoint (OnboardingInternalController, CostCenterTemplateApplyInternalController).
  • BackEnd service: TenantOperationalDefaultsProvisioningService — trusts the ambient ITenantInfo (never resolves/switches a tenant database itself), resolves current state for every requested kind before writing anything (the same plan a DryRun reports is the plan a real apply executes), wraps all writes in one transaction, then wires CashierAppsSettings and UserCashierSettings (see Chapter 7).

6.4 Entitlement resolution

ITenantOperationalDefaultsService (MultiTenancyApi) resolves entitlement per kind via ISubscriptionFeatureEntitlementService.IsFeatureAllowedAsync — the same real, seeded SubscriptionFeature mechanism every sibling apply flow already uses (see Chapter 4 §4.2 for the exact keys per kind). A kind the tenant is not entitled to is skipped with a clear warning (never invented, never blocks the other entitled kinds, never fails the whole apply) — see Chapter 9 for the live-verified example.