Use this skill when working with IT Glue flexible assets - custom asset types for structured documentation. Covers flexible asset types, field definitions, creating and managing instances, cross-linking with other resources, and building custom documentation schemas for MSP needs.
Scanned 5/27/2026
Install via CLI
openskills install wyre-technology/msp-claude-plugins---
name: "IT Glue Flexible Assets"
description: >
Use this skill when working with IT Glue flexible assets - custom asset types
for structured documentation. Covers flexible asset types, field definitions,
creating and managing instances, cross-linking with other resources, and
building custom documentation schemas for MSP needs.
when_to_use: "When working with custom asset types for structured documentation in IT Glue flexible assets"
triggers:
- it glue flexible asset
- custom asset
- flexible asset type
- it glue custom documentation
- flexible asset field
- custom documentation
- structured asset
- it glue template
---
# IT Glue Flexible Assets Management
## Overview
Flexible Assets in IT Glue provide customizable, structured documentation templates. Unlike free-form documents, flexible assets have defined fields and types, enabling consistent documentation across organizations and powerful filtering/searching capabilities.
## Key Concepts
### Flexible Asset Types
Flexible Asset Types define the schema for a category of documentation:
```
Flexible Asset Type: Network Overview
├── Fields:
│ ├── Primary ISP (Text)
│ ├── Backup ISP (Text)
│ ├── Public IP Addresses (Textarea)
│ ├── Firewall (Tag - Configuration)
│ ├── Network Diagram (Upload)
│ └── DNS Provider (Select)
```
### Field Types
| Type | Description | Use Case |
|------|-------------|----------|
| Text | Single line text | Names, identifiers |
| Textarea | Multi-line text | Descriptions, notes |
| Number | Numeric value | Quantities, counts |
| Date | Date picker | Expiration dates |
| Checkbox | Boolean true/false | Flags, toggles |
| Select | Dropdown selection | Predefined options |
| Tag | Link to IT Glue resource | Configurations, contacts |
| Password | Password field | Embedded credentials |
| Upload | File attachment | Diagrams, documents |
| Percent | Percentage value | Utilization, progress |
| Header | Section header | Visual organization |
### Tag Fields
Tag fields create relationships to other IT Glue resources:
| Tag Type | Links To |
|----------|----------|
| Configuration | Configuration items |
| Contact | Contacts |
| Password | Passwords |
| Document | Documents |
| Flexible Asset | Other flexible assets |
| Location | Locations |
## Field Reference
### Flexible Asset Type Fields
| Field | Type | Description |
|-------|------|-------------|
| `id` | integer | Type identifier |
| `name` | string | Type name |
| `description` | string | Type description |
| `icon` | string | Display icon |
| `enabled` | boolean | Type enabled status |
### Flexible Asset Fields
| Field | Type | Description |
|-------|------|-------------|
| `id` | integer | Asset instance identifier |
| `organization-id` | integer | Parent organization |
| `flexible-asset-type-id` | integer | Type definition |
| `name` | string | Auto-generated from name field |
| `traits` | object | Field values |
### Traits (Field Values)
```json
{
"traits": {
"primary-isp": "Comcast Business",
"backup-isp": "Verizon FiOS",
"public-ip-addresses": "203.0.113.10\n203.0.113.11",
"firewall": {
"type": "Tag",
"values": [{"id": 12345, "type": "Configuration"}]
},
"dns-provider": "Cloudflare"
}
}
```
## Critical: Discover Type IDs First
**Flexible asset type IDs are instance-specific** — every IT Glue account has different IDs. Never guess or hardcode type IDs. Always call `list_flexible_asset_types` first to discover what types exist, then use the returned IDs with `search_flexible_assets`.
```
Step 1: list_flexible_asset_types → get type IDs
Step 2: search_flexible_assets(flexible_asset_type_id=<id from step 1>)
```
## API Patterns
### List Flexible Asset Types
```http
GET /flexible-asset-types
x-api-key: YOUR_API_KEY
Content-Type: application/vnd.api+json
```
### Get Flexible Asset Type Details
```http
GET /flexible-asset-types/123
x-api-key: YOUR_API_KEY
```
**With Field Definitions:**
```http
GET /flexible-asset-types/123?include=flexible-asset-fields
```
### List Flexible Assets
```http
GET /flexible-assets
x-api-key: YOUR_API_KEY
```
**By Organization:**
```http
GET /organizations/456/relationships/flexible-assets
```
**By Type:**
```http
GET /flexible-assets?filter[flexible-asset-type-id]=123
```
**By Organization and Type:**
```http
GET /flexible-assets?filter[organization-id]=456&filter[flexible-asset-type-id]=123
```
### Get Single Flexible Asset
```http
GET /flexible-assets/789
x-api-key: YOUR_API_KEY
```
**With Includes:**
```http
GET /flexible-assets/789?include=organization,flexible-asset-type
```
### Create Flexible Asset
```http
POST /flexible-assets
Content-Type: application/vnd.api+json
x-api-key: YOUR_API_KEY
```
```json
{
"data": {
"type": "flexible-assets",
"attributes": {
"organization-id": 456,
"flexible-asset-type-id": 123,
"traits": {
"name": "Acme Corp Network Overview",
"primary-isp": "Comcast Business",
"backup-isp": "Verizon FiOS",
"public-ip-addresses": "203.0.113.10\n203.0.113.11",
"dns-provider": "Cloudflare"
}
}
}
}
```
### Create with Tag Fields
```json
{
"data": {
"type": "flexible-assets",
"attributes": {
"organization-id": 456,
"flexible-asset-type-id": 123,
"traits": {
"name": "Main Office Network",
"firewall": [12345],
"core-switch": [67890],
"network-admin": [11111]
}
}
}
}
```
### Update Flexible Asset
```http
PATCH /flexible-assets/789
Content-Type: application/vnd.api+json
x-api-key: YOUR_API_KEY
```
```json
{
"data": {
"type": "flexible-assets",
"attributes": {
"traits": {
"backup-isp": "AT&T Business",
"last-reviewed": "2024-02-15"
}
}
}
}
```
### Delete Flexible Asset
```http
DELETE /flexible-assets/789
x-api-key: YOUR_API_KEY
```
## Common Flexible Asset Types
### Network Overview
```
Fields:
├── Name (Text) - Required, Name field
├── Primary ISP (Text)
├── Backup ISP (Text)
├── Public IP Addresses (Textarea)
├── Internal IP Scheme (Textarea)
├── Firewall (Tag - Configuration)
├── Core Switch (Tag - Configuration)
├── Network Diagram (Upload)
├── DNS Provider (Select)
└── Last Reviewed (Date)
```
### Application Documentation
```
Fields:
├── Name (Text) - Required, Name field
├── Description (Textarea)
├── Version (Text)
├── Vendor (Text)
├── Support Contact (Tag - Contact)
├── Primary Server (Tag - Configuration)
├── Database Server (Tag - Configuration)
├── Admin URL (Text)
├── Admin Credentials (Password)
├── License Key (Password)
├── License Expiration (Date)
├── Documentation URL (Text)
└── Notes (Textarea)
```
### Backup Overview
```
Fields:
├── Name (Text) - Required, Name field
├── Backup Solution (Select)
├── Backup Server (Tag - Configuration)
├── Retention Policy (Textarea)
├── Backup Schedule (Textarea)
├── Data Protected (Textarea)
├── Recovery Time Objective (Text)
├── Recovery Point Objective (Text)
├── Last Test Date (Date)
├── Backup Admin Credentials (Password)
└── Notes (Textarea)
```
### Microsoft 365 Tenant
```
Fields:
├── Name (Text) - Required, Name field
├── Tenant ID (Text)
├── Primary Domain (Text)
├── Additional Domains (Textarea)
├── License Summary (Textarea)
├── Admin Portal URL (Text)
├── Global Admin (Tag - Contact)
├── Admin Credentials (Password)
├── MFA Status (Select)
├── Conditional Access (Checkbox)
└── Notes (Textarea)
```
## Common Workflows
### Create Flexible Asset from Template
```javascript
async function createFlexibleAssetFromType(orgId, typeId, fieldValues) {
// Get the type definition to understand fields
const assetType = await getFlexibleAssetType(typeId, {
include: 'flexible-asset-fields'
});
// Validate required fields
const requiredFields = assetType.included?.filter(
f => f.attributes.required
) || [];
for (const field of requiredFields) {
const fieldKey = field.attributes['name-key'];
if (!fieldValues[fieldKey]) {
throw new Error(`Required field missing: ${field.attributes.name}`);
}
}
// Create the flexible asset
return await createFlexibleAsset({
'organization-id': orgId,
'flexible-asset-type-id': typeId,
traits: fieldValues
});
}
```
### Find Flexible Assets by Type
```javascript
async function findFlexibleAssetsByType(orgId, typeName) {
// First, find the type by name
const types = await fetchFlexibleAssetTypes();
const type = types.find(t =>
t.attributes.name.toLowerCase() === typeName.toLowerCase()
);
if (!type) {
throw new Error(`Flexible asset type not found: ${typeName}`);
}
// Then fetch assets of that type for the org
return await fetchFlexibleAssets({
filter: {
'organization-id': orgId,
'flexible-asset-type-id': type.id
}
});
}
```
### Update Tagged Resources
```javascript
async function updateFlexibleAssetTags(assetId, fieldName, newTagIds) {
return await updateFlexibleAsset(assetId, {
traits: {
[fieldName]: newTagIds
}
});
}
```
### Export Flexible Asset Data
```javascript
async function exportFlexibleAssets(orgId, typeId) {
const assets = await fetchFlexibleAssets({
filter: {
'organization-id': orgId,
'flexible-asset-type-id': typeId
}
});
const type = await getFlexibleAssetType(typeId, {
include: 'flexible-asset-fields'
});
const fieldNames = type.included?.reduce((acc, f) => {
acc[f.attributes['name-key']] = f.attributes.name;
return acc;
}, {}) || {};
return assets.map(asset => {
const exportData = { id: asset.id };
Object.entries(asset.attributes.traits || {}).forEach(([key, value]) => {
const fieldName = fieldNames[key] || key;
exportData[fieldName] = value;
});
return exportData;
});
}
```
### Flexible Asset Health Check
```javascript
async function flexibleAssetHealthCheck(orgId) {
// Get all flexible asset types
const types = await fetchFlexibleAssetTypes();
const results = [];
for (const type of types) {
const assets = await fetchFlexibleAssets({
filter: {
'organization-id': orgId,
'flexible-asset-type-id': type.id
}
});
results.push({
type: type.attributes.name,
count: assets.length,
hasAssets: assets.length > 0
});
}
return {
totalTypes: types.length,
typesWithData: results.filter(r => r.hasAssets).length,
details: results
};
}
```
### Clone Flexible Asset to Another Org
```javascript
async function cloneFlexibleAsset(sourceAssetId, targetOrgId) {
// Get source asset
const source = await getFlexibleAsset(sourceAssetId);
// Clone traits (remove tag fields that won't be valid in new org)
const traits = { ...source.attributes.traits };
// Note: Tag fields reference resources in the source org
// You may need to map or remove these
return await createFlexibleAsset({
'organization-id': targetOrgId,
'flexible-asset-type-id': source.attributes['flexible-asset-type-id'],
traits: traits
});
}
```
## Error Handling
### Common API Errors
| Code | Message | Resolution |
|------|---------|------------|
| 400 | Organization required | Include organization-id |
| 400 | Type required | Include flexible-asset-type-id |
| 401 | Invalid API key | Check IT_GLUE_API_KEY |
| 404 | Asset not found | Verify asset ID |
| 422 | Invalid trait value | Check field type requirements |
| 422 | Required field missing | Provide all required traits |
### Validation Errors
| Error | Cause | Fix |
|-------|-------|-----|
| Organization required | No org ID | Include organization-id |
| Type required | No type ID | Include flexible-asset-type-id |
| Invalid trait | Wrong data type | Match field type |
| Required trait | Missing required field | Add trait value |
| Invalid tag | Bad resource ID | Verify tagged resource exists |
### Error Recovery Pattern
```javascript
async function safeCreateFlexibleAsset(data) {
try {
return await createFlexibleAsset(data);
} catch (error) {
if (error.status === 422) {
const errors = error.errors || [];
// Handle missing required fields
const missingFields = errors.filter(e =>
e.detail?.includes('required') || e.detail?.includes("can't be blank")
);
if (missingFields.length > 0) {
console.log('Missing required fields:',
missingFields.map(e => e.source?.pointer)
);
// Get type definition to see required fields
const type = await getFlexibleAssetType(data['flexible-asset-type-id'], {
include: 'flexible-asset-fields'
});
const required = type.included?.filter(f => f.attributes.required);
console.log('Required fields:', required?.map(f => f.attributes.name));
}
// Handle invalid tag references
const invalidTags = errors.filter(e =>
e.detail?.includes('invalid') && e.source?.pointer?.includes('traits')
);
if (invalidTags.length > 0) {
console.log('Invalid tag references found. Removing...');
// Remove invalid tags and retry
// (implementation depends on which fields are tags)
}
}
throw error;
}
}
```
## Best Practices
1. **Plan type structure** - Design flexible asset types before creating
2. **Use consistent naming** - Follow conventions for field names
3. **Leverage tags** - Link to configurations, contacts for relationships
4. **Required fields** - Mark essential fields as required
5. **Use appropriate types** - Match field type to data (date for dates, etc.)
6. **Document types** - Add descriptions to types and fields
7. **Standardize across orgs** - Use same types for all clients
8. **Regular reviews** - Update flexible asset content periodically
9. **Avoid duplicates** - One flexible asset per topic per org
10. **Export capability** - Build export for reporting needs
## Related Skills
- [IT Glue Organizations](../organizations/SKILL.md) - Flexible asset scope
- [IT Glue Configurations](../configurations/SKILL.md) - Tag field targets
- [IT Glue Contacts](../contacts/SKILL.md) - Tag field targets
- [IT Glue Passwords](../passwords/SKILL.md) - Password fields
- [IT Glue Documents](../documents/SKILL.md) - Alternative documentation
- [IT Glue API Patterns](../api-patterns/SKILL.md) - API reference
No comments yet. Be the first to comment!