Skip to main content

Connected Asset Management Guide

The Connected Asset Management (CAM) API provides comprehensive asset management capabilities for connected operations through the su-cam-assets subgraph. CAM handles asset types, asset properties, asset hierarchy, and geospatial operations.

Overview

CAM enables you to:
  • Define and manage asset types with custom property schemas
  • Create and organize assets with hierarchical relationships
  • Query assets by type, location, and properties
  • Perform batch operations for large-scale asset management
  • Track asset states and status changes
  • Manage geospatial data and relationships

Core Concepts

Asset Types

Asset types define the schema and structure for assets. Each asset type specifies:
  • Properties: Custom attributes and their data types
  • Hierarchy: Parent-child relationships between assets
  • Extensions: External data source integrations
  • Status tracking: Asset state management configuration

Assets

Assets are instances of asset types representing physical or logical entities in your connected operations:
  • Sites: Top-level geographic locations
  • Equipment: Major operational assets
  • Components: Sub-components within equipment
  • Wells: Oil and gas well assets
  • Pipelines: Pipeline infrastructure
  • Unattributed: Assets not yet assigned to a specific type

Asset Hierarchy

Assets can be organized in parent-child relationships, enabling:
  • Multi-level organizational structures
  • Inherited properties and configurations
  • Hierarchical queries and filtering
  • Geographic nesting (e.g., equipment within sites)

Querying Assets

Get All Asset Types

query GetAssetTypes {
  assetTypes {
    all(first: 20) {
      edges {
        node {
          assetTypeId
          name
          description
          properties {
            id
            name
            dataType
            required
          }
        }
      }
      pageInfo {
        hasNextPage
        endCursor
      }
    }
  }
}

Get Specific Asset Type

query GetAssetType($assetTypeId: ID!) {
  assetTypes {
    byId(assetTypeId: $assetTypeId) {
      assetTypeId
      name
      description
      properties {
        id
        name
        dataType
        required
        defaultValue
      }
      extensions {
        id
        name
        connectionDetails {
          ... on AssetTypeExtensionConnectionSimple {
            idProperty
            idColumn
            stateProperty
          }
        }
      }
    }
  }
}
Variables:
{
  "assetTypeId": "site"
}

Query Assets by Type

query GetAssetsByType($assetTypeId: ID!) {
  camAssets(assetTypeId: $assetTypeId) {
    all(first: 20) {
      edges {
        node {
          id
          name
          description
          assetTypeId
          active
          geometry {
            type
            coordinates
          }
          properties
          parent {
            id
            name
          }
          children {
            id
            name
            assetTypeId
          }
        }
      }
      pageInfo {
        hasNextPage
        endCursor
      }
    }
  }
}
Variables:
{
  "assetTypeId": "equipment"
}

Query Asset by ID

query GetAsset($id: ID!) {
  camAssets {
    byId(id: $id) {
      id
      name
      description
      assetTypeId
      active
      geometry {
        type
        coordinates
      }
      properties
      parent {
        id
        name
        assetTypeId
      }
      status {
        statusId
        label
        setAt
        setBy
      }
    }
  }
}
Variables:
{
  "id": "site-001"
}

Filter and Search Assets

query SearchAssets($assetTypeId: ID!, $searchText: String!) {
  camAssets(assetTypeId: $assetTypeId) {
    all(
      first: 20
      fullTextSearch: { text: $searchText }
      filter: { active: true }
    ) {
      edges {
        node {
          id
          name
          description
          assetTypeId
        }
      }
      totalCount
    }
  }
}
Variables:
{
  "assetTypeId": "site",
  "searchText": "compressor"
}

Creating and Updating Assets

Create an Asset

mutation CreateAsset($input: CreateAssetInput!) {
  createAsset(input: $input) {
    asset {
      id
      name
      assetTypeId
      properties
    }
    correlationId
    errors {
      message
      type
    }
  }
}
Variables:
{
  "input": {
    "assetId": "site-abc",
    "name": "Compressor Station ABC",
    "description": "Primary compression facility",
    "assetTypeId": "site",
    "active": true,
    "group": "your-tenant-id",
    "geometry": {
      "type": "Point",
      "coordinates": [-114.0719, 51.0447]
    },
    "propertyValues": [
      {
        "propertyId": "operator",
        "value": "ACME Energy"
      },
      {
        "propertyId": "capacity",
        "value": "5000"
      }
    ]
  }
}

Update Asset Properties

mutation UpdateAssetProperty($input: UpdateAssetPropertyInput!) {
  updateAssetProperty(input: $input) {
    asset {
      id
      properties
    }
    correlationId
    errors {
      message
      type
    }
  }
}
Variables:
{
  "input": {
    "assetId": "site-abc",
    "group": "your-tenant-id",
    "propertyValues": [
      {
        "propertyId": "capacity",
        "value": "6000"
      }
    ]
  }
}

Update Asset Geometry

mutation UpdateAssetGeometry($input: UpdateAssetGeometryInput!) {
  updateAssetGeometry(input: $input) {
    asset {
      id
      geometry {
        type
        coordinates
      }
    }
    correlationId
    errors {
      message
      type
    }
  }
}
Variables:
{
  "input": {
    "assetId": "site-abc",
    "group": "your-tenant-id",
    "geometry": {
      "type": "Polygon",
      "coordinates": [[
        [-114.073, 51.045],
        [-114.071, 51.045],
        [-114.071, 51.044],
        [-114.073, 51.044],
        [-114.073, 51.045]
      ]]
    }
  }
}

Create Asset Status Record

mutation CreateAssetStatus($input: CreateAssetStatusInput!) {
  createAssetStatus(input: $input) {
    assetStatus {
      assetId
      statusId
      label
      setAt
      setBy
    }
    correlationId
    errors {
      message
      type
    }
  }
}
Variables:
{
  "input": {
    "assetId": "equipment-001",
    "group": "your-tenant-id",
    "statusId": "operational",
    "label": "Fully Operational",
    "notes": "Post-maintenance verification complete"
  }
}

Batch Operations

For large-scale asset creation or updates, CAM provides batch upsert capabilities.

Generate Batch Upload URL

query GenerateUploadUrl($input: GenerateBatchUpsertUploadUrlInput!) {
  generateBatchUpsertUploadUrl(input: $input) {
    uploadUrl
    batchUpsertReference
    expiresAt
  }
}
Variables:
{
  "input": {
    "assetTypeId": "equipment",
    "fileFormat": "CSV",
    "fileName": "equipment_batch_update.csv",
    "fileSizeBytes": 2048000,
    "group": "your-tenant-id",
    "expirationMinutes": 60
  }
}

Upload File and Trigger Batch Upsert

// 1. Get the upload URL
const { data } = await client.query({
  query: GENERATE_UPLOAD_URL,
  variables: { input: uploadParams }
})

// 2. Upload file to S3
await fetch(data.generateBatchUpsertUploadUrl.uploadUrl, {
  method: 'PUT',
  headers: { 'Content-Type': 'text/csv' },
  body: csvFileContent
})

// 3. Trigger batch processing
await client.mutate({
  mutation: gql`
    mutation BatchUpsert($ref: String!) {
      manageCamAssets(dryRun: false) {
        batchUpsert(batchUpsertReference: $ref) {
          success
          processedCount
          errors {
            row
            message
          }
        }
      }
    }
  `,
  variables: {
    ref: data.generateBatchUpsertUploadUrl.batchUpsertReference
  }
})

Asset Hierarchy Operations

Query Asset Hierarchy

query GetAssetHierarchy($rootId: ID!) {
  camAssets {
    byId(id: $rootId) {
      id
      name
      assetTypeId
      children {
        id
        name
        assetTypeId
        children {
          id
          name
          assetTypeId
        }
      }
    }
  }
}

Create Child Asset

mutation CreateChildAsset($input: CreateAssetInput!) {
  createAsset(input: $input) {
    asset {
      id
      name
      parent {
        id
        name
      }
    }
    correlationId
    errors {
      message
      type
    }
  }
}
Variables:
{
  "input": {
    "assetId": "compressor-001",
    "name": "Compressor Unit 1",
    "assetTypeId": "equipment",
    "active": true,
    "group": "your-tenant-id",
    "parent": {
      "assetId": "site-abc",
      "assetTypeId": "site"
    },
    "geometry": {
      "type": "Point",
      "coordinates": [-114.0720, 51.0448]
    }
  }
}

