openrouter-compliance-review
Review OpenRouter integration for regulatory compliance (SOC2, GDPR,
maintainx-sdk-patterns
Learn MaintainX REST API patterns, pagination, filtering, and client
Full skill instructions
Production-grade patterns for building robust MaintainX API integrations with proper error handling, cursor-based pagination, retry logic, and type safety.
maintainx-install-auth setup// src/maintainx/typed-client.ts
import axios, { AxiosInstance, AxiosRequestConfig, AxiosError } from 'axios';
interface PaginatedResponse<T> {
cursor: string | null;
}
interface WorkOrder {
id: number;
title: string;
status: 'OPEN' | 'IN_PROGRESS' | 'ON_HOLD' | 'COMPLETED' | 'CLOSED';
priority: 'NONE' | 'LOW' | 'MEDIUM' | 'HIGH';
description?: string;
assignees: Array<{ type: 'USER' | 'TEAM'; id: number }>;
assetId?: number;
locationId?: number;
createdAt: string;
updatedAt: string;
completedAt?: string;
dueDate?: string;
categories: string[];
}
interface Asset {
id: number;
name: string;
serialNumber?: string;
model?: string;
manufacturer?: string;
locationId?: number;
createdAt: string;
}
interface WorkOrdersResponse extends PaginatedResponse<WorkOrder> {
workOrders: WorkOrder[];
}
interface AssetsResponse extends PaginatedResponse<Asset> {
assets: Asset[];
}
export class MaintainXClient {
private http: AxiosInstance;
constructor(apiKey?: string) {
const key = apiKey || process.env.MAINTAINX_API_KEY;
if (!key) throw new Error('MAINTAINX_API_KEY required');
this.http = axios.create({
baseURL: 'https://api.getmaintainx.com/v1',
headers: { Authorization: `Bearer ${key}`, 'Content-Type': 'application/json' },
timeout: 30_000,
});
}
async getWorkOrders(params?: Record<string, any>): Promise<WorkOrdersResponse> {
const { data } = await this.http.get<WorkOrdersResponse>('/workorders', { params });
return data;
}
async getWorkOrder(id: number): Promise<WorkOrder> {
const { data } = await this.http.get<WorkOrder>(`/workorders/${id}`);
return data;
}
async createWorkOrder(input: Partial<WorkOrder>): Promise<WorkOrder> {
const { data } = await this.http.post<WorkOrder>('/workorders', input);
return data;
}
async updateWorkOrder(id: number, input: Partial<WorkOrder>): Promise<WorkOrder> {
const { data } = await this.http.patch<WorkOrder>(`/workorders/${id}`, input);
return data;
}
async getAssets(params?: Record<string, any>): Promise<AssetsResponse> {
const { data } = await this.http.get<AssetsResponse>('/assets', { params });
return data;
}
async request<T = any>(method: string, path: string, body?: any): Promise<T> {
const config: AxiosRequestConfig = { method, url: path, data: body };
const { data } = await this.http.request<T>(config);
return data;
}
}
MaintainX uses cursor-based pagination. The response includes a cursor field; pass it as a query parameter to get the next page.
async function paginate<T>(
fetcher: (cursor?: string) => Promise<{ cursor: string | null } & Record<string, T[]>>,
key: string,
): Promise<T[]> {
const all: T[] = [];
let cursor: string | undefined;
do {
const response = await fetcher(cursor);
const items = (response as any)[key] as T[];
all.push(...items);
cursor = response.cursor ?? undefined;
} while (cursor);
return all;
}
// Usage
const allWorkOrders = await paginate(
(cursor) => client.getWorkOrders({ limit: 100, cursor, status: 'OPEN' }),
'workOrders',
);
console.log(`Total open work orders: ${allWorkOrders.length}`);
const allAssets = await paginate(
(cursor) => client.getAssets({ limit: 100, cursor }),
'assets',
);
console.log(`Total assets: ${allAssets.length}`);
async function withRetry<T>(
fn: () => Promise<T>,
maxRetries = 3,
baseDelayMs = 1000,
): Promise<T> {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await fn();
} catch (err: any) {
const status = err?.response?.status;
const isRetryable = status === 429 || (status >= 500 && status < 600);
if (!isRetryable || attempt === maxRetries) throw err;
// Honor Retry-After header if present
const retryAfter = err.response?.headers?.['retry-after'];
const delayMs = retryAfter
? parseInt(retryAfter) * 1000
: baseDelayMs * Math.pow(2, attempt) + Math.random() * 500;
console.warn(`Retry ${attempt + 1}/${maxRetries} after ${delayMs}ms (HTTP ${status})`);
await new Promise((r) => setTimeout(r, delayMs));
}
}
throw new Error('Unreachable');
}
// Usage
const wo = await withRetry(() => client.getWorkOrder(12345));
import PQueue from 'p-queue';
const queue = new PQueue({ concurrency: 5, interval: 1000, intervalCap: 10 });
async function batchCreateWorkOrders(items: Array<Partial<WorkOrder>>): Promise<WorkOrder[]> {
const results = await Promise.all(
items.map((item) =>
queue.add(() => withRetry(() => client.createWorkOrder(item)))
),
);
return results as WorkOrder[];
}
// Create 50 PMs in controlled batches
const pms = Array.from({ length: 50 }, (_, i) => ({
title: `Weekly Inspection - Zone ${i + 1}`,
priority: 'LOW' as const,
categories: ['PREVENTIVE'],
}));
const created = await batchCreateWorkOrders(pms);
console.log(`Created ${created.length} preventive maintenance orders`);
class WorkOrderQuery {
private params: Record<string, any> = {};
status(s: WorkOrder['status']) { this.params.status = s; return this; }
priority(p: WorkOrder['priority']) { this.params.priority = p; return this; }
assignee(userId: number) { this.params.assigneeId = userId; return this; }
asset(assetId: number) { this.params.assetId = assetId; return this; }
location(locationId: number) { this.params.locationId = locationId; return this; }
createdAfter(date: string) { this.params.createdAtGte = date; return this; }
createdBefore(date: string) { this.params.createdAtLte = date; return this; }
limit(n: number) { this.params.limit = n; return this; }
async execute(client: MaintainXClient) {
return client.getWorkOrders(this.params);
}
}
// Usage
const results = await new WorkOrderQuery()
.status('OPEN')
.priority('HIGH')
.location(2345)
.createdAfter('2026-01-01T00:00:00Z')
.limit(25)
.execute(client);
Retry-After header supportp-queue| Pattern | Use Case |
|---|---|
withRetry() | Transient errors (429, 5xx) with exponential backoff |
paginate() | Collecting all items from cursor-based endpoints |
PQueue | Controlled concurrency to avoid rate limits |
WorkOrderQuery | Type-safe filtering to prevent invalid API calls |
For core workflows, see maintainx-core-workflow-a (Work Orders) and maintainx-core-workflow-b (Assets).
Stream large datasets with async iterators:
async function* streamWorkOrders(client: MaintainXClient, params?: Record<string, any>) {
let cursor: string | undefined;
do {
const response = await client.getWorkOrders({ ...params, limit: 100, cursor });
for (const wo of response.workOrders) {
yield wo;
}
cursor = response.cursor ?? undefined;
} while (cursor);
}
for await (const wo of streamWorkOrders(client, { status: 'COMPLETED' })) {
console.log(`Processing completed WO #${wo.id}`);
}
Review OpenRouter integration for regulatory compliance (SOC2, GDPR,
Data synchronization, ETL patterns, and data management for MaintainX.
Execute Groq primary workflow: chat completions with tool use and JSON
Validate CSRF protection implementations for security gaps. Use when
Configure this skill should be used when the user asks about "API contract",
Execute Ideogram incident response with triage, mitigation, and postmortem.
Execute create, select, and transform features to improve machine learning
Reusable patterns for the Gamma REST API (no SDK exists).
Apply production-ready Deepgram SDK patterns for TypeScript and Python.
Migrate to OpenRouter from direct provider APIs or upgrade between SDK/model
Diagnose and fix common OpenRouter API errors. Use when encountering
Optimize Linear API usage, reduce unnecessary calls, and maximize
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience