DirectivSys.Sdk 1.2.9

dotnet add package DirectivSys.Sdk --version 1.2.9
                    
NuGet\Install-Package DirectivSys.Sdk -Version 1.2.9
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="DirectivSys.Sdk" Version="1.2.9" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="DirectivSys.Sdk" Version="1.2.9" />
                    
Directory.Packages.props
<PackageReference Include="DirectivSys.Sdk" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add DirectivSys.Sdk --version 1.2.9
                    
#r "nuget: DirectivSys.Sdk, 1.2.9"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package DirectivSys.Sdk@1.2.9
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=DirectivSys.Sdk&version=1.2.9
                    
Install as a Cake Addin
#tool nuget:?package=DirectivSys.Sdk&version=1.2.9
                    
Install as a Cake Tool

DirectivSys.Sdk

Official .NET SDK for DirectivSys Analytics Platform. Enables seamless integration with DirectivSys to receive AI-powered business intelligence directives and submit analytics payloads.

DirectivSys is an AI-powered platform for autonomous business operations. This SDK provides backend integration for businesses to submit operational data for analysis and receive intelligent, actionable directives via webhookβ€”all without DirectivSys ever accessing your core systems.

NuGet License: MIT

Key Principles

Zero System Access - DirectivSys never accesses your databases, APIs, or system credentials. You control exactly what data flows in and out through this SDK.

Platform Agnostic - Works with any tech stack. Lightweight SDK with webhook-based directive delivery means minimal integration effort.

Autonomous Intelligence - Move beyond dashboards to actionable directives. The AI analyzes your data and recommends specific business actions.

Features

✨ Zero Boilerplate - Automatic webhook endpoint creation
πŸ”’ Secure by Default - Built-in authentication via API keys
πŸ“¦ Strongly Typed - Complete DTOs for all analytics types
πŸš€ Easy Submission - Fluent API for submitting analytics payloads
πŸ“Š Inventory Ingestion - Real-time and batch data synchronization
πŸ›‘οΈ Secure Directive Execution - Template Method executors with retries, circuit breaker, and audited ImpactData
⚑ Async/Await - Modern async patterns throughout
🎯 Enum Support - Type-safe analytics type selection
πŸ” Zero Direct Access - Your data is never accessed directly by DirectivSys

Installation

dotnet add package DirectivSys.Sdk

Or via Package Manager Console:

Install-Package DirectivSys.Sdk

Quick Start

1. Configure Services (Program.cs or Startup.cs)

using DirectivSys.Sdk.Extensions;
using DirectivSys.Sdk.Services;

var builder = WebApplication.CreateBuilder(args);

// Add DirectivSys SDK
builder.Services.AddDirectivSys(options =>
{
    options.ApiKey = "your-directivsys-api-key";
    // ClientId is automatically extracted from the API Key
});

// Register directive executors (action -> executor mapping)
builder.Services.AddDirectiveExecutor<ReorderSupplierExecutor>("reorderSupplier");

var app = builder.Build();

// Map the webhook endpoint
app.MapDirectivWebhook();

// Optional: log records when they arrive (business logic runs in executors)
var directivSys = app.GetDirectivSys();
directivSys.OnDirectiveReceived = record =>
{
    Console.WriteLine($"Received {record.Directives.Count} directives for {record.AnalyticsType}");
};

app.Run();

Create an executor by deriving from BaseDirectiveExecutor (business logic stays in your code; SDK only calls you with parameters and status updates):

public sealed class ReorderSupplierExecutor : BaseDirectiveExecutor
{
    public ReorderSupplierExecutor(DirectivSysClient client, ILogger<BaseDirectiveExecutor> logger)
        : base(client, logger) { }

    protected override Task<DirectiveExecutionResult> ExecuteInternalAsync(Dictionary<string, object> parameters)
    {
        var sku = parameters["sku"].ToString();
        var quantity = Convert.ToInt32(parameters["quantity"]);

        // Your secure business logic here (no DbContext injected into SDK)

        return Task.FromResult(new DirectiveExecutionResult
        {
            Success = true,
            ImpactData = new ImpactData
            {
                EntityId = sku,
                PropertyChanged = "stockLevel",
                OriginalValue = null,
                NewValue = null,
                InsightDelta = -quantity
            },
            Message = "Reorder placed"
        });
    }
}

What the template method does for you:

  • Updates directive status to Executing, retries transient failures (HTTP/timeout/SqlException name match) with jittered exponential backoff, and trips a 30s circuit breaker after 5 consecutive failures.
  • Calls your ExecuteInternalAsync once per directive.
  • On success, posts Executed with your ImpactData; on failure, posts Failed and logs.

2. Submit Analytics Data

using DirectivSys.Sdk.Models.Payloads;
using DirectivSys.Sdk.Services;

public class InventoryService
{
    private readonly DirectivSysClient _client;

    public InventoryService(DirectivSysClient client)
    {
        _client = client;
    }

