From kaseya-it-glue
Manages IT Glue organizations: create, search, update, and handle client documentation including types, statuses, parent/child relationships, PSA sync, quick notes, and related configs, contacts, passwords.
npx claudepluginhub wyre-technology/msp-claude-plugins --plugin it-glueThis skill uses the workspace's default tool permissions.
Organizations are the foundational entity in IT Glue, representing companies, clients, vendors, or internal entities. All documentation, configurations, contacts, passwords, and flexible assets are associated with an organization. Proper organization management enables comprehensive client documentation and cross-platform integration with PSA tools.
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.
Organizations are the foundational entity in IT Glue, representing companies, clients, vendors, or internal entities. All documentation, configurations, contacts, passwords, and flexible assets are associated with an organization. Proper organization management enables comprehensive client documentation and cross-platform integration with PSA tools.
Organizations are classified by type for categorization:
| Type | Description | Use Case |
|---|---|---|
| Customer | Active client organizations | Primary service clients |
| Vendor | Product/service suppliers | Software vendors, hardware suppliers |
| Partner | Business partners | MSP partnerships, referral partners |
| Internal | Your own organization | Internal documentation |
| Prospect | Potential clients | Pre-sales documentation |
| Status | Description | Business Logic |
|---|---|---|
| Active | Currently serviced | Standard operational state |
| Inactive | Not currently active | Suspended or paused accounts |
| Archived | Historical only | No longer serviced, read-only |
Organizations can have hierarchical relationships:
Parent Organization (Acme Holdings)
├── Child: Acme East Division
├── Child: Acme West Division
└── Child: Acme International
This enables:
| Field | Type | Required | Description |
|---|---|---|---|
id | integer | System | Auto-generated unique identifier |
name | string | Yes | Organization name (unique) |
description | string | No | Detailed description |
quick-notes | string | No | Quick reference notes |
organization-type-id | integer | No | Type classification |
organization-status-id | integer | No | Status classification |
| Field | Type | Description |
|---|---|---|
parent-id | integer | Parent organization ID |
primary-contact-id | integer | Primary contact for org |
primary-location-id | integer | Primary location ID |
| Field | Type | Description |
|---|---|---|
psa-id | string | PSA system company ID |
psa-integration-type | string | PSA type (autotask, connectwise, etc.) |
| Field | Type | Description |
|---|---|---|
created-at | datetime | Creation timestamp |
updated-at | datetime | Last update timestamp |
short-name | string | Abbreviated name |
alert | string | Alert/warning message |
GET /organizations
x-api-key: YOUR_API_KEY
Content-Type: application/vnd.api+json
With Filters:
GET /organizations?filter[name]=Acme&filter[organization-status-id]=1
With Pagination:
GET /organizations?page[size]=100&page[number]=1&sort=name
GET /organizations/123456
x-api-key: YOUR_API_KEY
With Includes:
GET /organizations/123456?include=configurations,contacts,passwords
POST /organizations
Content-Type: application/vnd.api+json
x-api-key: YOUR_API_KEY
{
"data": {
"type": "organizations",
"attributes": {
"name": "New Client Corporation",
"description": "IT services client since 2024",
"quick-notes": "Primary contact: John Smith (555-123-4567)",
"organization-type-id": 37,
"organization-status-id": 1
}
}
}
PATCH /organizations/123456
Content-Type: application/vnd.api+json
x-api-key: YOUR_API_KEY
{
"data": {
"type": "organizations",
"attributes": {
"quick-notes": "Updated: New primary contact is Jane Doe",
"alert": "Contract renewal due March 2024"
}
}
}
DELETE /organizations/123456
x-api-key: YOUR_API_KEY
Warning: Deleting an organization removes all associated resources (configurations, passwords, documents, etc.)
GET /organizations?filter[psa-id]=12345
async function onboardClient(clientData) {
// Step 1: Create organization
const org = await createOrganization({
name: clientData.companyName,
description: clientData.description,
'quick-notes': clientData.notes,
'organization-type-id': CUSTOMER_TYPE_ID,
'organization-status-id': ACTIVE_STATUS_ID
});
// Step 2: Create primary contact
await createContact(org.id, {
name: clientData.primaryContact.name,
email: clientData.primaryContact.email,
phone: clientData.primaryContact.phone,
'contact-type-id': PRIMARY_CONTACT_TYPE
});
// Step 3: Create initial documentation
await createDocument(org.id, {
name: 'Client Overview',
content: generateOverviewContent(clientData)
});
return org;
}
async function offboardClient(orgId, reason) {
// Update status to archived
await updateOrganization(orgId, {
'organization-status-id': ARCHIVED_STATUS_ID,
alert: `ARCHIVED: ${new Date().toISOString().split('T')[0]} - ${reason}`
});
// Add final note
await addQuickNote(orgId, `
Client offboarded on ${new Date().toLocaleDateString()}
Reason: ${reason}
Final contact: [Record contact name and handoff details]
`);
}
async function verifyPsaSync() {
// Get all active organizations
const orgs = await fetchOrganizations({
filter: { 'organization-status-id': ACTIVE_STATUS_ID }
});
const syncStatus = {
synced: [],
unsynced: [],
mismatched: []
};
for (const org of orgs) {
if (!org.attributes['psa-id']) {
syncStatus.unsynced.push(org);
} else {
// Verify PSA record exists
const psaCompany = await lookupPsaCompany(org.attributes['psa-id']);
if (psaCompany) {
syncStatus.synced.push(org);
} else {
syncStatus.mismatched.push(org);
}
}
}
return syncStatus;
}
async function generateOrgReport() {
const orgs = await fetchAllOrganizations();
return orgs.map(org => ({
name: org.attributes.name,
type: org.relationships['organization-type']?.data?.id,
status: org.relationships['organization-status']?.data?.id,
hasConfigurations: org.relationships.configurations?.data?.length > 0,
hasPasswords: org.relationships.passwords?.data?.length > 0,
psaSynced: !!org.attributes['psa-id'],
createdAt: org.attributes['created-at'],
updatedAt: org.attributes['updated-at']
}));
}
| Code | Message | Resolution |
|---|---|---|
| 400 | Name can't be blank | Provide organization name |
| 400 | Name has already been taken | Use unique name |
| 401 | Invalid API key | Check IT_GLUE_API_KEY |
| 404 | Organization not found | Verify organization ID |
| 422 | Invalid organization type | Query valid type IDs first |
| Error | Cause | Fix |
|---|---|---|
| Name required | Missing name field | Add name to request |
| Name not unique | Duplicate name | Use different name |
| Invalid type ID | Non-existent type | Query /organization-types first |
| Invalid status ID | Non-existent status | Query /organization-statuses first |
async function safeCreateOrganization(data) {
try {
return await createOrganization(data);
} catch (error) {
if (error.status === 422 && error.detail?.includes('already been taken')) {
// Organization exists - find and return it
const existing = await findOrganizationByName(data.name);
return existing;
}
if (error.status === 401) {
throw new Error('API key invalid or expired. Check IT_GLUE_API_KEY.');
}
throw error;
}
}