Hudu API Patterns — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Hudu API Patterns (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
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.
a JSON:API envelope with data/attributes wrappers and its own pagination, against Hudu's flat JSON and x-api-key header. Use itglue-api-patterns. Request shapes do not transfer between them.
toggle, not a bad key or an expired token, and the same key works everywhere else. Use hudu-passwords.
succeeds** — that is a gateway-connection problem; use shared-skills-wyre-gateway-troubleshooting.
Hudu uses API key authentication via the x-api-key header:
GET /api/v1/companies
x-api-key: YOUR_API_KEY
Content-Type: application/jsonRequired 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/companiesFor self-hosted instances:
https://hudu.yourcompany.com/api/v1/companiesHudu 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). Request and single-resource response bodies are wrapped in the singular resource key ({ "company": { ... } }); collections are wrapped in the plural key ({ "companies": [ ... ] }).
See references/examples.md for full CRUD request/response examples.
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=AcmeHudu 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=3Pagination 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);
}
}
}Standard REST verbs: POST to the collection, GET on collection or /:id, PUT /:id for updates (send only the fields you're changing), DELETE /:id. DELETE requires explicit API key permission — not all keys can delete records. Several resources also expose /:id/archive and /:id/unarchive as PUT verbs rather than an archived field.
Most child resources are filtered by company rather than nested under it:
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
GET /api/v1/assets?company_id=123&asset_layout_id=5See references/examples.md for full request/response bodies per verb.
| 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 |
Errors come back as either a single error string or an errors array of strings — handle both. See references/examples.md for the exact shapes and a status-code dispatch helper.
company scope are all per-key toggles; a working key can still 403 on one resource.
asset_passwords; Processes are procedures.page returns fewer than 25 items.
company_id when possible~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.