Skip to main content
All Docs
FeaturesmyProp (AgentOS People Portal)Updated April 4, 2026

Fixing Silent AgentOS API Authentication Failures in v0.1.50

Fixing Silent AgentOS API Authentication Failures in v0.1.50

Release: v0.1.50 · PR: #33 · Severity: Critical

Background

The myProp portal communicates with the AgentOS/LetMC platform through a set of server-side API calls constructed by a shared utility function, buildLetmcUrl(), located in src/lib/letmc/config.ts. This function accepts a path fragment and returns a fully-qualified URL ready for use in fetch requests.

The AgentOS API authenticates all requests via a api_key query parameter appended to the URL — for example:

GET https://live-api.letmc.com/acme/payments/requests/person-123?api_key=MY_KEY

This pattern was established in the original Lambda BFF (Express handler) that the Next.js app replaced.

The Problem

When buildLetmcUrl() was ported to the Next.js app, the api_key query parameter was never included. The function resolved the API key from the environment correctly, but then discarded it — the returned URL contained only the base URL and path:

// Before fix
export function buildLetmcUrl(path: string, config?: LetmcConfig): string {
  const resolved = config ?? getLetmcConfig();
  const cleanPath = path.startsWith("/") ? path : `/${path}`;
  return `${resolved.apiBaseUrl}${cleanPath}`;
  //     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  //     api_key was never appended
}

Because buildLetmcUrl() is the single entry point for constructing every AgentOS API URL, this omission affected all endpoints simultaneously — not just one route. Every request to accounts, landlords, tenants, contractors, affiliates, and payments was sent without authentication. The AgentOS API silently rejected or returned empty responses, meaning the portal appeared to function but served no real data.

The Fix

The fix appends ?api_key={KEY} (URL-encoded) to every URL produced by buildLetmcUrl(). A ? separator is used when no existing query string is present; & is used if one already exists, preserving correctness for any future paths that include their own query parameters.

// After fix
export function buildLetmcUrl(path: string, config?: LetmcConfig): string {
  const resolved = config ?? getLetmcConfig();
  const cleanPath = path.startsWith("/") ? path : `/${path}`;
  const baseUrl = `${resolved.apiBaseUrl}${cleanPath}`;

  const separator = baseUrl.includes("?") ? "&" : "?";
  return `${baseUrl}${separator}api_key=${encodeURIComponent(resolved.apiKey)}`;
}

URL encoding

The API key is passed through encodeURIComponent() before being appended. This ensures that any special characters in the key (spaces, &, =, etc.) are safely percent-encoded and cannot corrupt the query string.

Scope of Impact

All AgentOS API endpoints are affected by this fix. Because every request is routed through buildLetmcUrl(), a single-line change restores authentication across the entire integration:

Endpoint categoryWas broken?Fixed?
Accounts✅ Yes✅ Yes
Landlords✅ Yes✅ Yes
Tenants✅ Yes✅ Yes
Contractors✅ Yes✅ Yes
Affiliates✅ Yes✅ Yes
Payments / requests✅ Yes✅ Yes

Test Coverage

The following test cases were added or updated in this release:

  • buildLetmcUrl with leading slash — asserts ?api_key=key is appended
  • buildLetmcUrl without leading slash — same assertion
  • Custom base URL — verifies api_key is appended regardless of base URL override
  • Pre-resolved config object — verifies api_key from config is used, not the environment
  • URL-encoding of special characters — key key with spaces&special=chars becomes key%20with%20spaces%26special%3Dchars
  • Payment-requests path — explicit regression test asserting the URL matches the original Lambda BFF format exactly
  • All HTTP methods (GET, POST, PUT, PATCH, DELETE) — each client method test updated to assert ?api_key= is present in the outbound URL

Configuration

No configuration changes are required. The API key continues to be sourced from the LETMC_API_KEY environment variable. This fix only changes how that value is transmitted — it is now correctly included in every outbound request URL.

If you are running the portal locally, ensure LETMC_API_KEY is set in your .env.local file. Without it, buildLetmcUrl() will throw at config resolution time before any URL is constructed.