DirectivSys.Sdk
1.2.9
dotnet add package DirectivSys.Sdk --version 1.2.9
NuGet\Install-Package DirectivSys.Sdk -Version 1.2.9
<PackageReference Include="DirectivSys.Sdk" Version="1.2.9" />
<PackageVersion Include="DirectivSys.Sdk" Version="1.2.9" />
<PackageReference Include="DirectivSys.Sdk" />
paket add DirectivSys.Sdk --version 1.2.9
#r "nuget: DirectivSys.Sdk, 1.2.9"
#:package DirectivSys.Sdk@1.2.9
#addin nuget:?package=DirectivSys.Sdk&version=1.2.9
#tool nuget:?package=DirectivSys.Sdk&version=1.2.9
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.
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
ExecuteInternalAsynconce per directive. - On success, posts
Executedwith yourImpactData; on failure, postsFailedand 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:
- Your backend collects operational data - You decide what data to send
- This SDK packages and sends it to DirectivSys - Encrypted transmission via TLS 1.3
- DirectivSys analyzes the data - Using Claude Haiku 4.5, aggregated at the portfolio level
- Results come back via webhook - Delivered only to your endpoint
- 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:
- Login to your DirectivSys account - Access the client platform
- Go to Analytics Configuration - Set up analytics types you want to use
- Define Instructions - Tell the AI how to behave for your business
- Configure Directives - Define what actions the AI can recommend
- 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:
- Keep your API key secure - treat it like a password
- Never commit your API key to version control
- Use environment variables or secrets management (Azure Key Vault, AWS Secrets Manager, etc.)
- The webhook endpoint is automatically mapped and secured when you call
app.MapDirectivWebhook() - 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:
- Documentation: https://docs.directivsys.com
- GitHub Issues: https://github.com/directivsys/directivsys-sdk-dotnet/issues
- Status Page: https://status.directivsys.com
- Community Chat: https://community.directivsys.com
Getting Help
- Check the documentation - Most questions are answered at https://docs.directivsys.com
- Review examples - See examples for common patterns
- Search GitHub issues - Your question may have been answered already
- Contact support - Email support@directivsys.com for enterprise support
- 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 | Versions 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. |
-
net8.0
- Microsoft.Extensions.Http (>= 8.0.0)
- Polly (>= 8.3.1)
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 |