Use this Quick Start guide to step through the process of provisioning a Standard instance and performing common access control operations. This guide provides both C# and cURL examples so you can follow along in your preferred development environment.
What You’ll Build: A basic access control system with people, credentials, readers, and access levels
The guide will walk you through the following tasks:
Before you begin, ensure you have the following:
Developer Account: You should have received Credentials containing:
📧 Don’t have an account or credentials? Contact support@acresecurity.com or get in touch with your RSM
*.acresecurity.cloudLet’s configure your development environment to use the acre Access Control API. The setup process differs depending on whether you’re using C# (.NET) or cURL.
If you’re following the C# examples, you’ll need to add the acre Security NuGet package source.
acre Securityhttps://nuget-secure.feenics.com/nugetdotnet nuget add source https://nuget-secure.feenics.com/nuget --name "acre Security"
Create or edit NuGet.config in your project root:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="acre Security" value="https://nuget-secure.feenics.com/nuget" />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
</configuration>
mkdir AcreApiQuickStart
cd AcreApiQuickStart
dotnet new console
The acre Access Control API requires several NuGet packages. The wrapper library will automatically install most dependencies.
Install these packages using your preferred method:
Using Visual Studio:
Using .NET CLI:
# Install the acre API wrapper and model
dotnet add package Feenics.Keep.WebApi.Model.Standard
dotnet add package Feenics.Keep.WebApi.Wrapper.Standard
Using Package Manager Console:
Install-Package Feenics.Keep.WebApi.Model.Standard
Install-Package Feenics.Keep.WebApi.Wrapper.Standard
Core API Packages:
Dependencies (automatically installed):
Optional Packages (install only if needed):
Create a simple test to verify packages are installed correctly:
using Feenics.Keep.WebApi.Wrapper;
using Feenics.Keep.WebApi.Model;
using System;
class Program
{
static void Main(string[] args)
{
var client = new Client("https://api.us.acresecurity.cloud");
Console.WriteLine("✓ Packages installed successfully!");
Console.WriteLine($" Client initialized with base URL: {client.BaseUrl}");
}
}
Run the project to confirm:
dotnet run
Expected output:
✓ Packages installed successfully!
Client initialized with base URL: https://api.us.acresecurity.cloud
| Issue | Possible Cause | Solution |
|---|---|---|
| “Unable to load package source” | Network access blocked | Check firewall/proxy settings for nuget-secure.feenics.com |
| “Package not found” | Credentials not configured | Verify developer account is active, contact support |
| “Version conflict” errors | Incompatible .NET version | Ensure you’re using .NET 8.0 or later |
| “Unable to resolve dependency” | Missing nuget.org source | Add nuget.org as package source |
Before authenticating, let’s verify your workstation can reach the acre Access Control API servers. The /api/sysinfo endpoint is a public (unauthenticated) endpoint that provides system information.
Endpoint: GET https://api.us.acresecurity.cloud/api/sysinfo
Authentication: None required (public endpoint)
Purpose:
Response Fields:
ServerTime - Current UTC time on the server (useful for clock sync verification)Version - API version currently deployedServerId - Unique identifier of the specific server that handled your request$type - Full type name for deserializationusing Feenics.Keep.WebApi.Wrapper;
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
// Initialize the client with base URL and user agent
var client = new Client(
"https://api.us.acresecurity.cloud",
userAgent: "QuickStartApp/1.0"
);
Console.WriteLine("Connecting to acre Access Control API...");
// Get system information (no authentication required)
var sysInfo = await client.GetSysInfo();
Console.WriteLine("✓ Successfully connected to acre Access Control API");
Console.WriteLine($" Server Time (UTC): {sysInfo.ServerTime}");
Console.WriteLine($" API Version: {sysInfo.Version}");
Console.WriteLine($" Server ID: {sysInfo.ServerId}");
// Verify clock synchronization
var timeDiff = DateTime.UtcNow - sysInfo.ServerTime;
Console.WriteLine($" Clock Difference: {timeDiff.TotalSeconds:F1} seconds");
if (Math.Abs(timeDiff.TotalSeconds) > 300) // 5 minutes
{
Console.WriteLine(" ⚠️ WARNING: Local clock differs by more than 5 minutes!");
Console.WriteLine(" This may cause authentication issues.");
}
}
}
# Basic request
curl -s https://api.us.acresecurity.cloud/api/sysinfo
# With pretty-print formatting (requires jq)
curl -s https://api.us.acresecurity.cloud/api/sysinfo | jq .
# Alternative formatting with json_pp (usually pre-installed)
curl -s https://api.us.acresecurity.cloud/api/sysinfo | json_pp
{
"$type": "Feenics.Keep.WebApi.Model.SysInfo, Feenics.Keep.WebApi.Model",
"Version": "25.12.14.0",
"ServerId": "01e16dae017e4062a7d401cfe771dfc8",
"ServerTime": "2026-01-26T19:04:24.2101341Z",
"EventPublisherUrl": "wss://events.us.acresecurity.cloud",
"FitScriptEngineUrl": "fits.us.acresecurity.cloud",
"LicenseServerUrl": "licenseserver.us.acresecurity.cloud",
"UapBrokerUrl": "mqtt.us.acresecurity.cloud",
"FargoConnectApiUrl": "fargoconnect.us.acresecurity.cloud",
"AacClientUrl": null,
"GalleryIsEnabled": true,
"ReleaseNotes": [
{
"$type": "Feenics.Keep.WebApi.Model.ReleaseNote, Feenics.Keep.WebApi.Model",
"Name": "API",
"Url": "https://acre.my.site.com/knowledgearticles/s/article/acre-Access-Control-Release-Notes"
},
// Other links
]
}
The acre Access Control API runs on multiple servers behind a load balancer. Each request may be handled by a different server.
Run the cURL command multiple times and observe the ServerId field changing:
# Run 5 times and extract just the ServerId
for i in {1..5}; do
echo "Request $i:"
curl -s https://api.us.acresecurity.cloud/api/sysinfo | jq -r '.ServerId'
done
Expected behavior: You should see different ServerId values, confirming requests are distributed across multiple servers for high availability.
Throughout this guide, we’ll use the following example constants. Replace these with your actual values from your Developer Welcome Letter:
| Name | Example Value | Description |
|---|---|---|
| BaseAddress | https://api.us.acresecurity.cloud | The HTTPS endpoint of the acre Access Control service |
| InstanceName | QuickStart | Your instance name (case-sensitive) - find this in your welcome letter |
| Username | admin | Your administrator username |
| Password | adminpass | Your administrator password |
💡 Tip: Store these values as constants or environment variables in your application rather than hardcoding them.
acre Access Control uses OAuth 2.0 with JWT (JSON Web Tokens) for authentication. Understanding token management is crucial for building robust integrations.
┌─────────────┐ ┌──────────────┐
│ Your App │ │ acre API │
└──────┬──────┘ └──────┬───────┘
│ │
│ 1. POST /token (username + password) │
│─────────────────────────────────────────────────>│
│ │
│ 2. Returns: access_token + refresh_token │
│<─────────────────────────────────────────────────│
│ │
│ 3. Subsequent API calls with Bearer token │
│─────────────────────────────────────────────────>│
│ │
│ 4. Token expires after 24 hours │
│ │
│ 5. POST /token (refresh_token) │
│─────────────────────────────────────────────────>│
│ │
│ 6. Returns: new access_token + refresh_token │
│<─────────────────────────────────────────────────│
Authorization: Bearer <token> headerExample in C#
using Feenics.Keep.WebApi.Wrapper;
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
// Configuration - replace with your actual values
const string baseUrl = "https://api.us.acresecurity.cloud";
const string instanceName = "QuickStart"; // From your welcome letter
const string username = "admin"; // Your username
const string password = "your-password"; // Your password
// Create client with a descriptive user agent
var client = new Client(baseUrl, userAgent: "QuickStartApp/1.0");
Console.WriteLine($"Logging in to instance '{instanceName}'...");
// Attempt login - returns tuple with success status and error details
var (isLoggedIn, loginError, loginErrorMsg) = await client.LoginAsync(
instanceName,
username,
password
);
if (!isLoggedIn)
{
Console.WriteLine("❌ Login failed!");
Console.WriteLine($" Error Code: {loginError}");
Console.WriteLine($" Message: {loginErrorMsg}");
// Provide helpful troubleshooting tips
if (loginError?.Contains("invalid_grant") == true)
{
Console.WriteLine("\n💡 Tip: Check your username and password");
}
else if (loginError?.Contains("instance") == true)
{
Console.WriteLine("\n💡 Tip: Verify your instance name (case-sensitive)");
}
return; // Exit if login fails
}
Console.WriteLine("✓ Login successful!");
Console.WriteLine($" Instance: {instanceName}");
Console.WriteLine($" User: {username}");
// The access token is now stored in the client object
// and will be automatically included in all subsequent API calls
// Get current user information to verify authentication
var currentUser = await client.GetCurrentUserAsync();
Console.WriteLine($" User Key: {currentUser.Key}");
Console.WriteLine($" Full Name: {currentUser.CommonName}");
// Get current instance information
var currentInstance = await client.GetCurrentInstanceAsync();
Console.WriteLine($" Instance Key: {currentInstance.Key}");
}
}
Example in cURL
When using cURL, you need to manually manage tokens. Here’s how to login and store the token:
# Store your credentials as variables for security
INSTANCE="QuickStart"
USERNAME="admin"
PASSWORD="your-password"
# Request access token
curl -X POST https://api.us.acresecurity.cloud/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d "grant_type=password" \
-d "client_id=consoleApp" \
-d "client_secret=consoleSecret" \
-d "username=${USERNAME}" \
-d "password=${PASSWORD}" \
-d "instance=${INSTANCE}" \
-d "sendonetimepassword=false" \
| jq .
The above commands return JSON structured data like this:
{
"userName": "QuickStart\\admin",
"access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjhkY2U5YTA2YTg1NzEzNjMzYmI4NGMyN2EwZWQyNTY5IiwidHlwIjoiSl...",
"as:client_id": "consoleApp",
"token_type": "bearer",
"refresh_token": "18764039r94d936a710d8849",
"expires_in": 86399,
".issued": "Wed, 21 Jan 2026 21:08:09 GMT",
".expires": "Thu, 22 Jan 2026 21:08:08 GMT",
"instance": "54f2ca32bad37c2788b2827f"
}
Store the token for subsequent requests:
# Extract and save the access token to a variable
ACCESS_TOKEN=$(curl -s -X POST https://api.us.acresecurity.cloud/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d "grant_type=password&client_id=consoleApp&client_secret=consoleSecret&username=${USERNAME}&password=${PASSWORD}&instance=${INSTANCE}&sendonetimepassword=false" \
| jq -r '.access_token')
echo "Token obtained successfully"
echo "Token preview: ${ACCESS_TOKEN:0:50}..."
# Test the token with an authenticated request
curl -X GET https://api.us.acresecurity.cloud/api/ \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
| jq .
Access tokens expire after 24 hours. Instead of logging in again, use the refresh token to obtain a new access token.
Example in C#
var refreshSuccess = await client.RefreshAsync();
if (refreshSuccess)
{
Console.WriteLine("✓ Token refreshed successfully");
}
else
{
Console.WriteLine("❌ Token refresh failed - re-authentication required");
// Re-authenticate with username and password
await client.LoginAsync(instanceName, username, password);
}
Example in cURL
# Use the refresh token from the initial login response
REFRESH_TOKEN="abc123ABC123"
# Request a new access token
NEW_ACCESS_TOKEN=$(curl -s -X POST https://api.us.acresecurity.cloud/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d "grant_type=refresh_token" \
-d "client_id=consoleApp" \
-d "client_secret=consoleSecret" \
-d "refresh_token=${REFRESH_TOKEN}" \
| jq -r '.access_token')
echo "New token obtained: ${NEW_ACCESS_TOKEN:0:50}..."
It’s important to remember that HTTP is a stateless, connection-less protocol. Unlike persistent database connections (ODBC, JDBC), there is no maintained session with the API server.
How Authentication Works:
POST credentials to /token endpointAuthorization header of all subsequent requestsWith the C# Wrapper:
With cURL:
Authorization: Bearer <token> in every requestThe acre Access Control API returns specific error codes to help diagnose authentication issues. These errors are returned in the response body as JSON with error and error_description fields.
| Error Code | HTTP Status | Cause | Solution |
|---|---|---|---|
invalid_grant |
400 | Incorrect username or password, or SSO user attempting standard login | Verify credentials in your welcome letter. SSO users must use SSO authentication |
incorrect_password |
400 | Password is incorrect (Low security instances only) | Re-enter password. Check for caps lock |
incorrect_tfacode |
400 | Two-factor authentication code is incorrect | Re-enter the 6-digit code from your authenticator app |
user_notfound |
400 | Username does not exist (Low security instances only) | Verify username spelling and instance name |
user_disabled |
400 | User account has been disabled (Low/Medium security) | Contact your administrator to re-enable account |
user_lockedout |
400 | Account is locked after too many failed attempts (Low/Medium security) | Wait 15 minutes or contact support to unlock |
password_expired |
400 | User’s password has expired | Change password using newpassword parameter or contact admin |
new_password_required |
400 | User must change password on first login | Include newpassword parameter in login request |
one_time_password_required |
400 | User has two-factor authentication enabled | Include onetimepassword parameter with 6-digit code |
password_doesnot_meet_complexity_rule |
400 | New password doesn’t meet complexity requirements | Use mix of uppercase, lowercase, numbers, special characters |
password_doesnot_meet_minimum_length_rule |
400 | New password is too short | Use at least 8 characters (or instance minimum) |
instance_not_found |
400 | Instance name is incorrect or doesn’t exist | Verify instance name (case-sensitive) |
instance_disabled |
400 | Instance has been disabled | Contact acre Security support |
instance_missing_license |
400 | Instance does not have a valid license | Contact your administrator or acre Security support |
instance_license_tampered |
400 | Instance license signature is invalid | Contact acre Security support immediately |
instance_license_expired |
400 | Trial license has expired | Contact sales to upgrade to full license |
invalid_client |
400 | Wrong client_id or client_secret | Use consoleApp / consoleSecret as defaults |
unsupported_grant_type |
400 | Wrong grant_type parameter | Use password for login, refresh_token for refresh |
unauthorized |
401 | Missing or invalid token in API request | Check Authorization: Bearer <token> header format |
RefreshTokenTicketNotValid |
400 | Refresh token is invalid or expired | Re-authenticate with username and password |
The API adapts error messages based on your instance’s security level setting:
invalid_grant for most authentication failures to prevent user enumerationuser_disabled and user_lockedoutincorrect_password, user_notfound, and incorrect_tfacodeSecurity Note: High security instances intentionally provide less detailed error information to prevent attackers from determining which usernames exist in the system.
{
"error": "invalid_grant",
"error_description": "The email or password is incorrect"
}
If two-factor authentication is enabled for a user:
curl -X POST https://api.us.acresecurity.cloud/token \
-d "instance=QuickStart&username=admin&password=mypassword"
Response:
{
"error": "one_time_password_required",
"error_description": "User has two factor authentication turned on. Please authenticate with 'instance', 'username', 'password' and 'onetimepassword' values"
}
curl -X POST https://api.us.acresecurity.cloud/token \
-d "instance=QuickStart&username=admin&password=mypassword&sendonetimepassword=true"
curl -X POST https://api.us.acresecurity.cloud/token \
-d "instance=QuickStart&username=admin&password=mypassword&onetimepassword=123456"
| Symptom | Likely Cause | Action |
|---|---|---|
| Error on first login | Password change required | Include newpassword parameter |
| Error after password change | New password rejected | Check complexity and length requirements |
| Intermittent token errors | Token expiration | Implement token refresh logic |
| “SSO user must login using SSO” | Account configured for single sign-on | Use SSO authentication endpoint instead |
| Generic “invalid_grant” | High security instance | Check all credentials carefully; detailed errors are hidden |
| Connection timeout | Network/firewall issue | Verify outbound HTTPS access to *.acresecurity.cloud |
Now that you’re authenticated, you’re ready to configure your access control system. The following topics walk you through creating a complete working system:
Here’s a simplified example showing the typical flow from authentication to granting access:
// 1. Login
var client = new Client("https://api.us.acresecurity.cloud", userAgent: "MyApp/1.0");
await client.LoginAsync("QuickStart", "admin", "password");
// 2. Get current instance
var instance = await client.GetCurrentInstanceAsync();
// 3. Create an access level
var accessLevel = await client.AddAccessLevelAsync(instance, new AccessLevelInfo
{
CommonName = "Employee Access"
});
// 4. Create a schedule (weekdays 9-5)
var schedule = await client.AddScheduleAsync(instance, new ScheduleInfo
{
CommonName = "Business Hours",
// ... schedule details ...
});
// 5. Add a person
var person = await client.AddPersonAsync(instance, new PersonInfo
{
GivenName = "John",
Surname = "Doe",
CommonName = "JohnDoe"
});
// 6. Link person to access level
await client.AssignConnectedObjectAsync(person, accessLevel, "AccessLevel", false);
// 7. Assign a card
person.CardAssignments = new[]
{
new CardAssignmentInfo
{
EncodedCardNumber = 123456,
DisplayCardNumber = "123456",
ActiveOn = DateTime.UtcNow,
ExpiresOn = DateTime.UtcNow.AddYears(1)
}
};
await client.UpdatePersonAsync(person);
Console.WriteLine("✓ Person created and granted access!");
Congratulations! You’ve completed the Quick Start guide. You should now be able to:
✅ Set up your development environment with required packages
✅ Verify connectivity to the acre Access Control API
✅ Authenticate and manage tokens securely
✅ Understand the basic authentication flow
✅ Know where to find detailed documentation for next steps
What’s Next?
Start building your access control system by working through the Core Configuration guides listed above. Each guide provides detailed examples in both C# and cURL.
Happy coding! 🚀