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_KEYfrom the server environment and uses Node.jsfetch.
Prerequisites
Set the following environment variable before using the client:
| Variable | Description |
|---|---|
LETMC_API_KEY | API 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:
| Attempt | Delay before retry |
|---|---|
| 1st retry | 1 000 ms |
| 2nd retry | 2 000 ms |
| 3rd retry | 3 000 ms |
Retried errors:
- Network failures (DNS, connection refused, etc.)
- Request timeouts (
408) - Server errors (
5xx) - Rate-limit responses (
429)
Not retried:
- Any
4xxclient error other than429(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
| Response | Behaviour |
|---|---|
2xx with JSON body | Parsed and returned as T |
2xx with non-JSON body | Returned as string |
204 No Content | Returns null |
Non-2xx | Throws 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.