Adding a New Person

Overview

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.


PersonInfo Properties Reference

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 Types

Address Type Class Key Properties
Phone PhoneInfo Number, Type (Work/Home/Mobile)
Email EmailAddressInfo MailTo, Type (Work/Home)
Mailing MailingAddressInfo Street, City, Province, Country, PostalCode

Prerequisites

Before adding a person, you should have:

  1. Working Instance - A valid InstanceInfo context (Acquire Instance)
  2. Access Level (optional) - Pre-created AccessLevelInfo to assign permissions
  3. Badge Type (optional) - Pre-created badge type for visual identification
  4. Card Format (optional) - If assigning cards, know your card format configuration

Creating a Person

Option 1: Complete Person with All Properties

This 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}");

Option 2: Minimal Person (Add Details Later)

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)
});

Adding a Person to a Specific Folder

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"
});

Working with Custom Metadata

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 Application property must match a custom form configured in acre Access Control. Set up custom forms before adding metadata.


cURL Examples

Create Person with Full Details

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"]
  }'

Create Minimal Person

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"
  }'

Assign Access Level After Creation

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"

Best Practices

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

Common Patterns

Check if Person Exists Before Creating

// 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}");
}

Find Person by Moniker (External ID)

// 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();

Troubleshooting

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