SDKs
TypeScript SDK
Installation
npm install levelfourClient Setup
import { LevelFourClient } from "levelfour";
const client = new LevelFourClient({
apiKey: "l4_live_...",
baseURL: "https://api.levelfour.ai",
timeoutInSeconds: 30,
maxRetries: 2,
});With environment variable auto-detection:
const client = new LevelFourClient();Constructor Options
| Parameter | Type | Default |
|---|---|---|
apiKey | string | LEVELFOUR_API_KEY env var |
baseURL | string | https://api.levelfour.ai |
timeoutInSeconds | number | 30 |
maxRetries | number | 2 |
fetch | typeof fetch | Built-in |
defaultHeaders | Record<string, string> | undefined |
Recommendations
const summary = await client.recommendations.getSavingsByProvider();
const potential = await client.recommendations.getPotentialSavings();
const overview = await client.recommendations.getOverview();
const processing = await client.recommendations.listInProgress();
const detail = await client.recommendations.get({ recommendation_id: "rec_123" });
const page = await client.recommendations.list({
page: 1,
page_size: 50,
sort_by: "monthly_savings",
sort_order: "desc",
});Recommendations Audit
const summary = await client.recommendations.audit.getSummary();
const page = await client.recommendations.audit.list({
page: 1,
page_size: 50,
sort_by: "monthly_savings",
sort_order: "desc",
start: "2025-01-01",
end: "2025-03-31",
preset: "6M",
provider: "aws",
service: ["EC2", "RDS"],
environment: ["production"],
account_id: ["123456789012"],
});Costs
const summary = await client.costs.getSummary();
const breakdown = await client.costs.list({
format: "table",
period: "2025-03",
provider_id: "aws",
page: 1,
page_size: 50,
sort_by: "cost",
sort_order: "desc",
});
const daily = await client.costs.getDailyCosts({
start: "2025-03-01",
end: "2025-03-31",
});
const monthly = await client.costs.getMonthlyCosts();Providers
const providers = await client.providers.list();
const top = await client.providers.getTopRecommendations({ provider_id: "aws" });
const recs = await client.providers.listRecommendations({
provider_id: "aws",
page: 1,
page_size: 50,
sort_by: "monthly_savings",
sort_order: "desc",
service: ["EC2"],
display_status: ["available", "pending"],
});
const overview = await client.providers.getRecommendationsOverview({ provider_id: "aws" });
const savings = await client.providers.listRealizedSavings({
provider_id: "aws",
page: 1,
page_size: 50,
preset: "6M",
});
const savingsSummary = await client.providers.getRealizedSavingsSummary({ provider_id: "aws" });
const spending = await client.providers.getCostsSummary({ provider_id: "aws" });
const spendingList = await client.providers.listCosts({
provider_id: "aws",
format: "table",
page: 1,
page_size: 50,
});API Keys
const keys = await client.apiKeys.list();
const newKey = await client.apiKeys.create({
name: "CI Pipeline",
scope: "read",
});
await client.apiKeys.revoke({ key_id: "key_123" });
const rotated = await client.apiKeys.rotate({ key_id: "key_123" });Webhooks
const endpoints = await client.webhooks.list();
const endpoint = await client.webhooks.register({
url: "https://example.com/webhook",
event_types: ["recommendation.accepted", "optimization.completed"],
});
await client.webhooks.delete({ endpoint_id: "ep_123" });Auth
const me = await client.auth.getWhoami();Pagination
Methods that return paginated results return a Page object that implements AsyncIterable. You can auto-iterate items, manually navigate pages, or collect everything into an array.
Auto-iterate all items
for await (const rec of await client.recommendations.list({ page_size: 50 })) {
console.log(rec.recommendation_id);
}Manual pagination
const page = await client.recommendations.list({ page: 1, page_size: 50 });
console.log(page.data);
while (page.hasNextPage()) {
await page.getNextPage();
console.log(page.data);
}Collect all items
import { collectAll } from "levelfour";
const allRecs = await collectAll(await client.recommendations.list());See Pagination for more details.
Error Handling
import {
LevelFourClient,
NotFoundError,
RateLimitError,
LevelFourError,
} from "levelfour";
const client = new LevelFourClient();
try {
await client.recommendations.get({ recommendation_id: "rec_nonexistent" });
} catch (err) {
if (err instanceof NotFoundError) {
console.log("Not found:", err.message);
} else if (err instanceof RateLimitError) {
console.log("Rate limited");
} else if (err instanceof LevelFourError) {
console.log(`API error ${err.statusCode}: ${err.message}`);
}
}All error classes extend LevelFourError which exposes statusCode, body, and rawResponse properties.
See Error Handling for the full error class hierarchy.
Webhook Verification
import { WebhookVerifier, WebhookVerificationError } from "levelfour";
const verifier = new WebhookVerifier("whsec_your_signing_secret");
try {
const payload = verifier.verify(requestBody, {
"webhook-id": headers["webhook-id"],
"webhook-timestamp": headers["webhook-timestamp"],
"webhook-signature": headers["webhook-signature"],
});
console.log("Verified event:", payload.type);
} catch (err) {
if (err instanceof WebhookVerificationError) {
console.log("Verification failed:", err.message);
}
}Custom timestamp tolerance (default is 300 seconds):
const payload = verifier.verify(body, headers, { toleranceSeconds: 600 });See Webhooks for event types and payload details.
Raw Response Access
Every API method returns an HttpResponsePromise that can be awaited directly for parsed data, or unwrapped to access HTTP metadata:
const data = await client.costs.getSummary();
const { data: costs, rawResponse } = await client.costs
.getSummary()
.withRawResponse();
console.log(rawResponse.status);
console.log(rawResponse.headers);Request Options
Override client defaults on a per-request basis by passing a second argument:
const summary = await client.recommendations.getSavingsByProvider({
timeoutInSeconds: 60,
maxRetries: 5,
headers: { "X-Request-Id": "abc123" },
abortSignal: controller.signal,
});| Option | Type | Description |
|---|---|---|
timeoutInSeconds | number | Override request timeout |
maxRetries | number | Override max retry attempts |
headers | Record<string, string> | Extra headers for this request |
abortSignal | AbortSignal | Cancel the request |