TypeScript SDK Reference

The cPod TypeScript SDK gives you typed access to the 6 domains of the Enterprise Data Model: People, Technology, Licenses, Assets, Risk & Compliance, and Common.

Package: @cpod/sdk
NPM: npmjs.com/package/@cpod/sdk
Source: github.com/cpod-ai/cpod-sdk/tree/main/sdks/typescript
Node.js: ≥ 18.0.0


Installation

npm install @cpod/sdk
# or
pnpm add @cpod/sdk
# or
yarn add @cpod/sdk

Basic Import

import { CpodClient } from '@cpod/sdk'
 
const client = new CpodClient({
  apiKey: process.env.CPOD_API_KEY!,
})

Quick Example

The following shows a representative real-world query: look up a person, find the technology assets they have access to, check their active entitlements, and list any vulnerabilities on those assets.

import { CpodClient } from '@cpod/sdk'
 
const client = new CpodClient({ apiKey: process.env.CPOD_API_KEY! })
 
async function personSecurityProfile(personEmail: string) {
  // 1. Find the person by email
  const { data: people } = await client.people.list({ search: personEmail })
  const person = people[0]
  if (!person) throw new Error(`Person not found: ${personEmail}`)
 
  console.log(`Person: ${person.displayName} (${person.type}, ${person.status})`)
 
  // 2. Get all technology assets they have access to
  const { data: entitlements } = await client.technology.getEntitlements(person.id)
  const activeEntitlements = entitlements.filter(e => e.status === 'active')
 
  console.log(`Active entitlements: ${activeEntitlements.length}`)
 
  // 3. For each asset, check for open vulnerabilities
  const assetIds = [...new Set(activeEntitlements.map(e => e.assetId))]
 
  const vulnChecks = await Promise.all(
    assetIds.map(assetId =>
      client.risk.listVulnerabilities({ affectedAssetId: assetId, status: 'open' })
    )
  )
 
  const criticalVulns = vulnChecks
    .flatMap(r => r.data)
    .filter(v => v.severity === 'critical' || v.severity === 'high')
 
  console.log(`Critical/High open vulnerabilities on accessible assets: ${criticalVulns.length}`)
 
  return { person, activeEntitlements, criticalVulns }
}

CpodClient

The root client. All domain services are namespaced under it.

const client = new CpodClient(config: CpodConfig)

CpodConfig

interface CpodConfig {
  /** Your cPod API key. Required. */
  apiKey: string
  /** Base URL of the cPod API. Default: 'https://api.cyberpod.app' */
  baseUrl?: string
  /** Request timeout in milliseconds. Default: 30000 */
  timeout?: number
}

Domain Service Properties

PropertyTypeDomain
client.peoplePeopleServicePeople
client.groupsGroupServicePeople
client.technologyTechnologyServiceTechnology
client.licensesLicenseServiceLicenses
client.assetsAssetServiceAssets
client.riskRiskServiceRisk & Compliance
client.relationshipsRelationshipServiceCommon
client.dataSourcesDataSourceServiceCommon

People Domain

PeopleServiceclient.people

list(opts?, requestOpts?)

const { data: people, total } = await client.people.list({
  type: 'employee',            // 'employee' | 'contractor' | 'vendor' | 'partner' | 'service_account'
  status: 'active',            // 'active' | 'on_leave' | 'terminated' | 'suspended'
  department: 'Engineering',
  search: 'jane',              // searches displayName, email, employeeId
  page: 1,
  pageSize: 50,
})

get(id, requestOpts?)

const person = await client.people.get('person-uuid')
// person.email, person.displayName, person.department, person.managerId, ...

create(input, requestOpts?)

const newPerson = await client.people.create({
  email: 'jane.doe@acme.com',
  displayName: 'Jane Doe',
  firstName: 'Jane',
  lastName: 'Doe',
  type: 'employee',
  department: 'Engineering',
  title: 'Senior Engineer',
  location: { site: 'HQ', city: 'San Francisco', country: 'US', remote: false },
  managerId: 'manager-uuid',
})

update(id, input, requestOpts?)

const updated = await client.people.update('person-uuid', {
  title: 'Staff Engineer',
  department: 'Platform Engineering',
})

deactivate(id, requestOpts?)

// Transitions person status to 'terminated'. Does not revoke entitlements automatically.
const deactivated = await client.people.deactivate('person-uuid')

GroupServiceclient.groups

list(requestOpts?)

const { data: groups } = await client.groups.list()

get(id, requestOpts?)

const group = await client.groups.get('group-uuid')
// group.name, group.type, group.members, group.ownerId, ...

create(input, requestOpts?)

const group = await client.groups.create({
  name: 'Platform Team',
  type: 'team',
  description: 'Core platform engineering team',
  ownerId: 'person-uuid',
  source: 'manual',
})

addMember(groupId, personId, role?, requestOpts?)

await client.groups.addMember('group-uuid', 'person-uuid', 'lead')

