Feature Overrides & Configuration API
Feature Overrides & Configuration API
Agencies can control portal behaviour per client using feature flags sourced from the AgentOS API. These overrides are fetched at runtime — no code changes or deployments required to toggle portal sections on or off.
Overview
The Feature Overrides system has two levels of configuration:
- Company-level overrides — apply to all portal users of a given agency
- Person-level overrides — apply to a specific person (currently scoped to FixFlo URL routing)
Flags default to false (disabled) when not set or when the API returns an error. The portal never blocks a user due to a flag resolution failure.
Known Feature Flags
| Flag | Type | Effect |
|---|---|---|
RemoveContactButtons | boolean | Hides contact/call buttons across the portal |
RemoveMaintenanceJobs | boolean | Hides the maintenance jobs section for tenants and landlords |
RemoveAffiliateLinks | boolean | Hides affiliate link sections |
ReplacePhotoPlaceholder | boolean | Replaces generic photo placeholders with a branded alternative |
RemoveViewings | boolean | Hides the viewings section |
RemovePropertyFeedback | boolean | Hides property feedback |
RemovePropertyRoomCounts | boolean | Hides room count information on property listings |
RemoveTenantCerts | boolean | Hides tenant certificate sections |
Additional dynamic flags returned by the AgentOS API are preserved in a raw field and are not discarded.
FixFlo Priority Chain
The effective FixFlo maintenance URL is resolved using the following priority order:
Company FixfloOverrideUrl → Person FixFlo Override → null
(highest priority) (no override)
The resolved result includes a fixfloSource field indicating which level supplied the URL:
"company"— the company-levelFixfloOverrideUrlwas used"person"— the person-level FixFlo override was used"none"— no FixFlo override is configured
tRPC API
Feature overrides are exposed via the featureOverrides tRPC router.
featureOverrides.status
Returns the health status of the feature overrides service.
Response:
{
available: boolean; // true if the AgentOS API is configured
knownFlags: string[]; // list of all known feature flag names
}
featureOverrides.companyOverrides
Fetches company-wide feature flags for a given agency.
Input:
{ shortName: string } // agency URL slug
Response: CompanyOverrides
{
removeContactButtons: boolean;
removeMaintenanceJobs: boolean;
removeAffiliateLinks: boolean;
replacePhotoPlaceholder: boolean;
removeViewings: boolean;
removePropertyFeedback: boolean;
removePropertyRoomCounts: boolean;
removeTenantCerts: boolean;
fixfloOverrideUrl: string | null;
raw: Record<string, unknown>; // full API response for dynamic flags
}
featureOverrides.personFixflo
Fetches the person-level FixFlo override URL for a specific user.
Input:
{
shortName: string; // agency URL slug
personId: string; // AgentOS person/account ID
}
Response: string | null
Returns the FixFlo URL string, or null if no override is configured for this person.
featureOverrides.resolve
Fetches both company-level overrides and the person-level FixFlo override in parallel, then applies the priority chain to produce a single resolved result.
Input:
{
shortName: string; // agency URL slug
personId?: string; // optional — omit to resolve company flags only
}
Response: ResolvedFeatureFlags
{
overrides: CompanyOverrides; // full company-level flags
personFixfloOverride: string | null; // raw person-level FixFlo URL
effectiveFixfloUrl: string | null; // URL after priority chain
fixfloSource: "company" | "person" | "none"; // which level won
resolvedAt: string; // ISO timestamp
}
Error Handling
- A
404from the company overrides endpoint means the agency has no overrides configured — all flags return their defaults (false). - A
404from the person FixFlo endpoint means no override exists for that person — returnsnull. - All other API errors are captured and logged. Safe defaults are returned rather than surfacing an error to the user.
- If the AgentOS API is not configured, all service functions throw
LetmcNotConfiguredError.
Usage Example
import { resolveFeatureFlags } from "@/lib/letmc/features";
const flags = await resolveFeatureFlags("acme-lettings", "person-123");
if (flags.overrides.removeMaintenanceJobs) {
// Hide the maintenance section in the UI
}
if (flags.effectiveFixfloUrl) {
// Redirect maintenance requests to FixFlo
window.location.href = flags.effectiveFixfloUrl;
}
console.log(flags.fixfloSource); // "company" | "person" | "none"