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.
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 |
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 (...)
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" } }
]
}
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}");
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\"}"'
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 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);
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:
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 is not directly supported via the API. The workflow is:
Tip: Plan your instance structure carefully before deploying hardware and creating cardholders.
Standard Instance (Headquarters)
├── Controllers
├── Readers
├── People
├── Access Levels
└── Schedules
Best for: Small to medium businesses with one location.
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.
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.
| 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 |
Cause: Attempting to link objects from different instances.
Solution: Verify all objects are in the same instance using their InFolderKey property.
Cause: The instance name in your login credentials doesn’t match any instance.
Solution: Verify the FullyQualifiedDomainName is correct (case-sensitive).
Cause: Attempting to move an instance to a non-VAR parent.
Solution: Only VAR instances can have child instances created or moved to them.