removeMember(groupId, personId, requestOpts?)

await client.groups.removeMember('group-uuid', 'person-uuid')

Technology Domain

TechnologyServiceclient.technology

list(requestOpts?)

const { data: assets } = await client.technology.list()
const criticalApps = assets.filter(a => a.criticality === 'critical' && a.status === 'active')

get(id, requestOpts?)

const asset = await client.technology.get('asset-uuid')
// asset.name, asset.vendor, asset.criticality, asset.dataClassification, ...

create(input, requestOpts?)

const asset = await client.technology.create({
  name: 'salesforce-crm',
  displayName: 'Salesforce CRM',
  type: 'saas',
  category: 'CRM',
  vendor: 'Salesforce',
  owner: { personId: 'owner-uuid' },
  environment: 'production',
  hosting: 'saas',
  criticality: 'critical',
  dataClassification: 'confidential',
  tags: ['sales', 'crm'],
})

update(id, input, requestOpts?)

const updated = await client.technology.update('asset-uuid', {
  version: '2024.3',
  status: 'active',
})

getEntitlements(assetId, requestOpts?)

Returns all AccessEntitlement records for the given asset — use this for access reviews.

const { data: entitlements } = await client.technology.getEntitlements('asset-uuid')
 
// Filter to only active, non-expiring entitlements held by humans (not groups)
const activeHumanAccess = entitlements.filter(
  e => e.status === 'active' && e.principalType === 'person'
)

grantEntitlement(input, requestOpts?)

const entitlement = await client.technology.grantEntitlement({
  assetId: 'asset-uuid',
  principalId: 'person-uuid',
  principalType: 'person',
  entitlementType: 'read',
  expiresAt: '2026-12-31T23:59:59Z',
})

revokeEntitlement(id, requestOpts?)

const revoked = await client.technology.revokeEntitlement('entitlement-uuid')
// revoked.status === 'revoked'

Licenses Domain

LicenseServiceclient.licenses

list(requestOpts?)

const { data: licenses } = await client.licenses.list()
const overAllocated = licenses.filter(l => l.complianceStatus === 'over_allocated')
const expiringSoon = licenses.filter(l => l.status === 'expiring_soon')

get(id, requestOpts?)

const license = await client.licenses.get('license-uuid')
// license.totalSeats, license.usedSeats, license.availableSeats, license.complianceStatus

create(input, requestOpts?)

const license = await client.licenses.create({
  vendor: 'Atlassian',
  productName: 'Jira Software',
  productSku: 'JIRA-CLOUD-ENTERPRISE',
  licenseType: 'subscription',
  totalSeats: 500,
  cost: { amount: 45000, currency: 'USD', billingCycle: 'annual' },
  purchaseDate: '2026-01-01',
  expiryDate: '2027-01-01',
  autoRenew: true,
})

getAssignments(licenseId, requestOpts?)

const { data: assignments } = await client.licenses.getAssignments('license-uuid')
const activeAssignments = assignments.filter(a => a.status === 'active')

assign(licenseId, assigneeId, assigneeType, requestOpts?)

const assignment = await client.licenses.assign(
  'license-uuid',
  'person-uuid',
  'person'
)

unassign(assignmentId, requestOpts?)

await client.licenses.unassign('assignment-uuid')

Assets Domain

AssetServiceclient.assets

listPhysical(requestOpts?) / getPhysical(id, requestOpts?)

const { data: laptops } = await client.assets.listPhysical()
const lost = laptops.filter(a => a.status === 'lost_stolen')
 
const laptop = await client.assets.getPhysical('asset-uuid')

createPhysical(input, requestOpts?)

const laptop = await client.assets.createPhysical({
  assetTag: 'HW-00423',
  name: "Jane's MacBook Pro",
  model: 'MacBook Pro 14-inch, M3 Pro',
  manufacturer: 'Apple',
  serialNumber: 'C02XG1JFJGH5',
  type: 'laptop',
  status: 'in_use',
  assignedTo: { personId: 'person-uuid' },
  purchaseDate: '2025-09-01',
  warrantyExpiry: '2028-09-01',
  os: { name: 'macOS', version: '15.3' },
  managedBy: 'jamf',
})

listCloud(requestOpts?) / getCloud(id, requestOpts?)

const { data: resources } = await client.assets.listCloud()
const runningEC2 = resources.filter(
  r => r.provider === 'aws' && r.resourceType === 'AWS::EC2::Instance' && r.status === 'running'
)

syncCloud(requestOpts?)

Enqueues an on-demand sync from all active cloud DataSource integrations.

await client.assets.syncCloud()
// Then poll status via client.dataSources.getSyncStatus(dataSourceId)

Risk & Compliance Domain

RiskServiceclient.risk

listVulnerabilities(opts?, requestOpts?)

const { data: vulns } = await client.risk.listVulnerabilities({
  severity: 'critical',
  status: 'open',
  source: 'qualys',
})

getVulnerability(id, requestOpts?)

const vuln = await client.risk.getVulnerability('vuln-uuid')
// vuln.cveId, vuln.cvssScore, vuln.affectedAssetId, vuln.dueDate

updateVulnerabilityStatus(id, status, requestOpts?)

const updated = await client.risk.updateVulnerabilityStatus(
  'vuln-uuid',
  'in_remediation'
)

listControls(framework?, requestOpts?)

// All controls
const { data: allControls } = await client.risk.listControls()
 
// SOC 2 controls only
const { data: soc2Controls } = await client.risk.listControls('soc2')
const gaps = soc2Controls.filter(c => c.status !== 'implemented' && c.status !== 'not_applicable')

getControl(id, requestOpts?)

const control = await client.risk.getControl('control-uuid')
// control.framework, control.controlId, control.evidence, control.status

listRisks(requestOpts?) / getRisk(id, requestOpts?)

const { data: risks } = await client.risk.listRisks()
const openHighRisks = risks.filter(r => r.status === 'open' && r.riskScore >= 15)

createRisk(input, requestOpts?)

const risk = await client.risk.createRisk({
  title: 'Unpatched critical CVEs in production SaaS tools',
  description: 'Multiple production SaaS applications have critical CVEs that have not been addressed.',
  category: 'security',
  likelihood: 'likely',
  impact: 'major',
  owner: 'ciso-person-uuid',
  linkedVulnerabilityIds: ['vuln-uuid-1', 'vuln-uuid-2'],
  mitigationPlan: 'Engage vendors for patches; apply compensating controls in the interim.',
  dueDate: '2026-07-01',
})

Common Domain

RelationshipServiceclient.relationships

list(sourceId?, targetId?, requestOpts?)

// All relationships involving a person as source
const { data: rels } = await client.relationships.list('person-uuid')

create(input, requestOpts?)

const rel = await client.relationships.create({
  sourceId: 'person-uuid',
  sourceType: 'Person',
  targetId: 'asset-uuid',
  targetType: 'TechnologyAsset',
  relationshipType: 'owns',
  confidence: 0.95,
  source: 'manual',
})

delete(id, requestOpts?)

await client.relationships.delete('relationship-uuid')

traverse(entityId, entityType, depth?, requestOpts?)

Graph traversal — returns all entities connected within depth hops.

// Find everything connected to this person within 2 hops
const nodes = await client.relationships.traverse('person-uuid', 'Person', 2)
 
for (const node of nodes) {
  console.log(`${node.entityType} ${node.entityId} at depth ${node.depth} via ${node.viaRelationship.relationshipType}`)
}

DataSourceServiceclient.dataSources

list(requestOpts?)

const { data: sources } = await client.dataSources.list()
const errored = sources.filter(s => s.status === 'error')

create(input, requestOpts?)

const source = await client.dataSources.create({
  name: 'Production Okta',
  type: 'okta',
  config: {
    domain: 'acme.okta.com',
    apiToken: process.env.OKTA_API_TOKEN!,
  },
})

triggerSync(id, requestOpts?)

await client.dataSources.triggerSync('datasource-uuid')

getSyncStatus(id, requestOpts?)

const status = await client.dataSources.getSyncStatus('datasource-uuid')
// status.running, status.entitiesProcessed, status.errors, status.completedAt

Error Handling

All SDK methods throw typed error classes that extend CpodError.

import {
  CpodError,
  ApiError,
  AuthenticationError,
  NotFoundError,
  RateLimitError,
  TimeoutError,
} from '@cpod/sdk'
 
try {
  const person = await client.people.get('nonexistent-uuid')
} catch (err) {
  if (err instanceof NotFoundError) {
    console.error('Person not found:', err.message)
  } else if (err instanceof AuthenticationError) {
    console.error('Invalid API key or insufficient permissions')
  } else if (err instanceof RateLimitError) {
    console.error(`Rate limited. Retry after ${err.retryAfter} seconds`)
  } else if (err instanceof TimeoutError) {
    console.error('Request timed out')
  } else if (err instanceof ApiError) {
    console.error(`API error ${err.status}: ${err.message}`)
  } else if (err instanceof CpodError) {
    console.error('cPod SDK error:', err.message)
  }
}

The SDK automatically retries on transient errors (429, 500, 502, 503, 504) with exponential backoff up to 3 attempts.


Request Options

Every method accepts an optional RequestOptions argument as its last parameter.

interface RequestOptions {
  /** AbortSignal for cancellation. */
  signal?: AbortSignal
  /** Override the client-level timeout in milliseconds. */
  timeout?: number
  /** Additional headers merged into this specific request. */
  headers?: Record<string, string>
}

Example — cancellable request with a custom timeout:

const controller = new AbortController()
setTimeout(() => controller.abort(), 5000)
 
const person = await client.people.get('person-uuid', {
  signal: controller.signal,
  timeout: 5000,
})