    public async Task AnalyzeInventoryAsync()
    {
        var payload = new InventoryHealthPayload
        {
            Sku = "SKU123",
            StockLevel = 20,
            ReorderPoint = 50,
            SafetyStock = 30,
            ForecastedDemandNext30Days = 200,
            AverageLeadTimeDays = 5
        };

        // Submit the payload for async processing
        // Instructions are pre-configured in AnalyticsConfig on the backend
        var response = await _client.SubmitInventoryHealthAsync(payload);
        Console.WriteLine($"Payload submitted: {response.PayloadId}, Status: {response.Status}");
        
        // Option 1: Poll for results
        var result = await PollForResultAsync(response.PayloadId);
        
        // Option 2: Process immediately (synchronous)
        // var result = await _client.ProcessLatestAsync("InventoryHealth");
    }
    
    private async Task<AnalyticsResult?> PollForResultAsync(Guid payloadId, int maxAttempts = 30)
    {
        for (int i = 0; i < maxAttempts; i++)
        {
            var response = await _client.GetResultByPayloadIdAsync(payloadId);
            
            if (response.IsComplete && response.Result != null)
            {
                return response.Result;
            }
            
            if (response.Status == "failed")
            {
                throw new Exception($"Processing failed: {response.Error}");
            }
            
            await Task.Delay(1000); // Wait 1 second before next poll
        }
        
        throw new TimeoutException("Polling timed out");
    }
}

Supported Analytics Types

The SDK includes strongly-typed payload classes for all DirectivSys analytics types:

Important: Instructions for each analytics type are configured once in the AnalyticsConfig on the DirectivSys platform dashboard, not sent with each payload submission. Payloads contain only data - this reduces payload size and allows updating instructions without changing client code.

Supply Chain Analytics

  • InventoryHealth - Stock level monitoring and reorder recommendations

    • Monitors current stock against reorder points
    • Detects stockout risks proactively
    • Recommends reorder quantities and supplier switches
    • Integrates supplier reliability data
    • Generates directives: reorderSupplier, adjustReorderPoint, switchSupplier
  • SupplierReliability - Supplier performance evaluation

    • Tracks lead times, late delivery rates, and quality metrics
    • Flags underperforming suppliers
    • Recommends supplier switches for critical SKUs
    • Suggests quality improvement negotiations
    • Generates directives: switchSupplier, negotiateContract, flagSupplier
  • DemandForecast - Future demand prediction using historical data and seasonality

    • Predicts future demand trends
    • Accounts for seasonality and growth trends
    • Supports multi-period forecasting
    • Identifies demand spikes requiring production planning
    • Generates directives: prepareForecastedDemand, adjustSafetyStock, launchPromotion
  • CostOptimization - Order quantity optimization and supplier cost comparison

    • Calculates optimal order quantities using Economic Order Quantity (EOQ)
    • Balances holding costs against stockout risks
    • Compares alternative suppliers for cost-effectiveness
    • Recommends safety stock adjustments based on lead times
    • Generates directives: optimizeOrderQuantity, adjustSafetyStock, switchSupplier, renegotiateTerms

E-Commerce Analytics

  • CustomerSegmentation - Customer grouping by behavior and lifetime value

    • Segments customers into strategic groups
    • Identifies high-value and at-risk customers
    • Enables targeted retention campaigns
    • Supports personalized marketing strategies
    • Generates directives: targetRetention, launchVIPProgram, sendWinBackOffer
  • CartAbandonment - Abandoned cart detection and recovery strategies

    • Identifies carts left behind before purchase
    • Estimates lost revenue
    • Recommends targeted recovery campaigns
    • Suggests product-specific follow-up strategies
    • Generates directives: sendRecoveryEmail, offerDiscount, updateRecommendations
  • SalesFunnelConversion - Conversion rate tracking and funnel optimization

    • Tracks conversion at each stage of the customer journey
    • Identifies drop-off points in the funnel
    • Highlights devices or channels with low conversion
    • Compares performance across regions and segments
    • Generates directives: optimizeCheckout, reduceCheckoutSteps, improveProductPages
  • ProductPerformance - Bestseller and slow-mover identification

    • Identifies high-performing and underperforming products
    • Tracks sales trends and velocity
    • Recommends inventory adjustments
    • Identifies candidates for promotion or deprecation
    • Generates directives: boostPromotion, reduceInventory, discontinue
  • CustomerLifetimeValue - Long-term customer value estimation

    • Estimates total lifetime value of each customer
    • Predicts churn risk and identifies at-risk high-value customers
    • Supports premium customer retention programs
    • Calculates optimal marketing spend per customer segment
    • Generates directives: prioritizeRetention, offerPremiumService, increaseLoyaltyRewards
  • MarketingROI - Campaign effectiveness measurement

    • Measures cost per acquisition and return on ad spend
    • Tracks campaign performance across channels
    • Identifies most cost-effective campaigns
    • Recommends budget reallocation across channels
    • Generates directives: pauseLowPerformingCampaign, scaleHighPerformingCampaign, testNewChannel

Architecture & Security

Zero System Access Design

