People (cardholders) are the core entities in the acre Access Control system. Each person record can contain contact information, card assignments, access level permissions, badge types, custom metadata, and notes. This guide covers creating person records with all available properties and relationships.
| Property | Type | Description |
|---|---|---|
CommonName |
string | Unique identifier/display name (auto-generated if not provided) |
GivenName |
string | First name |
Surname |
string | Last name |
Addresses |
AddressInfo[] | Collection of phone, email, and mailing addresses |
CardAssignments |
CardAssignmentInfo[] | Assigned credentials/cards |
ObjectLinks |
ObjectLinkItem[] | Links to access levels, badge types, and other objects |
Links |
Link[] | General purpose links to external resources |
Metadata |
MetadataItem[] | Custom form data (JSON-based) |
Monikers |
MonikerItem[] | Unique identifiers for external system integration |
Notes |
NoteInfo[] | User notes attached to the person record |
Tags |
string[] | Searchable tags for categorization (must be lowercase, no spaces) |
| Address Type | Class | Key Properties |
|---|---|---|
| Phone | PhoneInfo | Number, Type (Work/Home/Mobile) |
| EmailAddressInfo | MailTo, Type (Work/Home) |
|
| Mailing | MailingAddressInfo | Street, City, Province, Country, PostalCode |
Before adding a person, you should have:
InstanceInfo context (Acquire Instance)AccessLevelInfo to assign permissionsThis example creates a person with all available properties populated:
// Create a comprehensive person record with all properties
var person = await client.AddPersonAsync(currentInstance, new PersonInfo
{
// Basic identification
CommonName = "JohnDoe", // Unique display name (system auto-generates key)
GivenName = "John",
Surname = "Doe",
// Contact information - multiple address types supported
Addresses = new AddressInfo[]
{
// Phone numbers with type classification
new PhoneInfo { Number = "847-691-0602", Type = "Work" },
new PhoneInfo { Number = "847-764-8989", Type = "Home" },
new PhoneInfo { Number = "847-999-2222", Type = "Mobile" },
// Email addresses
new EmailAddressInfo { MailTo = "work@email.com", Type = "Work" },
new EmailAddressInfo { MailTo = "home@email.com", Type = "Home" },
// Physical mailing address
new MailingAddressInfo
{
Street = "101 Champagne Ave",
City = "Ottawa",
Province = "ON",
Country = "CA",
PostalCode = "K1S4P3",
Type = "Home"
}
},
// Card/credential assignments
CardAssignments = new CardAssignmentInfo[]
{
new CardAssignmentInfo
{
DisplayCardNumber = "6564212356", // Human-readable card number
EncodedCardNumber = 6564212356, // Encoded value for card reader
ActiveOn = DateTime.UtcNow, // Card becomes active immediately
ExpiresOn = DateTime.UtcNow.AddYears(1), // Expires in one year
AntiPassbackExempt = false, // Subject to anti-passback rules
ExtendedAccess = false, // Normal door hold time
PinExempt = false, // Not exempt from PIN requirements
// PinCode = "1234" // Optional: For keypad readers (PIN only/Card+PIN/Card OR PIN modes)
}
},
// Custom metadata for integrations or custom forms
Metadata = new MetadataItem[]
{
new MetadataItem
{
Application = "HR_System", // Namespace for the application
Values = "{\"employeeId\":\"EMP001\",\"department\":\"Engineering\"}"
}
},
// External system identifiers
Monikers = new MonikerItem[]
{
new MonikerItem
{
Namespace = "ActiveDirectory", // External system name
Nickname = "jdoe@company.com" // Unique ID in that system
}
},
// Notes/comments attached to person
Notes = new NoteInfo[]
{
new NoteInfo
{
CreatedOn = DateTime.UtcNow,
NoteText = "New employee - requires safety training before lab access",
User = new ObjectLinkItem
{
CommonName = "AdminUser",
LinkedObjectKey = currentUser.Key,
Relation = "CreatedBy"
}
}
},
// Searchable tags - must be lowercase with no spaces
Tags = new string[] { "engineering", "building-a", "full-time" }
});
Console.WriteLine($"Created person: {person.CommonName} (Key: {person.Key})");
// Assign access level and badge type after creation
await client.AssignConnectedObjectAsync(person, accessLevel, "AccessLevel", false);
await client.AssignConnectedObjectAsync(person, badgeType, "BadgeType", false);
Console.WriteLine($"Assigned access level: {accessLevel.CommonName}");
Console.WriteLine($"Assigned badge type: {badgeType.CommonName}");
Create a basic person record and add relationships separately:
// Step 1: Create minimal person
var person = await client.AddPersonAsync(currentInstance, new PersonInfo
{
CommonName = "JaneDoe",
GivenName = "Jane",
Surname = "Doe"
});
// Step 2: Assign access level separately
await client.AssignConnectedObjectAsync(person, accessLevel, "AccessLevel", false);
// Step 3: Add card assignment separately
await client.AddCardAssignmentAsync(person, new CardAssignmentInfo
{
DisplayCardNumber = "12345",
EncodedCardNumber = 12345,
ActiveOn = DateTime.UtcNow,
ExpiresOn = DateTime.UtcNow.AddYears(1)
});
Organize people into folders for management:
// Get or create a folder for a department
var engineeringFolder = (await client.SearchAsync(currentInstance, "{\"_t\": \"Folder\", \"CommonName\":\"Engineering\"}"))
.OfType<FolderInfo>().FirstOrDefault();
// Create person in specific folder
var person = await client.AddPersonAsync(engineeringFolder, new PersonInfo
{
CommonName = "BobSmith",
GivenName = "Bob",
Surname = "Smith"
});
Custom forms allow storing application-specific data:
// Metadata must be JSON-formatted string
var customData = new
{
employeeId = "EMP12345",
costCenter = "CC-1001",
hireDate = "2024-01-15",
emergencyContact = new
{
name = "Jane Doe",
phone = "555-123-4567"
}
};
var person = await client.AddPersonAsync(currentInstance, new PersonInfo
{
CommonName = "NewEmployee",
GivenName = "New",
Surname = "Employee",
Metadata = new MetadataItem[]
{
new MetadataItem
{
Application = "HRIntegration", // Must match custom form name exactly
Values = JsonConvert.SerializeObject(customData)
}
}
});
Important: The
Applicationproperty must match a custom form configured in acre Access Control. Set up custom forms before adding metadata.
curl -X POST \
"https://api.us.acresecurity.cloud/api/f/INSTANCE_KEY/people" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"$type": "Feenics.Keep.WebApi.Model.PersonInfo, Feenics.Keep.WebApi.Model",
"CommonName": "JohnDoe",
"GivenName": "John",
"Surname": "Doe",
"Addresses": [
{
"$type": "Feenics.Keep.WebApi.Model.PhoneInfo, Feenics.Keep.WebApi.Model",
"Number": "847-691-0602",
"Type": "Work"
},
{
"$type": "Feenics.Keep.WebApi.Model.EmailAddressInfo, Feenics.Keep.WebApi.Model",
"MailTo": "john.doe@company.com",
"Type": "Work"
}
],
"Tags": ["engineering", "full-time"]
}'
curl -X POST \
"https://api.us.acresecurity.cloud/api/f/INSTANCE_KEY/people" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"$type": "Feenics.Keep.WebApi.Model.PersonInfo, Feenics.Keep.WebApi.Model",
"CommonName": "JaneDoe",
"GivenName": "Jane",
"Surname": "Doe"
}'
curl -X PUT \
"https://api.us.acresecurity.cloud/api/f/INSTANCE_KEY/people/PERSON_KEY/accesslevels/ACCESS_LEVEL_KEY" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
| Practice | Recommendation |
|---|---|
| CommonName | Use a consistent naming convention (e.g., LastName, FirstName or employee_id) |
| Card Numbers | Keep DisplayCardNumber and EncodedCardNumber synchronized for clarity |
| Expiration Dates | ExpiresOn for card assignments is required |
| Metadata | Store only essential data; large payloads impact performance |
| Monikers | Use for external system integration (SCIM, Active Directory sync) |
| Tags | Use consistent tag values for effective searching and reporting |
// Check for existing person by CommonName
var existing = (await client.SearchAsync(currentInstance, "{\"_t\": \"Person\", \"CommonName\":\"Doe, John\"}"))
.OfType<PersonInfo>().FirstOrDefault();
if (existing == null)
{
var person = await client.AddPersonAsync(currentInstance, new PersonInfo
{
CommonName = "JohnDoe",
GivenName = "John",
Surname = "Doe"
});
}
else
{
Console.WriteLine($"Person already exists: {existing.Key}");
}
// Search by external system identifier
var people = await client.SearchAsync(currentInstance, "{\"Monikers.Namespace\":\"ActiveDirectory\",\"Monikers.Nickname\":\"jdoe@company.com\"}");
var person = people.OfType<PersonInfo>().FirstOrDefault();
| Issue | Cause | Solution |
|---|---|---|
| Card not working | Person not linked to access level | Ensure ObjectLinks includes AccessLevel relationship |
| Metadata not saving | Invalid JSON | Validate JSON format before saving |
| Person not appearing | Wrong instance context | Verify currentInstance is correct target |