From hudu
Documents Hudu API patterns: x-api-key authentication, REST endpoints, UI/API naming differences, pagination, filtering, rate limiting, error handling, and permissions.
npx claudepluginhub wyre-technology/msp-claude-plugins --plugin huduThis skill uses the workspace's default tool permissions.
The Hudu API is a RESTful JSON API that provides access to companies, assets, asset layouts, articles, asset passwords, websites, folders, procedures, and more. This skill covers authentication, query building, pagination, error handling, and performance optimization patterns.
Fetches up-to-date documentation from Context7 for libraries and frameworks like React, Next.js, Prisma. Use for setup questions, API references, and code examples.
Retrieves current documentation, API references, and code examples for libraries, frameworks, SDKs, CLIs, and services via Context7 CLI. Ideal for API syntax, configs, migrations, and setup queries.
Uses ctx7 CLI to fetch current library docs, manage AI coding skills (install/search/generate), and configure Context7 MCP for AI editors.
The Hudu API is a RESTful JSON API that provides access to companies, assets, asset layouts, articles, asset passwords, websites, folders, procedures, and more. This skill covers authentication, query building, pagination, error handling, and performance optimization patterns.
Hudu uses API key authentication via the x-api-key header:
GET /api/v1/companies
x-api-key: YOUR_API_KEY
Content-Type: application/json
Required Headers:
| Header | Value | Description |
|---|---|---|
x-api-key | Your API key | Authentication token |
Content-Type | application/json | JSON content type |
export HUDU_BASE_URL="https://your-company.huducloud.com"
export HUDU_API_KEY="your-api-key-here"
All API endpoints follow the pattern:
https://[YOUR_DOMAIN]/api/v1/[resource]
For Hudu Cloud instances:
https://your-company.huducloud.com/api/v1/companies
For self-hosted instances:
https://hudu.yourcompany.com/api/v1/companies
Hudu API keys support granular permission controls:
| Permission | Description |
|---|---|
| Password Access | Allow or deny reading password values |
| DELETE Operations | Allow or deny deletion of records |
| IP Whitelist | Restrict API key usage to specific IPs |
| Company Scope | Restrict API key to specific companies |
Administrators configure these in Admin > API Keys when creating or editing a key.
Hudu's UI names differ from API endpoint names in several cases. This is critical to get right:
| Hudu UI Name | API Endpoint | API Resource Name |
|---|---|---|
| Company (label is customizable) | /api/v1/companies | company |
| Password | /api/v1/asset_passwords | asset_password |
| Knowledge Base Article | /api/v1/articles | article |
| Process | /api/v1/procedures | procedure |
| Asset | /api/v1/assets | asset |
| Asset Layout | /api/v1/asset_layouts | asset_layout |
| Website | /api/v1/websites | website |
| Folder | /api/v1/folders | folder |
| Activity Log | /api/v1/activity_logs | activity_log |
| Magic Dash | /api/v1/magic_dash | magic_dash |
| Network | /api/v1/networks | network |
| Relation | /api/v1/relations | relation |
Hudu uses standard JSON (not JSON:API) for request and response bodies:
{
"company": {
"name": "Acme Corporation",
"nickname": "ACME",
"address_line_1": "123 Main St",
"city": "Springfield",
"state": "IL"
}
}
Single Resource:
{
"company": {
"id": 1,
"name": "Acme Corporation",
"nickname": "ACME",
"address_line_1": "123 Main St",
"city": "Springfield",
"state": "IL",
"created_at": "2024-01-15T10:30:00.000Z",
"updated_at": "2024-02-15T14:22:00.000Z"
}
}
Collection:
{
"companies": [
{
"id": 1,
"name": "Acme Corporation",
"nickname": "ACME"
},
{
"id": 2,
"name": "TechStart Inc",
"nickname": "TSI"
}
]
}
Hudu uses simple query parameters for filtering:
GET /api/v1/companies?name=Acme
GET /api/v1/companies?city=Springfield
GET /api/v1/companies?id_in_integration=12345
GET /api/v1/assets?company_id=1
GET /api/v1/asset_passwords?company_id=1&name=Domain
GET /api/v1/articles?company_id=1&name=backup
| Endpoint | Parameters | Description |
|---|---|---|
/companies | name, city, state, id_in_integration, website | Filter companies |
/assets | company_id, asset_layout_id, name, primary_serial, archived | Filter assets |
/asset_passwords | company_id, name, slug | Filter passwords |
/articles | company_id, name, slug | Filter articles |
/websites | company_id, name, slug | Filter websites |
/asset_layouts | name | Filter asset layouts |
/activity_logs | user_id, user_email, resource_id, resource_type, action_message | Filter logs |
Some endpoints support a search parameter for broader matching:
GET /api/v1/companies?search=Acme
Hudu uses page-based pagination with the page query parameter:
GET /api/v1/companies?page=1
GET /api/v1/companies?page=2
GET /api/v1/companies?page=3
Pagination Details:
| Parameter | Description | Default |
|---|---|---|
page | Page number (1-based) | 1 |
| Results per page | Fixed by Hudu | 25 |
When a page returns fewer than 25 results (or an empty array), you have reached the last page:
async function fetchAllCompanies() {
const allItems = [];
let page = 1;
let hasMore = true;
while (hasMore) {
const response = await fetch(
`${baseUrl}/api/v1/companies?page=${page}`,
{ headers: { 'x-api-key': apiKey } }
);
const data = await response.json();
const companies = data.companies || [];
allItems.push(...companies);
// If fewer than 25 results, we reached the last page
hasMore = companies.length === 25;
page++;
}
return allItems;
}
Hudu enforces rate limits to ensure fair API usage:
| Metric | Limit |
|---|---|
| Requests per minute | 300 |
When rate limited (HTTP 429):
{
"error": "Rate limit exceeded. Please wait before making more requests."
}
async function requestWithRetry(url, options, maxRetries = 5) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await fetch(url, options);
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || 60;
const jitter = Math.random() * 5000;
await sleep(retryAfter * 1000 + jitter);
continue;
}
return response;
} catch (error) {
if (attempt === maxRetries - 1) throw error;
// Exponential backoff with jitter
const delay = Math.pow(2, attempt) * 1000 + Math.random() * 1000;
await sleep(delay);
}
}
}
POST /api/v1/companies
Content-Type: application/json
x-api-key: YOUR_API_KEY
{
"company": {
"name": "New Client Inc",
"nickname": "NCI",
"address_line_1": "456 Oak Ave",
"city": "Portland",
"state": "OR"
}
}
Single resource:
GET /api/v1/companies/123
Collection with filters:
GET /api/v1/companies?name=Acme&page=1
PUT /api/v1/companies/123
Content-Type: application/json
x-api-key: YOUR_API_KEY
{
"company": {
"nickname": "ACME-UPDATED",
"notes": "Updated contact information"
}
}
DELETE /api/v1/companies/123
x-api-key: YOUR_API_KEY
Note: DELETE operations require explicit API key permission. Not all API keys can delete records.
Many resources can be filtered by company:
GET /api/v1/assets?company_id=123
GET /api/v1/asset_passwords?company_id=123
GET /api/v1/articles?company_id=123
GET /api/v1/websites?company_id=123
For assets specifically, you can also scope by asset layout:
GET /api/v1/assets?company_id=123&asset_layout_id=5
| Code | Meaning | Action |
|---|---|---|
| 200 | Success | Process response |
| 201 | Created | Resource created successfully |
| 204 | No Content | Delete successful |
| 400 | Bad Request | Check request format and required fields |
| 401 | Unauthorized | Verify API key |
| 403 | Forbidden | Check API key permissions (e.g., password access, DELETE) |
| 404 | Not Found | Resource doesn't exist or wrong base URL |
| 422 | Unprocessable Entity | Validation errors (missing/invalid fields) |
| 429 | Rate Limited | Implement backoff, wait 60 seconds |
| 500 | Server Error | Retry with backoff |
{
"error": "Validation failed: Name can't be blank"
}
Or for multiple errors:
{
"errors": [
"Name can't be blank",
"Company is required"
]
}
function handleApiError(response, body) {
if (response.status === 401) {
console.log('API key invalid or expired. Check HUDU_API_KEY.');
} else if (response.status === 403) {
console.log('Permission denied. Check API key permissions.');
console.log('If accessing passwords, verify password access is enabled.');
} else if (response.status === 404) {
console.log('Resource not found. Check HUDU_BASE_URL and resource ID.');
} else if (response.status === 422) {
console.log('Validation error:', body.error || body.errors);
} else if (response.status === 429) {
console.log('Rate limited. Wait 60 seconds before retrying.');
}
}
/api/v1/ in all requestsasset_passwords, Processes are procedurescompany_id when possible