Card assignments represent physical credentials (access cards, key fobs, mobile credentials) issued to people. This guide shows you how to assign, manage, and troubleshoot card assignments.
A card assignment links a physical or virtual credential to a person in the system. The card number is what readers recognize when a cardholder presents their credential.
| Property | Description | Required |
|---|---|---|
EncodedCardNumber |
The binary number stored on the card | ✅ Yes |
DisplayCardNumber |
Human-readable card number (usually same as encoded) | ✅ Yes |
ActiveOn |
Date when card becomes valid | ✅ Yes |
ExpiresOn |
Date when card expires | ✅ Yes |
PinCode |
PIN code for keypad readers (enables PIN-based entry modes) | ❌ No |
AntiPassbackExempt |
Bypass anti-passback rules | ❌ No |
ExtendedAccess |
Allow extended door hold time | ❌ No |
IsDisabled |
Temporarily disable the card | ❌ No |
⚠️ Cards are not Deleted: Once a card is entered into the system, it is not hard deleted by default—only disabled or reassigned. This maintains audit trail integrity. Optionally, you may enable the CleanExpiredCards option in InstanceSettings to hard delete after 30 days of a card’s expiration. 💡 Card Numbers Must Be Unique: Each active
EncodedCardNumbercan only be assigned to one person at a time.
// Assign a card with known card number
var cardAssignment = await client.AddCardAssignmentAsync(person, new CardAssignmentInfo
{
DisplayCardNumber = "12345678",
EncodedCardNumber = 12345678,
ActiveOn = DateTime.UtcNow,
ExpiresOn = DateTime.UtcNow.AddYears(1),
AntiPassbackExempt = false,
ExtendedAccess = false
});
Console.WriteLine($"Card {cardAssignment.DisplayCardNumber} assigned to {person.CommonName}");
Console.WriteLine($"Valid: {cardAssignment.ActiveOn:d} to {cardAssignment.ExpiresOn:d}");
curl -X POST \
https://api.us.acresecurity.cloud/api/f/INSTANCE_KEY/people/PERSON_KEY/cards \
-H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"$type": "Feenics.Keep.WebApi.Model.CardAssignmentInfo, Feenics.Keep.WebApi.Model",
"EncodedCardNumber": 12345678,
"DisplayCardNumber": "12345678",
"ActiveOn": "2024-01-01T00:00:00Z",
"ExpiresOn": "2025-01-01T00:00:00Z",
"AntiPassbackExempt": false,
"ExtendedAccess": false,
"IsDisabled": false
}'
For readers with keypads, you can assign a PIN code to enable PIN-based authentication. Readers may be configured to accept:
var cardAssignment = await client.AddCardAssignmentAsync(person, new CardAssignmentInfo
{
DisplayCardNumber = "12345678",
EncodedCardNumber = 12345678,
PinCode = "1234", // 4-digit PIN for keypad readers
ActiveOn = DateTime.UtcNow,
ExpiresOn = DateTime.UtcNow.AddYears(1)
});
Console.WriteLine($"Card with PIN assigned. PIN: {cardAssignment.PinCode}");
⚠️ PIN Uniqueness: PIN codes must be unique within an instance unless overwritten via InstanceSettings. Use
GetRandomPinAsyncto help with uniqueness. 💡 Reader Configuration: The reader’s configuration determines which entry mode(s) are allowed (PIN only, card only, card+PIN, or card/PIN).
You can include card assignments when creating a new person.
var person = await client.AddPersonAsync(currentInstance, new PersonInfo
{
CommonName = "Jane Smith",
GivenName = "Jane",
Surname = "Smith",
CardAssignments = new CardAssignmentInfo[]
{
new CardAssignmentInfo
{
DisplayCardNumber = "87654321",
EncodedCardNumber = 87654321,
ActiveOn = DateTime.UtcNow,
ExpiresOn = DateTime.UtcNow.AddYears(2)
}
}
});
Console.WriteLine($"Created {person.CommonName} with card {person.CardAssignments[0].DisplayCardNumber}");
var person = (await client.SearchAsync(currentInstance, $"{{\\"_t\\":\\"Person\\",\\"_id\\":\\"{personKey}\\"}}"))
.OfType<PersonInfo>().FirstOrDefault();
foreach (var card in person.CardAssignments)
{
var status = card.IsDisabled ? "DISABLED" :
(card.ExpiresOn < DateTime.UtcNow ? "EXPIRED" : "ACTIVE");
Console.WriteLine($"Card: {card.DisplayCardNumber} - {status}");
Console.WriteLine($" Valid: {card.ActiveOn:d} to {card.ExpiresOn:d}");
}
// Find the card assignment
var person = (await client.SearchAsync(currentInstance, $"{{\\"_t\\":\\"Person\\",\\"_id\\":\\"{personKey}\\"}}"))
.OfType<PersonInfo>().FirstOrDefault();
var card = person.CardAssignments.FirstOrDefault(c => c.DisplayCardNumber == "12345678");
if (card != null)
{
card.IsDisabled = true;
await client.UpdateCardAssignmentAsync(person, card);
Console.WriteLine($"Card {card.DisplayCardNumber} has been disabled");
}
var card = person.CardAssignments.First();
card.ExpiresOn = DateTime.UtcNow.AddYears(1); // Extend by 1 year
await client.UpdateCardAssignmentAsync(person, card);
Console.WriteLine($"Card expiration extended to {card.ExpiresOn:d}");
For updating many cards at once, use the bulk operations for better performance.
// Extend all cards expiring in 30 days by 1 year
var result = await client.ExtendCardExpiry(
currentInstance,
expiresBefore: DateTime.UtcNow.AddDays(30),
expiresAfter: DateTime.UtcNow,
newExpiresOn: DateTime.UtcNow.AddYears(1),
trialRun: false
);
Console.WriteLine($"Extended {result.CardsUpdated} cards");
See Bulk Card Operations for complete documentation.
Grant extra time for people who need longer door hold times (accessibility accommodation).
var card = new CardAssignmentInfo
{
DisplayCardNumber = "11111111",
EncodedCardNumber = 11111111,
ExtendedAccess = true, // Door stays open longer
ActiveOn = DateTime.UtcNow,
ExpiresOn = DateTime.UtcNow.AddYears(1)
};
Bypass anti-passback rules for managers or maintenance staff.
var card = new CardAssignmentInfo
{
DisplayCardNumber = "22222222",
EncodedCardNumber = 22222222,
AntiPassbackExempt = true, // Can badge in multiple times
ActiveOn = DateTime.UtcNow,
ExpiresOn = DateTime.UtcNow.AddYears(1)
};
Restrict the number of times a card can be used (visitor passes).
var card = new CardAssignmentInfo
{
DisplayCardNumber = "VISITOR001",
EncodedCardNumber = 99999001,
OriginalUseCount = 10, // Maximum 10 uses
CurrentUseCount = 0,
ActiveOn = DateTime.UtcNow,
ExpiresOn = DateTime.UtcNow.AddDays(1)
};
| Practice | Recommendation |
|---|---|
| Validate Card Numbers | Ensure encoded number matches card format |
| Use Display Numbers | Make display number human-readable if required |
| Track Card History | Use events to audit card usage |
| Disable, Don’t Delete | Disable lost cards immediately, can re-active if found later |
| Issue | Cause | Solution |
|---|---|---|
CardIsAlreadyAssigned |
Card number in use by another person | Disable old assignment first |
DuplicatePinCode |
PIN already exists | Use GetRandomPinAsync for unique PIN |
| Card not working | Card disabled or expired | Check IsDisabled and ExpiresOn |