From maintainx-pack
Sets up MaintainX REST API authentication: generates keys, configures env vars, installs TypeScript Axios client for work orders/assets/locations. For CMMS integrations.
npx claudepluginhub jeremylongshore/claude-code-plugins-plus-skills --plugin maintainx-packThis skill is limited to using the following tools:
Set up MaintainX REST API authentication and configure your development environment for CMMS integration.
Builds robust TypeScript MaintainX REST API client with generics, cursor pagination, filtering, error handling, and retry logic for production integrations.
Automates Maintainx operations via Composio toolkit and Rube MCP. Guides tool discovery with RUBE_SEARCH_TOOLS, connection management, and schema-compliant execution.
Guides Next.js Cache Components and Partial Prerendering (PPR): 'use cache' directives, cacheLife(), cacheTag(), revalidateTag() for caching, invalidation, static/dynamic optimization. Auto-activates on cacheComponents: true.
Share bugs, ideas, or general feedback.
Set up MaintainX REST API authentication and configure your development environment for CMMS integration.
# Set environment variable
export MAINTAINX_API_KEY="your-api-key-here"
# Or create .env file
echo 'MAINTAINX_API_KEY=your-api-key' >> .env
# For multi-organization tokens, also set:
export MAINTAINX_ORG_ID="your-organization-id"
// src/maintainx/client.ts
import axios, { AxiosInstance, AxiosError } from 'axios';
export class MaintainXClient {
private client: AxiosInstance;
private baseUrl = 'https://api.getmaintainx.com/v1';
constructor(apiKey?: string, orgId?: string) {
const key = apiKey || process.env.MAINTAINX_API_KEY;
if (!key) {
throw new Error('MAINTAINX_API_KEY is required');
}
this.client = axios.create({
baseURL: this.baseUrl,
headers: {
'Authorization': `Bearer ${key}`,
'Content-Type': 'application/json',
...(orgId && { 'X-Organization-Id': orgId }),
},
});
this.client.interceptors.response.use(
response => response,
this.handleError
);
}
private handleError(error: AxiosError) {
if (error.response) {
const { status, data } = error.response;
console.error(`MaintainX API Error [${status}]:`, data);
}
throw error;
}
// Core API methods
async getWorkOrders(params?: WorkOrderQueryParams) {
return this.client.get('/workorders', { params });
}
async getWorkOrder(id: string) {
return this.client.get(`/workorders/${id}`);
}
async createWorkOrder(data: CreateWorkOrderInput) {
return this.client.post('/workorders', data);
}
async getAssets(params?: AssetQueryParams) {
return this.client.get('/assets', { params });
}
async getLocations(params?: LocationQueryParams) {
return this.client.get('/locations', { params });
}
async getUsers(params?: UserQueryParams) {
return this.client.get('/users', { params });
}
}
// Type definitions
interface WorkOrderQueryParams {
cursor?: string;
limit?: number;
status?: 'OPEN' | 'IN_PROGRESS' | 'ON_HOLD' | 'DONE';
}
interface CreateWorkOrderInput {
title: string;
description?: string;
priority?: 'NONE' | 'LOW' | 'MEDIUM' | 'HIGH';
assignees?: string[];
assetId?: string;
locationId?: string;
dueDate?: string;
}
interface AssetQueryParams {
cursor?: string;
limit?: number;
locationId?: string;
}
interface LocationQueryParams {
cursor?: string;
limit?: number;
}
interface UserQueryParams {
cursor?: string;
limit?: number;
}
// test-connection.ts
import { MaintainXClient } from './maintainx/client';
async function testConnection() {
const client = new MaintainXClient();
try {
const response = await client.getUsers({ limit: 1 });
console.log('Connection successful!');
console.log('Organization has users:', response.data.users.length > 0);
return true;
} catch (error) {
console.error('Connection failed:', error);
return false;
}
}
testConnection();
# Run test
npx ts-node test-connection.ts
# maintainx_client.py
import os
import requests
from typing import Optional, Dict, Any
class MaintainXClient:
BASE_URL = "https://api.getmaintainx.com/v1"
def __init__(self, api_key: Optional[str] = None, org_id: Optional[str] = None):
self.api_key = api_key or os.environ.get("MAINTAINX_API_KEY")
if not self.api_key:
raise ValueError("MAINTAINX_API_KEY is required")
self.headers = {
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json",
}
if org_id:
self.headers["X-Organization-Id"] = org_id
def _request(self, method: str, endpoint: str, **kwargs) -> Dict[str, Any]:
url = f"{self.BASE_URL}{endpoint}"
response = requests.request(method, url, headers=self.headers, **kwargs)
response.raise_for_status()
return response.json()
def get_work_orders(self, **params) -> Dict[str, Any]:
return self._request("GET", "/workorders", params=params)
def create_work_order(self, data: Dict[str, Any]) -> Dict[str, Any]:
return self._request("POST", "/workorders", json=data)
def get_assets(self, **params) -> Dict[str, Any]:
return self._request("GET", "/assets", params=params)
def get_locations(self, **params) -> Dict[str, Any]:
return self._request("GET", "/locations", params=params)
# Test connection
if __name__ == "__main__":
client = MaintainXClient()
users = client._request("GET", "/users", params={"limit": 1})
print("Connection successful!")
print(f"Found {len(users.get('users', []))} users")
.env file with API key configured| Error | Cause | Solution |
|---|---|---|
| 401 Unauthorized | Invalid or expired API key | Generate new key in Settings > Integrations |
| 403 Forbidden | Insufficient permissions | Ensure admin role or correct plan tier |
| 404 Not Found | Wrong base URL or endpoint | Use api.getmaintainx.com/v1 |
| Network Error | Firewall blocking HTTPS | Allow outbound 443 to getmaintainx.com |
After successful auth, proceed to maintainx-hello-world for your first API call.
Quick test with curl:
curl -s https://api.getmaintainx.com/v1/users?limit=1 \
-H "Authorization: Bearer $MAINTAINX_API_KEY" | jq .
Multi-org setup (for contractors managing multiple facilities):
const clients = {
plantA: new MaintainXClient(process.env.MAINTAINX_KEY_PLANT_A, 'org-plant-a'),
plantB: new MaintainXClient(process.env.MAINTAINX_KEY_PLANT_B, 'org-plant-b'),
};
const orders = await clients.plantA.getWorkOrders({ status: 'OPEN' });