DirectivSys operates completely outside your infrastructure. You control all data flow:

  1. Your backend collects operational data - You decide what data to send
  2. This SDK packages and sends it to DirectivSys - Encrypted transmission via TLS 1.3
  3. DirectivSys analyzes the data - Using Claude Haiku 4.5, aggregated at the portfolio level
  4. Results come back via webhook - Delivered only to your endpoint
  5. Your backend executes directives - You maintain full control

Key Security Principles:

  • βœ… DirectivSys never authenticates to your systems
  • βœ… DirectivSys never reads your database directly
  • βœ… DirectivSys never calls your internal APIs with your credentials
  • βœ… DirectivSys never stores your API keys or system credentials
  • βœ… All data transmission is encrypted end-to-end

Data Privacy Considerations

Current (February 2026):

  • You choose what data to send
  • DirectivSys does NOT automatically scrub or mask data
  • Recommended: Send operational data only (SKUs, inventory levels, supplier names, costs)
  • Avoid sending PII (customer emails, addresses, phone numbers) for now

Roadmap (Q2 2026):

  • Automatic PII detection and masking
  • Configurable privacy levels (Aggressive/Balanced/Minimal)
  • HIPAA compliance support
  • GDPR compliance support
  • SOC 2 certification

Platform Configuration

Analytics instructions and directives are configured once in your DirectivSys platform dashboard:

  1. Login to your DirectivSys account - Access the client platform
  2. Go to Analytics Configuration - Set up analytics types you want to use
  3. Define Instructions - Tell the AI how to behave for your business
  4. Configure Directives - Define what actions the AI can recommend
  5. Your backend just sends data - This SDK handles the rest

This means you can update your analytics strategy without touching your backend code!

Inventory Data Ingestion

The SDK provides powerful methods for synchronizing inventory data into DirectivSys for real-time analytics. This enables you to keep your inventory data up-to-date with both single-item updates and efficient batch synchronization.

Features

  • βœ… Single Item Updates - Real-time updates for individual inventory items
  • βœ… Batch Synchronization - Efficient bulk data sync with progress tracking
  • βœ… Automatic Validation - Client-side validation before sending
  • βœ… Sync Status Monitoring - Track progress of batch operations
  • βœ… Error Handling - Detailed error reporting for failed items
  • βœ… Idempotent Operations - Safe to retry on network failures

Single Item Update

Update or insert individual inventory items in real-time (e.g., after a sale or restock):

using DirectivSys.Sdk.Models;

public class InventoryService
{
    private readonly DirectivSysClient _client;

    public InventoryService(DirectivSysClient client)
    {
        _client = client;
    }

    public async Task UpdateInventoryAsync(string sku, decimal newStockLevel)
    {
        var item = new InventoryItem
        {
            Sku = sku,
            ProductName = "Widget A",
            ProductCategory = "Tools",
            PriorityLevel = "high",
            StockLevel = newStockLevel,
            ReorderPoint = 50,
            SafetyStock = 20,
            ForecastedDemandNext30Days = 200,
            UnitCost = 5.5m,
            HoldingCostPerUnit = 0.2m,
            OrderCost = 15m,
            SupplierId = "SUP456",
            SupplierName = "Acme Supplies",
            AvgLeadTimeDays = 7,
            LateDeliveriesPercent = 0.05m,
            QualityDefectRate = 0.02m,
            SupplierReliabilityScore = 92m,
            MinOrderQty = 10,
            BudgetCap = 5000m
        };

        // Using enum (recommended)
        var response = await _client.UpdateInventoryItemAsync(
            AnalyticsType.InventoryHealth, 
            item);

        Console.WriteLine($"Item {response.Sku} {response.Status}");
    }
}

Required Fields:

  • Sku - Stock Keeping Unit (unique identifier)
  • StockLevel - Current stock level (must be >= 0)
  • ReorderPoint - Reorder threshold (must be >= 0)

All other fields are optional but recommended for comprehensive analytics.

Batch Synchronization

For syncing large datasets (e.g., nightly full inventory sync), use batch ingestion with automatic progress tracking:

public class InventorySyncService
{
    private readonly DirectivSysClient _client;
    private readonly ILogger<InventorySyncService> _logger;

    public InventorySyncService(
        DirectivSysClient client, 
        ILogger<InventorySyncService> logger)
    {
        _client = client;
        _logger = logger;
    }

