Instances

Instances are the foundation of acre Access Control’s multi-tenant architecture. They provide complete data isolation, security boundaries, and organizational structure for managing access control across one or multiple organizations.

Key Concept: Every object in acre Access Control—people, controllers, access levels, events—belongs to exactly one instance. Objects that need to work together must be in the same instance.


Instance Types

acre Access Control offers four instance types, each designed for different organizational needs and are designated based on licensing:

Type Purpose Typical Use Case Key Restrictions
VAR Value Added Reseller Security integrators managing multiple customers Created by acre; parent of customer instances; Should NOT include Hardware
Enterprise Large organizations National/international companies No restrictions; can have child Shared instances
Standard Local organizations Single-site or regional businesses Max 255 schedules; single region
Shared Geographic distribution Enterprise data in specific regions Must be child of Enterprise instance

Instance Hierarchy

Instances form a hierarchical tree structure. VAR instances can be nested to support multi-tier partner/reseller models:

acre Root
└── VAR Instance (Top-Level Reseller)
    ├── VAR Instance (Regional Partner A)
    │   ├── Enterprise Instance (Large Customer)
    │   │   ├── Shared Instance (Americas)
    │   │   │   ├── Controllers, Readers, People...
    │   │   │   └── Events, Access Levels...
    │   │   ├── Shared Instance (Europe)
    │   │   │   └── ...
    │   │   └── Shared Instance (Asia Pacific)
    │   │       └── ...
    │   ├── Standard Instance (Small Customer A)
    │   │   └── Controllers, Readers, People...
    │   └── Standard Instance (Small Customer B)
    │       └── ...
    └── VAR Instance (Regional Partner B)
        ├── Enterprise Instance (...)
        └── Standard Instance (...)

Why Instance Hierarchy Matters

  1. Data Isolation - Each instance is completely isolated; Customer A cannot see Customer B’s data
  2. Search Scope - You can search within an instance or include child instances
  3. Permission Inheritance - Administrative access can cascade down the hierarchy
  4. Administrative Compliance - Shared instances enable specific data access requirements

Working with Instances

Getting the Current Instance

After authentication, get your current instance context:

using Feenics.Keep.WebApi.Wrapper;

var client = new Client("https://api.us.acresecurity.cloud", userAgent: "myAppName/myAppVersion.0.0");
var (isLoggedIn, error, errorMsg) = await client.LoginAsync("myinstance", "username", "password");

if (isLoggedIn)
{
    // Get the instance you authenticated to
    var currentInstance = await client.GetCurrentInstanceAsync();
    Console.WriteLine($"Instance: {currentInstance.CommonName}");
    Console.WriteLine($"Domain: {currentInstance.FullyQualifiedDomainName}");
    Console.WriteLine($"Key: {currentInstance.Key}");
}

cURL:

# Get current instance (after authentication)
curl -X GET 'https://api.us.acresecurity.cloud/api' \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "UserAgent: myAppName/myAppVersion.0.0"

Response:

{
  "$type": "Feenics.Keep.WebApi.Model.InstanceInfo, Feenics.Keep.WebApi.Model",
  "FullyQualifiedDomainName": "myinstance",
  "CommonName": "My Organization",
  "Key": "5abde6c5d3aa1601458194a0",
  "Href": "/api/f/5abde6c5d3aa1601458194a0",
  "Links": [
    { "Relation": "People", "Anchor": { "Href": "people" } },
    { "Relation": "Controllers", "Anchor": { "Href": "controllers" } }
  ]
}

Creating a Customer Instance (VAR Workflow)

VAR instances can create child instances for customers:

// First, authenticate to your VAR instance
var client = new Client("https://api.us.acresecurity.cloud", userAgent: "myAppName/myAppVersion.0.0");
await client.LoginAsync("myvar", "admin", "password");

var varInstance = await client.GetCurrentInstanceAsync();

// Create a new Standard instance for a customer
var newInstance = new InstanceInfo
{
    CommonName = "Acme Corporation",
    FullyQualifiedDomainName = "acmecorp"  // Must be unique globally
};

// Parent instance is specified as first parameter
var createdInstance = await client.AddInstanceAsync(varInstance, newInstance, isSharedInstance: false);
Console.WriteLine($"Created instance: {createdInstance.Key}");

Searching Across Child Instances

When searching, you can include child instances in results:

// Search for people across all child instances
var searchResults = await client.SearchAsync(
    varInstance,
    "{\"_t\":\"Person\"}",
    includeChildFolders: true,  // Include all descendants
    page: 0,
    pageSize: 100
);

foreach (var person in searchResults.OfType<PersonInfo>())
{
    Console.WriteLine($"{person.CommonName} - Instance: {person.InFolderKey}");
}

cURL:

curl -X POST 'https://api.us.acresecurity.cloud/api/f/INSTANCE_KEY/search?includeChildFolders=true' \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -H "UserAgent: myAppName/myAppVersion.0.0" \
  -d '"{\"_t\": \"Person\"}"'

Instance Configuration

Instance Settings

InstanceSettingsInfo controls various operational settings for the instance:

var currentInstance = await client.GetCurrentInstanceAsync();
var settings = await client.GetInstanceSettingsAsync(currentInstance);

