# Activation Endpoint Specification

## Overview

The DEXPRO Advanced Workflow BC app contacts an activation endpoint via HTTP POST to validate its license. The endpoint receives identification and usage data and must respond with HTTP 200 to confirm an active license. Any non-200 response is treated as a failed check.

## Endpoint Contract

- **Method:** `POST`
- **Content-Type:** `application/json`
- **Expected success response:** HTTP `200`
- **Failed response:** Any non-200 status code (e.g. 401, 403, 404, 500)

## Request Body

<table id="bkmrk-field-type-descripti" style="width:861px;"><thead><tr><th style="width:202px;">Field</th><th style="width:115px;">Type</th><th style="width:274px;">Description</th><th style="width:270px;">Example</th></tr></thead><tbody><tr><td style="width:202px;">`appId`</td><td style="width:115px;">`string` (GUID)</td><td style="width:274px;">Unique ID of the AWF app extension. Same for all installations.</td><td style="width:270px;">`"a1b2c3d4-e5f6-7890-abcd-ef1234567890"`</td></tr><tr><td style="width:202px;">`appVersion`</td><td style="width:115px;">`string`</td><td style="width:274px;">Installed app version.</td><td style="width:270px;">`"1.0.3.1"`</td></tr><tr><td style="width:202px;">`installationId`</td><td style="width:115px;">`string` (GUID)</td><td style="width:274px;">Unique ID generated per app installation. Stable across sessions. Useful for OnPrem where `tenantId` is `"default"`.</td><td style="width:270px;">`"f47ac10b-58cc-4372-a567-0e02b2c3d479"`</td></tr><tr><td style="width:202px;">`tenantId`</td><td style="width:115px;">`string`</td><td style="width:274px;">BC tenant ID. On SaaS this is a real GUID. On OnPrem this is typically `"default"`.</td><td style="width:270px;">`"b3f8c2a1-1234-5678-9abc-def012345678"` (SaaS) or `"default"` (OnPrem)</td></tr><tr><td style="width:202px;">`companyId`</td><td style="width:115px;">`string` (GUID)</td><td style="width:274px;">ID of the current BC company.</td><td style="width:270px;">`"c9d0e1f2-3456-7890-abcd-ef1234567890"`</td></tr><tr><td style="width:202px;">`companyName`</td><td style="width:115px;">`string`</td><td style="width:274px;">Name of the current BC company.</td><td style="width:270px;">`"CRONUS AG"`</td></tr><tr><td style="width:202px;">`environmentName`</td><td style="width:115px;">`string`</td><td style="width:274px;">Name of the BC environment.</td><td style="width:270px;">`"Production"` or `"Sandbox"`</td></tr><tr><td style="width:202px;">`isSaaS`</td><td style="width:115px;">`boolean`</td><td style="width:274px;">`true` if running on Microsoft SaaS (Business Central Online). `false` if OnPrem/self-hosted.</td><td style="width:270px;">`true`</td></tr><tr><td style="width:202px;">`isSandbox`</td><td style="width:115px;">`boolean`</td><td style="width:274px;">`true` if the environment is a sandbox. On SaaS this is controlled by Microsoft and reliable. On OnPrem this value is **not trusted** by the app (see OnPrem section).</td><td style="width:270px;">`false`</td></tr><tr><td style="width:202px;">`completedWorkflowsTotal`</td><td style="width:115px;">`integer`</td><td style="width:274px;">Total number of completed workflow instances (all time, all companies in this tenant).</td><td style="width:270px;">`142`</td></tr><tr><td style="width:202px;">`completedWorkflowsMonth`</td><td style="width:115px;">`integer`</td><td style="width:274px;">Number of completed workflow instances in the current calendar month.</td><td style="width:270px;">`23`</td></tr></tbody></table>

### Example Request Body

```lang-json
{
  "appId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "appVersion": "1.0.3.1",
  "installationId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "tenantId": "b3f8c2a1-1234-5678-9abc-def012345678",
  "companyId": "c9d0e1f2-3456-7890-abcd-ef1234567890",
  "companyName": "CRONUS AG",
  "environmentName": "Production",
  "isSaaS": true,
  "isSandbox": false,
  "completedWorkflowsTotal": 142,
  "completedWorkflowsMonth": 23
}

```

## Automatic License Validation

The app automatically contacts the endpoint in these situations:

<table id="bkmrk-trigger-when-awf-set"><thead><tr><th>Trigger</th><th>When</th></tr></thead><tbody><tr><td>**AWF Setup page opened**</td><td>On every page open</td></tr><tr><td>**Role Center opened**</td><td>When the Workflow Activities card part loads</td></tr><tr><td>**Workflow started**</td><td>Inside `CheckTrialAndBlockIfNeeded()` before each workflow execution</td></tr></tbody></table>