    public async Task SyncFullInventoryAsync(List<InventoryItem> allItems)
    {
        // Generate unique sync ID
        var syncId = $"sync-{DateTime.UtcNow:yyyyMMdd-HHmmss}";
        
        // Split into batches of 100-500 items
        var batchSize = 250;
        var batches = allItems
            .Select((item, index) => new { item, index })
            .GroupBy(x => x.index / batchSize)
            .Select(g => g.Select(x => x.item).ToList())
            .ToList();

        _logger.LogInformation(
            "Starting sync {SyncId} with {TotalBatches} batches ({TotalItems} items)",
            syncId, batches.Count, allItems.Count);

        // Process each batch
        for (int i = 0; i < batches.Count; i++)
        {
            var request = new BatchIngestionRequest
            {
                SyncId = syncId,
                TotalBatches = batches.Count,
                CurrentBatchIndex = i,
                Items = batches[i]
            };

            try
            {
                var response = await _client.SyncInventoryBatchAsync(
                    AnalyticsType.InventoryHealth,
                    request);

                _logger.LogInformation(
                    "Batch {Current}/{Total}: {Success} succeeded, {Failed} failed",
                    i + 1,
                    batches.Count,
                    response.SuccessfulCount,
                    response.FailedCount);

                // Log any failures
                foreach (var failure in response.FailedItems)
                {
                    _logger.LogWarning(
                        "Failed to sync {Sku}: {Error} ({ErrorType})",
                        failure.Sku,
                        failure.ErrorMessage,
                        failure.ErrorType);
                }

                // Check if sync is complete
                if (response.SyncStatus.IsComplete)
                {
                    _logger.LogInformation(
                        "Sync {SyncId} completed! Total: {Success} succeeded, {Failed} failed",
                        syncId,
                        response.SyncStatus.TotalSuccessfulItems,
                        response.SyncStatus.TotalFailedItems);
                }
            }
            catch (DirectivSysException ex)
            {
                _logger.LogError(ex, "Failed to sync batch {Index}", i);
                throw;
            }
        }

        // Verify completion
        var finalStatus = await _client.GetSyncStatusAsync(syncId);
        
        if (!finalStatus.IsComplete)
        {
            throw new Exception(
                $"Sync incomplete: {finalStatus.ReceivedBatches}/{finalStatus.TotalBatches} batches received");
        }

        return finalStatus;
    }
}

Sync Status Monitoring

Check the progress of a batch synchronization job:

public async Task<SyncStatus> CheckSyncProgressAsync(string syncId)
{
    var status = await _client.GetSyncStatusAsync(syncId);

    Console.WriteLine($"Status: {status.Status}");
    Console.WriteLine($"Progress: {status.ReceivedBatches}/{status.TotalBatches} batches");
    Console.WriteLine($"Items: {status.TotalSuccessfulItems} succeeded, {status.TotalFailedItems} failed");
    Console.WriteLine($"Complete: {status.IsComplete}");

    if (status.IsComplete)
    {
        Console.WriteLine($"Completed at: {status.CompletedAt}");
    }

    return status;
}

Resilient Batch Sync with Recovery

Handle network interruptions gracefully:

public async Task SyncWithRecoveryAsync(
    List<InventoryItem> allItems, 
    string? resumeSyncId = null)
{
    string syncId;
    int startBatchIndex = 0;

    // Check if resuming an existing sync
    if (!string.IsNullOrEmpty(resumeSyncId))
    {
        var status = await _client.GetSyncStatusAsync(resumeSyncId);
        syncId = resumeSyncId;
        startBatchIndex = status.ReceivedBatches; // Resume from where we left off
        
        _logger.LogInformation(
            "Resuming sync {SyncId} from batch {StartIndex}",
            syncId, startBatchIndex);
    }
    else
    {
        syncId = $"sync-{DateTime.UtcNow:yyyyMMdd-HHmmss}";
        _logger.LogInformation("Starting new sync {SyncId}", syncId);
    }

    var batchSize = 250;
    var batches = allItems
        .Select((item, index) => new { item, index })
        .GroupBy(x => x.index / batchSize)
        .Select(g => g.Select(x => x.item).ToList())
        .ToList();

    // Process from startBatchIndex onwards
    for (int i = startBatchIndex; i < batches.Count; i++)
    {
        var request = new BatchIngestionRequest
        {
            SyncId = syncId,
            TotalBatches = batches.Count,
            CurrentBatchIndex = i,
            Items = batches[i]
        };

        try
        {
            await _client.SyncInventoryBatchAsync(
                AnalyticsType.InventoryHealth,
                request);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, 
                "Network failure at batch {Index}. Resume with syncId: {SyncId}",
                i, syncId);
            throw;
        }
    }
}

Inventory Item Schema

public class InventoryItem
{
    // Required fields
    public string Sku { get; set; }                         // Stock Keeping Unit
    public decimal StockLevel { get; set; }                 // Current stock level
    public decimal ReorderPoint { get; set; }               // Reorder threshold

    // Product information
    public string? ProductName { get; set; }
    public string? ProductCategory { get; set; }
    public string? PriorityLevel { get; set; }              // "high", "medium", "low"

    // Inventory metrics
    public decimal? SafetyStock { get; set; }
    public decimal? ForecastedDemandNext30Days { get; set; }
    public decimal? UnitCost { get; set; }
    public decimal? HoldingCostPerUnit { get; set; }
    public decimal? OrderCost { get; set; }
    public int? MinOrderQty { get; set; }
    public decimal? BudgetCap { get; set; }

    // Supplier information
    public string? SupplierId { get; set; }
    public string? SupplierName { get; set; }
    public int? AvgLeadTimeDays { get; set; }
    public decimal? LateDeliveriesPercent { get; set; }     // 0-1
    public decimal? QualityDefectRate { get; set; }         // 0-1
    public decimal? SupplierReliabilityScore { get; set; }  // 0-100
}

Best Practices