Geospatial Queries

CAM supports full GeoJSON geometry types for asset locations:

Query Assets by Bounding Box

query GetAssetsInBounds(
  $assetTypeId: ID!
  $minLon: Float!
  $minLat: Float!
  $maxLon: Float!
  $maxLat: Float!
) {
  camAssets(assetTypeId: $assetTypeId) {
    all(
      first: 100
      filter: {
        geometry: {
          bbox: [$minLon, $minLat, $maxLon, $maxLat]
        }
      }
    ) {
      edges {
        node {
          id
          name
          geometry {
            type
            coordinates
            bbox
          }
        }
      }
    }
  }
}

Supported Geometry Types

CAM supports all GeoJSON geometry types:
  • Point: Single location [-114.0719, 51.0447]
  • LineString: Linear features (pipelines, roads)
  • Polygon: Areas and boundaries
  • MultiPoint, MultiLineString, MultiPolygon: Collections
  • GeometryCollection: Mixed geometry types

Asset References

Query lightweight asset references for dropdowns and lookups:
query GetAssetReferences {
  camAssetReferences {
    all(first: 100) {
      edges {
        node {
          id
          name
          assetTypeId
        }
      }
    }
  }
}

CAM Engine and Datasets

Query available datasets and engine configuration:
query GetCamEngine {
  camEngine {
    datasets {
      id
      name
      assetTypeId
      sourceType
    }
  }
}

Get Datasets for Tenant

query GetCamDatasets($group: ID!) {
  camAssetsDatasets(group: $group) {
    dataset
    displayName
    assetTypeId
  }
}

Asset Configuration

Manage tenant-specific asset configurations:
query GetAssetConfigs($group: ID!) {
  assetConfigs(group: $group) {
    all {
      id
      value
    }
  }
}

Set Configuration

mutation SetAssetConfig($group: ID!, $id: ID!, $value: JSONObject!) {
  setAssetConfig(group: $group, id: $id, value: $value) {
    config {
      id
      value
    }
    correlationId
    errors {
      message
      type
    }
  }
}

Best Practices

1. Use Asset Type Filtering

Always filter by assetTypeId when querying assets to improve performance:
# Good - filtered by type
camAssets(assetTypeId: "equipment") { all(first: 20) { ... } }

# Less efficient - all asset types
camAssets { all(first: 20) { ... } }

2. Batch Operations for Scale

For bulk operations (>100 assets), use batch upsert instead of individual mutations:
# Good for >100 assets
generateBatchUpsertUploadUrlupload CSVmanageCamAssets.batchUpsert

# Use individual mutations for <100 assets
createAsset, updateAsset

3. Request Only Needed Fields

Minimize query size by selecting only required fields:
# Good - specific fields
camAssets { byId(id: "x") { id name } }

# Avoid - requesting all properties
camAssets { byId(id: "x") { id name properties ... } }

4. Use Asset References for Lookups

For dropdowns and selection lists, use camAssetReferences instead of full camAssets:
# Good - lightweight references
camAssetReferences { all { edges { node { id name } } } }

# Avoid - full asset queries for simple lookups
camAssets { all { edges { node { id name ... } } } }

5. Leverage Asset Hierarchy

Use parent-child relationships instead of flat structures:
# Good - hierarchical query
camAssets {
  byId(id: "site-001") {
    children { # Equipment at site
      children { # Components on equipment
        id
        name
      }
    }
  }
}

Error Handling

CAM mutations return errors in the standard format:
{
  "data": {
    "createAsset": {
      "asset": null,
      "correlationId": "abc-123",
      "errors": [
        {
          "message": "Asset with ID 'site-abc' already exists",
          "type": "DUPLICATE_ID"
        }
      ]
    }
  }
}
Common error types:
  • DUPLICATE_ID: Asset ID already exists
  • INVALID_PARENT: Parent asset not found or invalid type
  • INVALID_PROPERTY: Property validation failed
  • INVALID_GEOMETRY: GeoJSON geometry is malformed
  • MISSING_REQUIRED: Required field not provided