Yllibed.TenantCloudClient
3.0.19-dev
See the version list below for details.
dotnet add package Yllibed.TenantCloudClient --version 3.0.19-dev
NuGet\Install-Package Yllibed.TenantCloudClient -Version 3.0.19-dev
<PackageReference Include="Yllibed.TenantCloudClient" Version="3.0.19-dev" />
<PackageVersion Include="Yllibed.TenantCloudClient" Version="3.0.19-dev" />
<PackageReference Include="Yllibed.TenantCloudClient" />
paket add Yllibed.TenantCloudClient --version 3.0.19-dev
#r "nuget: Yllibed.TenantCloudClient, 3.0.19-dev"
#:package Yllibed.TenantCloudClient@3.0.19-dev
#addin nuget:?package=Yllibed.TenantCloudClient&version=3.0.19-dev&prerelease
#tool nuget:?package=Yllibed.TenantCloudClient&version=3.0.19-dev&prerelease
Yllibed.TenantCloudClient
Unofficial .NET client library for TenantCloud, a rental property management platform.
This is not an official TenantCloud product. TenantCloud does not provide a public API; this library works against their internal endpoints.
Packages
| Package | Description |
|---|---|
Yllibed.TenantCloudClient |
Core library: API client, token store abstractions, and OS-native secure storage |
Yllibed.TenantCloudClient.Cdp |
Chrome DevTools Protocol token provider (extracts tokens from a running browser) |
Both packages target net8.0 and net10.0 with no external runtime dependencies beyond System.Text.Json and Microsoft.Extensions.DependencyInjection.Abstractions.
Quick start
With dependency injection
services
.AddSecureTokenStore() // ITcTokenStore → OS credential store
.AddCdpTokenProvider() // ITcAuthTokenProvider → browser extraction + auto-refresh
.AddTenantCloudClient(); // ITcClient → TcClient
Then inject ITcClient wherever you need it:
public class MyService(ITcClient tc)
{
public async Task<TcUserInfo?> WhoAmI(CancellationToken ct)
=> await tc.GetUserInfo(ct);
}
Without dependency injection
var tokenStore = new SecureTokenStore();
var tokenProvider = new CdpTokenProvider(new CdpTokenProviderOptions
{
TokenStore = tokenStore,
AllowInteractiveLogin = true,
});
using var client = new TcClient(tokenProvider);
var user = await client.GetUserInfo(ct);
Authentication
TcClient requires an ITcAuthTokenProvider to supply Bearer tokens. The library does not store or manage credentials directly.
public interface ITcAuthTokenProvider
{
Task<string?> GetToken(CancellationToken ct);
Task OnTokenRejected(CancellationToken ct, string rejectedToken);
}
Built-in: CdpTokenProvider
Provided by the Yllibed.TenantCloudClient.Cdp package. Extracts auth tokens from a running Chromium browser via the Chrome DevTools Protocol, with automatic JWT refresh.
services.AddCdpTokenProvider(options =>
{
options.DebugPort = 9222; // CDP debug port (default)
options.AllowInteractiveLogin = true; // launch a browser if no session found
});
The provider follows a multi-step strategy:
- In-memory cache (if the JWT is still valid)
- Token store (load + refresh if expired)
- CDP extraction from an existing browser tab on
app.tenantcloud.com - Interactive login (if
AllowInteractiveLoginis enabled) — launches a browser window and waits for the user to sign in
Custom provider
Implement ITcAuthTokenProvider and register it before calling AddTenantCloudClient():
services.AddSingleton<ITcAuthTokenProvider, MyCustomTokenProvider>();
services.AddTenantCloudClient();
Token persistence
ITcTokenStore allows tokens to survive across process restarts. Both the core library and the CDP provider can use it.
public interface ITcTokenStore
{
Task<TcTokenSet?> LoadAsync(CancellationToken ct);
Task SaveAsync(TcTokenSet tokens, CancellationToken ct);
}
Built-in stores
| Store | Package | Description |
|---|---|---|
SecureTokenStore |
Core | OS-native credential storage: DPAPI (Windows), Keychain (macOS), Secret Service (Linux) |
FileTokenStore |
Cdp | Plain JSON file with atomic writes (useful for headless/CI scenarios) |
// OS-native secure storage (recommended)
services.AddSecureTokenStore();
// With custom options
services.AddSecureTokenStore(options =>
{
options.ServiceName = "MyApp";
options.AccountKey = "production";
});
// Or file-based (from the Cdp package, register manually)
services.AddSingleton<ITcTokenStore>(new FileTokenStore("/path/to/tokens.json"));
Custom store
Implement ITcTokenStore to persist tokens wherever you need (database, Azure Key Vault, etc.):
services.AddSingleton<ITcTokenStore, MyDatabaseTokenStore>();
API reference
ITcClient
| Member | Type | Description |
|---|---|---|
GetUserInfo(ct) |
Task<TcUserInfo?> |
Current signed-in user info |
Contacts |
IPaginatedSource<TcContact> |
Contacts (tenants, professionals) |
Properties |
IPaginatedSource<TcProperty> |
Properties |
Units |
IPaginatedSource<TcUnit> |
Rental units |
Transactions |
IPaginatedSource<TcTransaction> |
Financial transactions |
Leases |
IPaginatedSource<TcLease> |
Leases |
Paginated sources
Each collection is an IPaginatedSource<T>. Call .GetAll(ct) to fetch all pages, or .GetAll(ct, maxResults: n) to cap the fetch:
var contacts = await client.Contacts.OnlyMovedIn().GetAll(ct);
The result is a ReadOnlySequence<T> (one segment per API page). Use .AsEnumerable() to bridge to LINQ:
var names = (await client.Contacts.GetAll(ct))
.AsEnumerable()
.Select(c => c.Name)
.ToArray();
Filters
Filters are chainable extension methods that narrow the API query before fetching.
Contacts
.OnlyTenants()— tenant contacts only.OnlyMovedIn()— tenants with active leases.OnlyProfessionals()— professional contacts only.OnlyArchived()— archived contacts
Leases
.OnlyActive()— active leases.ForProperty(propertyId)— filter by property.ForUnit(unitId)— filter by unit
Units
.OnlyOccuped()— units with active leases.OnlyVacant()— vacant units.ForProperty(propertyId)— filter by property
Transactions
.ForTenant(tenantId)— filter by tenant.ForProperty(propertyId)— filter by property.ForUnit(unitId)— filter by unit.ForStatus(TcTransactionStatus)— filter by status (Due,Paid,Partial,Pending,Void,WithBalance,Overdue,Waive).ForCategory(TcTransactionCategory)— filter by category (Income,Expense,Refund,Credits,Liability).SortByDateDescending()— reverse chronological order
Example: overdue income per property
var balancePerProperty = (await client.Transactions
.ForCategory(TcTransactionCategory.Income)
.ForStatus(TcTransactionStatus.WithBalance)
.GetAll(ct))
.AsEnumerable()
.Where(t => t.PropertyId != null)
.GroupBy(t => (long)t.PropertyId!, t => t.Balance)
.Select(g => new { PropertyId = g.Key, Balance = g.Sum() })
.ToArray();
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
-
net8.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.4)
- System.Text.Json (>= 9.0.4)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Yllibed.TenantCloudClient:
| Package | Downloads |
|---|---|
|
Yllibed.TenantCloudClient.Cdp
Chrome DevTools Protocol (CDP) based token provider for Yllibed.TenantCloudClient. Extracts auth tokens from an existing browser session — no external NuGet dependencies. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 3.0.41-dev | 87 | 2/16/2026 |
| 3.0.40-dev | 84 | 2/16/2026 |
| 3.0.39-dev | 90 | 2/16/2026 |
| 3.0.20-dev | 82 | 2/16/2026 |
| 3.0.19-dev | 82 | 2/16/2026 |
| 3.0.18-dev | 86 | 2/16/2026 |
| 2.1.0 | 715 | 12/7/2020 |
| 2.1.0-dev.6 | 425 | 11/16/2020 |
| 2.1.0-dev.4 | 371 | 12/7/2020 |
| 2.1.0-dev.3 | 362 | 11/21/2020 |
| 2.1.0-dev.1 | 397 | 11/16/2020 |
| 2.0.0 | 696 | 11/16/2020 |
| 2.0.0-dev.36 | 363 | 11/16/2020 |
| 2.0.0-dev.35 | 353 | 11/16/2020 |
| 2.0.0-dev.33 | 405 | 11/5/2020 |
| 1.0.0-dev.21 | 483 | 6/5/2019 |
| 1.0.0-dev.20 | 484 | 6/5/2019 |
| 1.0.0-dev.18 | 472 | 6/3/2019 |
| 1.0.0-dev.16 | 483 | 6/2/2019 |
| 1.0.0-dev.15 | 476 | 6/2/2019 |