Batch Sizing
  • 50-100 items: Better error isolation, more API calls
  • 100-500 items: Balanced approach (recommended)
  • 500-1000 items: Fewer API calls, harder to debug failures
Sync ID Naming

Use descriptive, unique identifiers:

βœ… Good: "sync-20260118-nightly-001"
βœ… Good: "sync-inventory-full-20260118143045"
❌ Bad:  "sync1" or "test"
Error Handling
try
{
    var response = await client.UpdateInventoryItemAsync(
        AnalyticsType.InventoryHealth, 
        item);
}
catch (ArgumentException ex)
{
    // Validation error (e.g., missing SKU, negative stock)
    logger.LogError(ex, "Invalid inventory item");
}
catch (DirectivSysException ex)
{
    // API error (e.g., authentication, server error)
    logger.LogError(ex, "Failed to update inventory");
}
Real-Time vs Batch Sync

Use Single Item Updates for:

  • Real-time inventory changes (sales, restocking)
  • Event-driven updates
  • Individual corrections

Use Batch Sync for:

  • Full inventory synchronization
  • Large dataset ingestion
  • Scheduled periodic syncs (e.g., nightly)

Rate Limits

  • Single Item Updates: 100 requests/minute
  • Batch Ingestion: 10 batches/minute
  • Sync Status: 60 requests/minute

Exceeding rate limits returns 429 Too Many Requests.

API Reference

Configuration

DirectivSysOptions
public class DirectivSysOptions
{
    public string ApiKey { get; set; }        // Required: Your DirectivSys API Key (X-API-Key header)
    public string BaseUrl { get; set; }       // Default: "https://api.directivsys.com"
    public Guid? ClientId { get; set; }       // Optional: Extracted from API Key if not provided
    public int TimeoutSeconds { get; set; }   // Default: 30
}

Core Models

GlobalRecord

The main container for analytics results received via webhook:

public class GlobalRecord
{
    public Guid RecordId { get; set; }
    public string AnalyticsType { get; set; }
    public List<Directive> Directives { get; set; }
    public List<Metric> Metrics { get; set; }
    public List<Observation> Observations { get; set; }
    public string Provenance { get; set; }
    public DateTime CreatedAt { get; set; }
}
Directive

Actionable recommendations from the AI agent:

public class Directive
{
    public Guid DirectiveId { get; set; }
    public int Priority { get; set; }                    // 1 = highest priority
    public string Action { get; set; }                   // e.g., "reorderSupplier"
    public Dictionary<string, object> Parameters { get; set; }
    public List<string> Targets { get; set; }
    public string Rationale { get; set; }
    public string Status { get; set; }
}
Metric

Calculated business metrics:

public class Metric
{
    public string Name { get; set; }
    public double Value { get; set; }
    public string Unit { get; set; }
    public string Status { get; set; }      // "healthy", "warning", "critical"
    public string Explanation { get; set; }
}
Observation

Human-readable explanations and context:

public class Observation
{
    public string Text { get; set; }
    public string Severity { get; set; }    // "info", "warning", "critical"
    public string Scope { get; set; }       // "global", "product", "supplier"
}

DirectivSysClient Methods

Submit Analytics Payloads
// Strongly-typed convenience methods for predefined analytics types
Task<IngestResponse> SubmitInventoryHealthAsync(InventoryHealthPayload payload, CancellationToken cancellationToken = default)
Task<IngestResponse> SubmitSupplierReliabilityAsync(SupplierReliabilityPayload payload, CancellationToken cancellationToken = default)
Task<IngestResponse> SubmitDemandForecastAsync(DemandForecastPayload payload, CancellationToken cancellationToken = default)
Task<IngestResponse> SubmitCostOptimizationAsync(CostOptimizationPayload payload, CancellationToken cancellationToken = default)
Task<IngestResponse> SubmitCustomerSegmentationAsync(CustomerSegmentationPayload payload, CancellationToken cancellationToken = default)
Task<IngestResponse> SubmitCartAbandonmentAsync(CartAbandonmentPayload payload, CancellationToken cancellationToken = default)
Task<IngestResponse> SubmitSalesFunnelConversionAsync(SalesFunnelConversionPayload payload, CancellationToken cancellationToken = default)
Task<IngestResponse> SubmitProductPerformanceAsync(ProductPerformancePayload payload, CancellationToken cancellationToken = default)
Task<IngestResponse> SubmitCustomerLifetimeValueAsync(CustomerLifetimeValuePayload payload, CancellationToken cancellationToken = default)
Task<IngestResponse> SubmitMarketingROIAsync(MarketingROIPayload payload, CancellationToken cancellationToken = default)

// Generic submission for any analytics type (with enum)
Task<IngestResponse> SubmitAnalyticsAsync<T>(AnalyticsType analyticsType, T payload, CancellationToken cancellationToken = default) 
    where T : AnalyticsPayloadBase

// Generic submission for any analytics type (with string)
Task<IngestResponse> SubmitAnalyticsAsync<T>(string analyticsType, T payload, CancellationToken cancellationToken = default) 
    where T : AnalyticsPayloadBase