### Timing Rules

- **24-hour interval:** If the last successful check was less than 24 hours ago, no HTTP call is made.
- **15-minute retry:** If the last check failed and was less than 15 minutes ago, no HTTP call is made (but the license is deactivated if the 24h window has expired).
- **24-hour expiry:** If no successful check within 24 hours, the license is deactivated and the app falls back to trial mode.

## Manual License Check

The AWF Setup page provides a **"Check License"** promoted action. This allows the administrator to manually trigger a license check at any time, **bypassing** the 24-hour and 15-minute timing intervals.

Use cases:

- The 24-hour window expired and no trial runs are available — the user needs to re-verify the license immediately.
- The endpoint was temporarily unreachable and has been fixed.
- Initial license activation after entering the endpoint URL.

Behavior:

- If no endpoint URL is configured, an error is shown: *"No activation endpoint URL is configured. Please enter the Activation Endpoint URL first."*
- On HTTP 200: The license is activated (if in trial mode), and a success message is shown.
- On failure: A failure message is shown. The license state is not changed by the manual check itself (unlike the automatic check which deactivates on expiry).

## License States

<table id="bkmrk-state-istrialmode%28%29-"><thead><tr><th>State</th><th>`IsTrialMode()`</th><th>`Activated`</th><th>Description</th></tr></thead><tbody><tr><td>**Trial Active**</td><td>`true`</td><td>`true`</td><td>App is in trial mode with remaining runs.</td></tr><tr><td>**Trial Limit Reached**</td><td>`true`</td><td>`false`</td><td>Trial runs exhausted. App deactivated. All templates deactivated.</td></tr><tr><td>**Licensed**</td><td>`false`</td><td>`true`</td><td>Valid license confirmed by endpoint.</td></tr><tr><td>**Sandbox** (SaaS only)</td><td>varies</td><td>varies</td><td>SaaS sandbox environment. Unlimited usage, no trial counting.</td></tr></tbody></table>

## Trial Mode Behavior

- **Maximum workflow runs:** Default 50 (configurable via IsolatedStorage).
- **Template limit:** Only **1 active workflow template** is allowed in trial mode. Attempting to activate a second template shows an error.
- **Run counting:** Each completed workflow increments the run counter. Sandbox environments do not count.
- **90% warning:** When 90% of trial runs are used, a warning notification is shown.
- **Trial expiry (limit reached):**
    - `AWFSetup.Activated` is set to `false`.
    - **All active workflow templates are deactivated** (set to `Active = false`).
    - Standard BC processes (posting, releasing, etc.) continue to work normally because deactivated templates don't trigger workflows.

## Licensed Mode Behavior

- No template limit.
- No run counting.
- License is validated every 24 hours via the activation endpoint.
- If the endpoint is unreachable for more than 24 hours, the license is deactivated and the app falls back to trial mode. If the trial limit was already reached, the app and all templates are deactivated.

## Sandbox Behavior (SaaS Only)

On **SaaS** environments where `IsSandbox()` is `true`:

- Trial runs are **not counted**.
- There is **no template limit**.
- The trial cue on the Role Center is **hidden**.
- The "Workflow Runs Used" field on the Setup page is **hidden**.
- The status shows **"Sandbox"**.
- The activation endpoint is still called if configured (for tracking/reporting purposes).

### OnPrem Environments

On **OnPrem** environments, **sandbox mode is disabled entirely**. Even if `IsSandbox()` returns `true`, the app treats it as a production environment. This is because OnPrem administrators can manipulate the environment type setting, which would allow bypassing trial restrictions. The `isSandbox` field in the JSON body still reflects the raw `IsSandbox()` value from BC, so the backend can see the environment's self-reported type — but the app itself does not trust it for licensing decisions on OnPrem.

## Deactivation Side Effects

When the app is deactivated (trial expired or license revoked):

1. `AWFSetup.Activated` is set to `false`.
2. All active workflow templates are set to `Active = false`.
3. This ensures that event subscribers in the integration engine exit early and do not interfere with standard BC processes.
4. Templates are **not** automatically re-activated when the license is restored. The administrator must manually re-activate the desired templates.

## Identification Strategy

<table id="bkmrk-environment-primary-"><thead><tr><th>Environment</th><th>Primary Identifier</th><th>Notes</th></tr></thead><tbody><tr><td>**SaaS**</td><td>`tenantId` + `companyId`</td><td>`tenantId` is a real GUID assigned by Microsoft. tenantId alone is enough to identify a unique tenant of a customer</td></tr><tr><td>**OnPrem**</td><td>`installationId` + `companyId`</td><td>`tenantId` is `"default"` on OnPrem. `installationId` is a stable GUID generated once during first install.</td></tr></tbody></table>