// Security and capacity settings
settings.SecurityLevel = SecurityLevels.High;
settings.MaxCardHolders = 5000;
settings.MaxAccessLevels = 200;

// PIN configuration
settings.PinLength = 6;
settings.PinAllowSequentialDigits = false;
settings.AllowDuplicatePins = false;

// Muster settings
settings.ClearMusterIsActive = true;
settings.ClearMusterTimeInMinutes = 600;  // Clear muster at 10 hours
settings.IndividualCleardownIsActive = true;
settings.IndividualCleardownLengthHours = 12;

// Card management
settings.CleanExpiredCards = true;

// Session settings
settings.SessionTimeoutMinutes = 30;

await client.UpdateInstanceSettingsAsync(currentInstance, settings);

Password Policy

Password requirements and account lockout settings are configured through the PasswordPolicy property of InstanceInfo:

var currentInstance = await client.GetCurrentInstanceAsync();

// Configure password complexity requirements
currentInstance.PasswordPolicy = new PasswordPolicy
{
    MinimumPasswordLength = 8,
    PasswordComplexity = PasswordComplexity.RequireUpperCase | 
                        PasswordComplexity.RequireLowerCase | 
                        PasswordComplexity.RequireNumber | 
                        PasswordComplexity.RequireSpecial,
    MaximumFailedAttempts = 5,
    LockoutDuration = TimeSpan.FromMinutes(15),
    ForcePasswordChangeSpan = TimeSpan.FromDays(90),
    PasswordHistoryTimeToKeep = TimeSpan.FromDays(365)
};

await client.UpdateInstanceAsync(currentInstance);

Enterprise and Shared Instance Pattern

For large organizations requiring geographic or access based data distribution:

// Create Enterprise instance (parent)
var enterprise = new InstanceInfo
{
    CommonName = "Global Manufacturing Corp",
    FullyQualifiedDomainName = "globalmfg"
};
// isSharedInstance = false creates a standard/enterprise instance
var createdEnterprise = await client.AddInstanceAsync(varInstance, enterprise, isSharedInstance: false);

// instance must now be licensed as an ENTERPRISE

// Create Shared instances for each region
var regions = new[] { "Americas", "Europe", "AsiaPacific" };
foreach (var region in regions)
{
    var shared = new InstanceInfo
    {
        CommonName = $"Global Mfg - {region}",
        FullyQualifiedDomainName = $"globalmfg-{region.ToLower()}"
    };
    // isSharedInstance = true creates a shared instance
    await client.AddInstanceAsync(createdEnterprise, shared, isSharedInstance: true);
}

Why Use This Pattern:

  • Data Organization: Keep data separated by location or site.
  • Performance: Controllers connect to regional services
  • Management: Enterprise admins see all regions; regional admins see only their region

Critical Rules

⚠️ Cross-Instance Operations Are Not Allowed

Objects in different instances cannot be linked together:

Solution: Ensure all connected objects are in the same instance before creating relationships.


Moving Objects Between Instances

Moving objects between instances is not directly supported via the API. The workflow is:

  1. Export the object data manually.
  2. Delete from source instance
  3. Create new in target instance
  4. Update all references

Tip: Plan your instance structure carefully before deploying hardware and creating cardholders.


Common Patterns

Pattern 1: Single-Site Deployment

Standard Instance (Headquarters)
├── Controllers
├── Readers  
├── People
├── Access Levels
└── Schedules

Best for: Small to medium businesses with one location.


Pattern 2: Multi-Site, Single Organization

Enterprise Instance (Corporate)
├── People, Users, AlarmDefinitions...
├── Shared Instance (Building A)
│   ├── Controllers, Readers, AccessLevels, Schedules, Users...
├── Shared Instance (Building B)
│   ├── Controllers, Readers, AccessLevels, Schedules, Users...
└── Shared Instance (Building C)
    ├── Controllers, Readers, AccessLevels, Schedules, Users...

Best for: Organizations with multiple locations needing centralized management.


Pattern 3: Managed Services Provider

VAR Instance (MSP)
├── Standard Instance (Customer A)
├── Standard Instance (Customer B)
└── Enterprise Instance (Large Customer C)
    ├── Shared Instance (Region 1)
    └── Shared Instance (Region 2)

Best for: Security integrators managing multiple independent customers.


API Reference

Method Description
GetCurrentInstanceAsync() Get the instance you authenticated to
CreateInstanceAsync() Create a new child instance
SearchAsync(..., "{\"_t\":\"Instance\"}", includeChildFolders: true) List all child instances
GetInstanceSettingsAsync() Get instance configuration
UpdateInstanceSettingsAsync() Update instance settings
SearchAsync(..., includeChildFolders: true) Search across instance hierarchy

Troubleshooting

“Unable To Scope Object To Instance”

Cause: Attempting to link objects from different instances.

Solution: Verify all objects are in the same instance using their InFolderKey property.

“Instance Does Not Exist”

Cause: The instance name in your login credentials doesn’t match any instance.

Solution: Verify the FullyQualifiedDomainName is correct (case-sensitive).

“Cannot Move Instance To Non Var Instance”

Cause: Attempting to move an instance to a non-VAR parent.

Solution: Only VAR instances can have child instances created or moved to them.


Next Steps