Inventory Data Ingestion
// Update or insert a single inventory item (with enum)
Task<ItemUpdateResponse> UpdateInventoryItemAsync(
    AnalyticsType analyticsType, 
    InventoryItem item, 
    CancellationToken cancellationToken = default)

// Update or insert a single inventory item (with string)
Task<ItemUpdateResponse> UpdateInventoryItemAsync(
    string analyticsType, 
    InventoryItem item, 
    CancellationToken cancellationToken = default)

// Ingest a batch of inventory items (with enum)
Task<BatchIngestionResponse> SyncInventoryBatchAsync(
    AnalyticsType analyticsType, 
    BatchIngestionRequest request, 
    CancellationToken cancellationToken = default)

// Ingest a batch of inventory items (with string)
Task<BatchIngestionResponse> SyncInventoryBatchAsync(
    string analyticsType, 
    BatchIngestionRequest request, 
    CancellationToken cancellationToken = default)

// Get sync status and progress
Task<SyncStatus> GetSyncStatusAsync(
    string syncId, 
    CancellationToken cancellationToken = default)
Process and Retrieve Results
// Process the latest pending payload synchronously (with enum)
Task<AnalyticsResult> ProcessLatestAsync(AnalyticsType analyticsType, CancellationToken cancellationToken = default)

// Process the latest pending payload synchronously (with string)
Task<AnalyticsResult> ProcessLatestAsync(string analyticsType, CancellationToken cancellationToken = default)

// Get result for a specific payload (for polling after async submission)
Task<PayloadResultResponse> GetResultByPayloadIdAsync(Guid payloadId, CancellationToken cancellationToken = default)
Response Models
// Response from ingestion
public class IngestResponse
{
    public Guid PayloadId { get; set; }
    public string Status { get; set; }  // "pending"
}

// Response from single item update
public class ItemUpdateResponse
{
    public string Sku { get; set; }
    public string Status { get; set; }  // "upserted"
}

// Response from batch ingestion
public class BatchIngestionResponse
{
    public string SyncId { get; set; }
    public int BatchIndex { get; set; }
    public int TotalItemsInBatch { get; set; }
    public int SuccessfulCount { get; set; }
    public int FailedCount { get; set; }
    public List<FailedItem> FailedItems { get; set; }
    public SyncStatus SyncStatus { get; set; }
}

// Sync status information
public class SyncStatus
{
    public string Status { get; set; }         // "in-progress", "completed", "failed"
    public int TotalBatches { get; set; }
    public int ReceivedBatches { get; set; }
    public int TotalSuccessfulItems { get; set; }
    public int TotalFailedItems { get; set; }
    public bool IsComplete { get; set; }
    public DateTime? CompletedAt { get; set; }
}

// Failed item details
public class FailedItem
{
    public string Sku { get; set; }
    public string ErrorMessage { get; set; }
    public string ErrorType { get; set; }     // "validation", "processing", "conflict"
}

// Complete analytics result
public class AnalyticsResult
{
    public Guid ResultId { get; set; }
    public Guid PayloadId { get; set; }
    public string AnalyticsType { get; set; }
    public DateTime CreatedAt { get; set; }
    public string InputsSummary { get; set; }
    public string InstructionSet { get; set; }
    public string Provenance { get; set; }
    public List<MetricResult> Metrics { get; set; }
    public List<DirectiveResult> Directives { get; set; }
    public List<ObservationResult> Observations { get; set; }
}

// Polling response (can be complete or status)
public class PayloadResultResponse
{
    public bool IsComplete { get; set; }
    public AnalyticsResult? Result { get; set; }  // Available when IsComplete = true
    public string? Status { get; set; }            // "pending", "processing", "failed"
    public string? Error { get; set; }             // Available when Status = "failed"
}

Advanced Usage

Processing Patterns

The SDK supports three different processing patterns:

Pattern 1: Fire-and-Forget Ingestion

Submit payloads for async processing without waiting for results:

var response = await client.SubmitInventoryHealthAsync(payload);
// Store response.PayloadId for later retrieval if needed
Console.WriteLine($"Submitted: {response.PayloadId}");
Pattern 2: Synchronous Processing

Process immediately and get results:

// First ingest the payload
var ingestResponse = await client.SubmitInventoryHealthAsync(payload);

// Then immediately process the latest one
var result = await client.ProcessLatestAsync("InventoryHealth");

// Work with the result
foreach (var directive in result.Directives)
{
    Console.WriteLine($"{directive.Action}: {directive.Rationale}");
}
Pattern 3: Async with Polling

Submit for async processing and poll until complete:

var ingestResponse = await client.SubmitInventoryHealthAsync(payload);

// Poll for results
AnalyticsResult? result = null;
int attempts = 0;
while (result == null && attempts < 30)
{
    await Task.Delay(1000); // Wait 1 second
    
    var response = await client.GetResultByPayloadIdAsync(ingestResponse.PayloadId);
    
    if (response.IsComplete)
    {
        result = response.Result;
    }
    else if (response.Status == "failed")
    {
        throw new Exception($"Processing failed: {response.Error}");
    }
    
    attempts++;
}

Custom Analytics Types

