Skip to main content
All Docs
API ReferencemyProp (AgentOS People Portal)Updated April 3, 2026

LetMC API Client

LetMC API Client

The LetMC client (src/lib/letmc/client.ts) is a server-side HTTP client for communicating with the AgentOS (letmc.com) REST API. It is the single authorised path for myProp server code to read and write AgentOS data.

Server-side only. This module must not be imported in client components or browser bundles. It reads LETMC_API_KEY from the server environment and uses Node.js fetch.

Prerequisites

Set the following environment variable before using the client:

VariableDescription
LETMC_API_KEYAPI key issued by AgentOS / letmc.com

If LETMC_API_KEY is absent, every method throws LetmcNotConfiguredError immediately without making a network request.

Quick Start

import { letmcClient } from "@/lib/letmc/client";

// GET — fetch a list of properties
const properties = await letmcClient.get("/v3/lettings/properties");

// POST — create a new maintenance job
const job = await letmcClient.post("/v3/lettings/jobs", {
  description: "Fix tap",
});

Methods

All methods accept an optional options.headers object for custom request headers and return a generic Promise<T> (defaults to unknown).

letmcClient.get<T>(path, options?)

const data = await letmcClient.get<Property[]>("/v3/lettings/properties");

letmcClient.post<T>(path, body?, options?)

const result = await letmcClient.post<Job>("/v3/lettings/jobs", { description: "Fix boiler" });

letmcClient.put<T>(path, body?, options?)

await letmcClient.put("/v3/lettings/jobs/123", { status: "complete" });

letmcClient.patch<T>(path, body?, options?)

await letmcClient.patch("/v3/lettings/jobs/123", { priority: "high" });

letmcClient.delete<T>(path, options?)

await letmcClient.delete("/v3/lettings/jobs/123");

letmcClient.isConfigured()

Returns true if LETMC_API_KEY is present. Use this for health checks or conditional feature flags without risking a thrown error.

if (!letmcClient.isConfigured()) {
  return { error: "AgentOS integration is not enabled" };
}

Behaviour

Timeout

Every request is cancelled after 30 seconds. A cancelled request surfaces as:

LetmcApiError: AgentOS API request timed out after 30000ms: GET https://...
  status: 408
  statusText: "Request Timeout"

Retry Logic

Failed requests are retried up to 3 times with linear back-off:

AttemptDelay before retry
1st retry1 000 ms
2nd retry2 000 ms
3rd retry3 000 ms

Retried errors:

  • Network failures (DNS, connection refused, etc.)
  • Request timeouts (408)
  • Server errors (5xx)
  • Rate-limit responses (429)

Not retried:

  • Any 4xx client error other than 429 (bad request, unauthorised, forbidden, not found, validation errors)

Once all retries are exhausted, captureError() is called with domain letmc-api before the error is thrown to the caller.

Headers

The following headers are set automatically on every request:

Content-Type: application/json
Accept: application/json

Pass options.headers to merge additional headers.

Response Handling

ResponseBehaviour
2xx with JSON bodyParsed and returned as T
2xx with non-JSON bodyReturned as string
204 No ContentReturns null
Non-2xxThrows LetmcApiError with status, body, and request context

Error Types

LetmcApiError

Thrown for all non-2xx responses and timeout events.

import { LetmcApiError } from "@/lib/letmc/client";

try {
  await letmcClient.get("/v3/lettings/properties");
} catch (error) {
  if (error instanceof LetmcApiError) {
    console.error(error.status);     // HTTP status code
    console.error(error.statusText); // e.g. "Not Found"
    console.error(error.url);        // Full request URL
    console.error(error.method);     // HTTP method
    console.error(error.body);       // Parsed response body (if any)
  }
}

LetmcNotConfiguredError

Thrown immediately when any method is called and LETMC_API_KEY is not set.

import { LetmcNotConfiguredError } from "@/lib/letmc/client";

try {
  await letmcClient.get("/v3/lettings/properties");
} catch (error) {
  if (error instanceof LetmcNotConfiguredError) {
    // LETMC_API_KEY environment variable is missing
  }
}

Observability

After all retries are exhausted, the client calls:

captureError(error, {
  domain: "letmc-api",
  metadata: {
    path,
    method,
    retriesExhausted: true,
  },
});

This integrates with the application's existing error-capture pipeline for alerting and monitoring.