For analytics types not included in the SDK, use the generic submission method:

public class CustomAnalyticsPayload : AnalyticsPayloadBase
{
    public string CustomField1 { get; set; }
    public int CustomField2 { get; set; }
}

var payload = new CustomAnalyticsPayload
{
    CustomField1 = "value",
    CustomField2 = 42
};

await client.SubmitAnalyticsAsync("CustomAnalyticsType", payload);

Examples: Supply Chain Analytics

CostOptimization Example:

var costOptPayload = new CostOptimizationPayload
{
    Sku = "WIDGET-A-100",
    ProductName = "Premium Widget A",
    UnitCost = 25.00m,
    HoldingCostPerUnit = 2.50m,
    OrderCost = 50m,
    AnnualDemand = 10000,
    MinOrderQty = 500,
    AvgLeadTimeDays = 14,
    CurrentStockLevel = 2500,
    BudgetCap = 100000m,
    PriorityLevel = "high",
    AlternativeSuppliers = new List<SupplierOption>
    {
        new SupplierOption
        {
            SupplierId = "SUP-CHINA-01",
            SupplierName = "China Manufacturing",
            UnitCost = 18.00m,
            AvgLeadTimeDays = 45,
            ReliabilityScore = 85m
        }
    }
};

var response = await client.SubmitCostOptimizationAsync(costOptPayload);
Console.WriteLine($"Cost optimization submitted: {response.PayloadId}");

DemandForecast Example:

var forecastPayload = new DemandForecastPayload
{
    Sku = "SEASONAL-ITEM-200",
    ProductName = "Holiday Decoration Package",
    HistoricalSales = new List<int> { 100, 150, 200, 350, 400, 350 }, // Last 6 months
    TimePeriod = "monthly",
    SeasonalityFactor = 2.5m, // 150% higher in peak season
    CurrentStockLevel = 500,
    ForecastPeriods = 12, // Forecast next 12 months
    TrendPercentage = 0.15m, // 15% growth trend
    PriorityLevel = "high"
};

var result = await client.ProcessLatestAsync(AnalyticsType.DemandForecast);
foreach (var directive in result.Directives.OrderBy(d => d.Priority))
{
    Console.WriteLine($"Action: {directive.Action}, Rationale: {directive.Rationale}");
}

Examples: E-Commerce Analytics

SalesFunnelConversion Example:

var funnelPayload = new SalesFunnelConversionPayload
{
    FunnelName = "Q1 2026 Sales Pipeline",
    Visitors = 50000,
    CartAdditions = 8000,
    CheckoutInitiations = 5000,
    CompletedOrders = 3500,
    TimePeriod = "monthly",
    AverageOrderValue = 75.50m,
    TotalRevenue = 264250m,
    TrafficSource = "organic",
    DeviceType = "mobile"
};

await client.SubmitSalesFunnelConversionAsync(funnelPayload);

CustomerLifetimeValue Example:

var cltPayload = new CustomerLifetimeValuePayload
{
    CustomerId = "CUST-12345",
    PurchaseCount = 24,
    AverageOrderValue = 125.00m,
    TotalSpent = 3000m,
    DaysSinceFirstPurchase = 365,
    AvgPurchaseFrequencyDays = 15,
    CustomerSegment = "VIP",
    IsActive = true,
    ChurnRiskScore = 15m, // Low risk
    AverageMarginPerOrder = 45.00m,
    PreferredCategories = new List<string> { "Electronics", "Software", "Accessories" },
    LastPurchaseDate = DateTime.UtcNow.AddDays(-7)
};

await client.SubmitCustomerLifetimeValueAsync(cltPayload);

Accessing Services Directly

// In a controller or service
public class MyController : ControllerBase
{
    private readonly DirectivSysClient _client;
    private readonly IDirectivSysService _service;

    public MyController(DirectivSysClient client, IDirectivSysService service)
    {
        _client = client;
        _service = service;
        
        // Set callback dynamically
        _service.OnDirectiveReceived = HandleDirective;
    }
}

Error Handling

try
{
    var response = await client.SubmitInventoryHealthAsync(payload);
}
catch (DirectivSysException ex)
{
    // Handle DirectivSys-specific errors
    Console.WriteLine($"DirectivSys error: {ex.Message}");
}
catch (HttpRequestException ex)
{
    // Handle network errors
    Console.WriteLine($"Network error: {ex.Message}");
}

Configuration Best Practices

Using Configuration Files

appsettings.json:

{
  "DirectivSys": {
    "ApiKey": "your-api-key",
    "BaseUrl": "https://api.directivsys.com",
    "TimeoutSeconds": 30
  }
}

Program.cs:

builder.Services.AddDirectivSys(options =>
{
    builder.Configuration.GetSection("DirectivSys").Bind(options);
});

Using Environment Variables

builder.Services.AddDirectivSys(options =>
{
    options.ApiKey = Environment.GetEnvironmentVariable("DIRECTIVSYS_API_KEY") 
        ?? throw new InvalidOperationException("DIRECTIVSYS_API_KEY not set");
});

Webhook Security

The SDK's webhook endpoint (/directivsys/webhook) validates incoming requests to ensure directives come directly from DirectivSys:

Automatic Validation:

  • Checks for X-API-Key: {your-api-key} header in every request
  • Verifies the API key matches your configured key
  • Validates payload can be deserialized to GlobalRecord
  • Returns 401 Unauthorized for invalid or missing keys
  • Returns 400 Bad Request for malformed payloads

Best Practices:

  1. Keep your API key secure - treat it like a password
  2. Never commit your API key to version control
  3. Use environment variables or secrets management (Azure Key Vault, AWS Secrets Manager, etc.)
  4. The webhook endpoint is automatically mapped and secured when you call app.MapDirectivWebhook()
  5. All webhook traffic uses HTTPS in production

Network Security:

  • Webhook endpoint only accepts POST requests
  • TLS 1.3 encryption for all data transmission
  • Request IP allowlisting available for enterprise customers (contact support)
  • Webhook timeout: configurable, default 30 seconds

Example: Complete Integration

using DirectivSys.Sdk.Extensions;
using DirectivSys.Sdk.Models;
using DirectivSys.Sdk.Models.Payloads;
using DirectivSys.Sdk.Services;

var builder = WebApplication.CreateBuilder(args);

// Configure DirectivSys
builder.Services.AddDirectivSys(options =>
{
    options.ApiKey = builder.Configuration["DirectivSys:ApiKey"]!;
});

// Add your services
builder.Services.AddControllers();
builder.Services.AddHostedService<InventoryAnalysisWorker>();

var app = builder.Build();

app.UseRouting();
app.MapControllers();
app.MapDirectivWebhook();

// Configure directive callback
var directivSys = app.GetDirectivSys();
directivSys.OnDirectiveReceived = record =>
{
    var logger = app.Services.GetRequiredService<ILogger<Program>>();
    logger.LogInformation("Received analytics: {Type} with {Count} directives",
        record.AnalyticsType, record.Directives.Count);

    foreach (var directive in record.Directives)
    {
        // Process each directive
        ProcessDirective(directive, app.Services);
    }
};

app.Run();

void ProcessDirective(Directive directive, IServiceProvider services)
{
    var scope = services.CreateScope();
    
    switch (directive.Action)
    {
        case "reorderSupplier":
            var inventoryService = scope.ServiceProvider.GetRequiredService<IInventoryService>();
            inventoryService.Reorder(directive.Parameters["sku"].ToString()!);
            break;
            
        case "launchPromotion":
            var marketingService = scope.ServiceProvider.GetRequiredService<IMarketingService>();
            marketingService.LaunchCampaign(directive.Targets);
            break;
    }
}

// Background worker to periodically submit analytics
public class InventoryAnalysisWorker : BackgroundService
{
    private readonly DirectivSysClient _client;
    private readonly ILogger<InventoryAnalysisWorker> _logger;

    public InventoryAnalysisWorker(DirectivSysClient client, ILogger<InventoryAnalysisWorker> logger)
    {
        _client = client;
        _logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
                // Aggregate your data
                var inventoryData = await GetCurrentInventoryAsync();
                
                // Submit to DirectivSys
                await _client.SubmitInventoryHealthAsync(inventoryData, stoppingToken);
                
                _logger.LogInformation("Inventory analysis submitted successfully");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to submit inventory analysis");
            }

            // Run daily
            await Task.Delay(TimeSpan.FromHours(24), stoppingToken);
        }
    }

    private async Task<InventoryHealthPayload> GetCurrentInventoryAsync()
    {
        // Your logic to aggregate inventory data
        return new InventoryHealthPayload
        {
            Sku = "SKU123",
            StockLevel = 45,
            ReorderPoint = 50,
            SafetyStock = 30,
            ForecastedDemandNext30Days = 200
        };
    }
}

Requirements

  • .NET 6.0 or higher
  • ASP.NET Core application (for webhook endpoint)

Support

For issues, questions, or feature requests, please visit:

Getting Help

  1. Check the documentation - Most questions are answered at https://docs.directivsys.com
  2. Review examples - See examples for common patterns
  3. Search GitHub issues - Your question may have been answered already
  4. Contact support - Email support@directivsys.com for enterprise support
  5. Community - Join our community chat at community.directivsys.com for peer support

License

This project is licensed under the MIT License - see the LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.


Made with ❀️ by DirectivSys Inc

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.9 115 4/21/2026
1.2.8 131 4/10/2026
1.2.7 119 3/14/2026
1.2.6 117 3/9/2026
1.2.5 104 3/9/2026
1.2.4 99 3/8/2026
1.2.3 102 3/7/2026
1.2.1 270 2/4/2026
1.2.0 148 2/2/2026
1.1.9 121 2/1/2026
1.1.8 120 2/1/2026
1.1.7 122 2/1/2026
1.1.6 126 1/31/2026
1.1.5 135 1/20/2026
1.1.4 114 1/20/2026
1.1.3 114 1/19/2026
1.1.2 125 1/19/2026
1.1.1 121 1/18/2026
1.1.0 120 1/10/2026
1.0.1 122 1/9/2026
Loading failed