Skip to main content

Core Platform Guide

The Core Platform API provides foundational services that underpin all SensorUp operations. It includes authentication (su-auth), user management (su-user), core infrastructure (su-backend), geospatial services (su-maps), data catalogs (su-catalog), and event streaming (su-eventhub).

Overview

The Core Platform enables:
  • Authentication: Session management, API keys, and federated sign-in
  • User Management: User profiles, permissions, and device tracking
  • Geospatial Services: Maps, location queries, and spatial operations
  • Data Catalogs: Schema registry and metadata management
  • Event Streaming: Real-time event subscriptions and notifications
  • Core Infrastructure: Configuration, health checks, and system operations

Authentication (su-auth)

For comprehensive authentication documentation, see the Authentication Guide.

Quick Reference

Session-based Authentication:
mutation SignIn($input: AuthSignInInput!) {
  signIn(input: $input) {
    session {
      username
      authenticated
      expiresAt
      expiresAtHard
      userGroup
    }
    correlationId
    errors { message type }
  }
}
Check Current Session:
query {
  session {
    username
    authenticated
    expiresAt
    userGroup
    lastAuthenticatedAt
  }
}
API Key Creation:
mutation CreateAPIKey($input: AuthCreateAPIKeyInput!) {
  createAPIKey(input: $input) {
    apiKey {
      apiKeyId
      apiKeySessionId
      expiresAt
    }
    correlationId
    errors { message type }
  }
}

Session Lifetimes

Client TypeHard ExpirySoft Expiry (Idle)
Explorer (Web)30 days7 days
SensorHub Android365 days60 days
SensorHub iOS365 days60 days
API Key365 days60 days

Authentication Methods

  • Cookie: sensorup_sessionid (auto-set in browser)
  • Header: x-sensorup-sessionid (for API clients and M2M)
curl -X POST https://customer-demo.sensorup.com/api/graphql \
  -H "Content-Type: application/json" \
  -H "x-sensorup-sessionid: YOUR_SESSION_ID" \
  -d '{"query":"{ session { username } }"}'

User Management (su-user)

Query User Profile

query GetUser($userId: ID!) {
  user(id: $userId) {
    userId
    username
    email
    firstName
    lastName
    phoneNumber
    preferredLanguage
    timezone
    groups
    permissions {
      resource
      actions
    }
    devices {
      deviceKey
      name
      remembered
      lastSignedInAt
      lastIpAddress
    }
  }
}

Update User Profile

mutation UpdateUser($input: UpdateUserInput!) {
  updateUser(input: $input) {
    user {
      userId
      firstName
      lastName
      email
      phoneNumber
    }
    correlationId
    errors {
      message
      type
    }
  }
}
Variables:
{
  "input": {
    "userId": "user-123",
    "firstName": "John",
    "lastName": "Smith",
    "phoneNumber": "+1-555-0100",
    "timezone": "America/Edmonton"
  }
}

Query User Permissions

query GetUserPermissions($userId: ID!) {
  user(id: $userId) {
    userId
    username
    groups
    permissions {
      resource
      actions
      scope
    }
    roles {
      roleId
      roleName
      permissions {
        resource
        actions
      }
    }
  }
}

List Users in Group

query GetGroupUsers($group: ID!) {
  users(group: $group) {
    all(first: 100) {
      edges {
        node {
          userId
          username
          email
          firstName
          lastName
          active
        }
      }
      pageInfo {
        hasNextPage
        endCursor
      }
    }
  }
}

Device Management

query GetUserDevices($userId: ID!) {
  user(id: $userId) {
    devices {
      deviceKey
      name
      remembered
      createdAt
      lastSignedInAt
      lastIpAddress
      userAgent
    }
  }
}
Forget Device:
mutation ForgetDevice($input: AuthForgetSpecificDevicesInput!) {
  forgetDevices(input: $input) {
    session {
      username
    }
    correlationId
    errors { message type }
  }
}

Geospatial Services (su-maps)

Query Map Configuration

query GetMapConfig {
  maps {
    config {
      defaultCenter {
        lat
        lon
      }
      defaultZoom
      baseLayers {
        id
        name
        type
        url
        attribution
      }
      overlayLayers {
        id
        name
        type
        url
      }
    }
  }
}

Get Map Tiles

query GetMapTiles($bounds: BoundsInput!, $zoom: Int!) {
  maps {
    tiles(bounds: $bounds, zoom: $zoom) {
      tileUrl
      bounds {
        north
        south
        east
        west
      }
      zoom
    }
  }
}
Variables:
{
  "bounds": {
    "north": 51.1,
    "south": 51.0,
    "east": -114.0,
    "west": -114.1
  },
  "zoom": 12
}

Geocoding

query Geocode($address: String!) {
  maps {
    geocode(address: $address) {
      results {
        formattedAddress
        geometry {
          location {
            lat
            lon
          }
          bounds {
            north
            south
            east
            west
          }
        }
        placeId
        types
      }
    }
  }
}
Variables:
{
  "address": "Calgary, Alberta, Canada"
}

Reverse Geocoding

query ReverseGeocode($lat: Float!, $lon: Float!) {
  maps {
    reverseGeocode(lat: $lat, lon: $lon) {
      results {
        formattedAddress
        addressComponents {
          longName
          shortName
          types
        }
        placeId
      }
    }
  }
}
Variables:
{
  "lat": 51.0447,
  "lon": -114.0719
}

Spatial Queries

query FindNearbyAssets($location: LocationInput!, $radiusKm: Float!) {
  maps {
    findNearby(location: $location, radius: $radiusKm) {
      results {
        id
        type
        distance
        geometry {
          type
          coordinates
        }
        properties
      }
    }
  }
}
Variables:
{
  "location": {
    "lat": 51.0447,
    "lon": -114.0719
  },
  "radiusKm": 10.0
}

GeoJSON Support

The platform supports full GeoJSON geometry types:
type GeoJSONGeometry {
  type: GeoJSONType!  # Point, LineString, Polygon, etc.
  coordinates: GeoJSONCoordinates
  bbox: [Float]
}

enum GeoJSONType {
  Point
  MultiPoint
  LineString
  MultiLineString
  Polygon
  MultiPolygon
  GeometryCollection
  Feature
  FeatureCollection
}
Example Point:
{
  "type": "Point",
  "coordinates": [-114.0719, 51.0447]
}
Example Polygon:
{
  "type": "Polygon",
  "coordinates": [[
    [-114.073, 51.045],
    [-114.071, 51.045],
    [-114.071, 51.044],
    [-114.073, 51.044],
    [-114.073, 51.045]
  ]]
}

Data Catalogs (su-catalog)

Query Catalog Entries

query GetCatalogEntries {
  catalog {
    entries(first: 100) {
      edges {
        node {
          id
          name
          description
          schema
          dataType
          category
          tags
          createdAt
          updatedAt
        }
      }
      pageInfo {
        hasNextPage
        endCursor
      }
    }
  }
}

Get Specific Catalog Entry

query GetCatalogEntry($id: ID!) {
  catalog {
    entry(id: $id) {
      id
      name
      description
      schema
      dataType
      category
      tags
      metadata
      validationRules {
        rule
        message
      }
    }
  }
}

Create Catalog Entry

mutation CreateCatalogEntry($input: CreateCatalogEntryInput!) {
  createCatalogEntry(input: $input) {
    catalogEntry {
      id
      name
      schema
    }
    correlationId
    errors {
      message
      type
    }
  }
}
Variables:
{
  "input": {
    "id": "pressure-reading",
    "name": "Pressure Reading",
    "description": "Equipment pressure sensor reading",
    "dataType": "numeric",
    "schema": {
      "type": "object",
      "properties": {
        "value": { "type": "number" },
        "unit": { "type": "string", "enum": ["psi", "kPa", "bar"] },
        "timestamp": { "type": "string", "format": "date-time" }
      },
      "required": ["value", "unit", "timestamp"]
    },
    "category": "sensor-data",
    "tags": ["pressure", "sensor", "telemetry"]
  }
}

Query by Category

query GetCatalogByCategory($category: String!) {
  catalog {
    byCategory(category: $category) {
      id
      name
      description
      dataType
    }
  }
}
Variables:
{
  "category": "sensor-data"
}

Event Streaming (su-eventhub)

Subscribe to Events

subscription OnEvents($filter: EventFilter) {
  events(filter: $filter) {
    eventId
    eventType
    source
    timestamp
    data
    correlationId
  }
}
Variables (Filter by Event Type):
{
  "filter": {
    "eventTypes": ["ASSET_CREATED", "ASSET_UPDATED", "ISSUE_CREATED"]
  }
}

Publish Event

mutation PublishEvent($input: PublishEventInput!) {
  publishEvent(input: $input) {
    event {
      eventId
      eventType
      timestamp
    }
    correlationId
    errors {
      message
      type
    }
  }
}
Variables:
{
  "input": {
    "eventType": "CUSTOM_EVENT",
    "source": "integration-service",
    "data": {
      "action": "data_sync_completed",
      "recordsProcessed": 1500,
      "duration": 45.2
    }
  }
}

Query Event History

query GetEventHistory($filter: EventFilter!, $first: Int!) {
  eventHub {
    history(filter: $filter, first: $first) {
      edges {
        node {
          eventId
          eventType
          source
          timestamp
          data
        }
      }
      pageInfo {
        hasNextPage
        endCursor
      }
    }
  }
}
Variables:
{
  "filter": {
    "eventTypes": ["ASSET_CREATED"],
    "from": "2025-11-01T00:00:00Z",
    "to": "2025-11-05T23:59:59Z"
  },
  "first": 100
}

Event Types

Common system event types:
Event TypeDescription
ASSET_CREATEDNew asset created
ASSET_UPDATEDAsset modified
ASSET_DELETEDAsset removed
ISSUE_CREATEDNew issue opened
ISSUE_UPDATEDIssue modified
ISSUE_CLOSEDIssue resolved and closed
DETECTION_CREATEDNew detection recorded
FORM_SUBMITTEDXForm response submitted
USER_SIGNED_INUser authentication
API_KEY_CREATEDNew API key generated

Core Infrastructure (su-backend)

System Configuration

query GetConfig {
  config {
    environment
    version
    features {
      name
      enabled
      configuration
    }
    auth {
      loginEnabled
      ssoEnabled
      ssoUrl
      mfaRequired
    }
    integrations {
      name
      type
      endpoint
      active
    }
  }
}

Health Check

query HealthCheck {
  health {
    status
    version
    timestamp
    services {
      name
      status
      latency
      lastCheck
    }
  }
}

Feature Flags

query GetFeatureFlags {
  features {
    all {
      featureId
      name
      enabled
      rolloutPercentage
      conditions {
        type
        value
      }
    }
  }
}
Check Specific Feature:
query IsFeatureEnabled($featureId: ID!, $context: FeatureContext) {
  features {
    isEnabled(featureId: $featureId, context: $context)
  }
}

System Metrics

query GetSystemMetrics {
  metrics {
    apiCalls {
      total
      byEndpoint {
        endpoint
        count
        avgLatency
      }
    }
    errors {
      total
      byType {
        type
        count
      }
    }
    performance {
      avgResponseTime
      p95ResponseTime
      p99ResponseTime
    }
  }
}

Common Patterns

Authentication Flow

// 1. Sign in
const { data } = await client.mutate({
  mutation: SIGN_IN,
  variables: {
    input: {
      loginUsername: 'user@example.com',
      password: 'password',
      clientApplicationType: 'EXPLORER'
    }
  }
})

// 2. Store session ID
const sessionId = data.signIn.session.sessionId

// 3. Use in subsequent requests
const result = await fetch('https://customer-demo.sensorup.com/api/graphql', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-sensorup-sessionid': sessionId
  },
  body: JSON.stringify({ query: '{ session { username } }' })
})

Geospatial Queries

// Find assets near a location
async function findAssetsNearLocation(lat, lon, radiusKm) {
  const { data } = await client.query({
    query: FIND_NEARBY,
    variables: { location: { lat, lon }, radiusKm }
  })

  return data.maps.findNearby.results
}

// Geocode an address
async function getCoordinates(address) {
  const { data } = await client.query({
    query: GEOCODE,
    variables: { address }
  })

  return data.maps.geocode.results[0].geometry.location
}

Event Streaming

// Subscribe to real-time events
const subscription = client.subscribe({
  query: ON_EVENTS,
  variables: {
    filter: {
      eventTypes: ['ASSET_CREATED', 'ISSUE_CREATED']
    }
  }
}).subscribe({
  next: ({ data }) => {
    console.log('New event:', data.events)
    handleEvent(data.events)
  },
  error: (error) => console.error('Subscription error:', error)
})

// Cleanup
subscription.unsubscribe()

Catalog-Driven Forms

// Use catalog to validate form data
async function validateFormData(dataType, data) {
  // Get schema from catalog
  const { data: catalogData } = await client.query({
    query: GET_CATALOG_ENTRY,
    variables: { id: dataType }
  })

  const schema = catalogData.catalog.entry.schema

  // Validate against schema
  const valid = validateAgainstJsonSchema(data, schema)

  return valid
}

Best Practices

1. Session Management

Monitor session expiration and refresh proactively:
// Check session expiration
const { data } = await client.query({ query: GET_SESSION })
const expiresAt = new Date(data.session.expiresAt)
const now = new Date()

// Refresh if expiring soon (within 1 hour)
if (expiresAt - now < 3600000) {
  await refreshSession()
}

2. Geospatial Performance

Use appropriate zoom levels and bounds for map tiles:
# Good - reasonable bounds
maps { tiles(bounds: { ... }, zoom: 12) }

# Avoid - excessive detail over large area
maps { tiles(bounds: { ... }, zoom: 18) }

3. Event Filtering

Subscribe only to needed event types:
# Good - filtered subscription
subscription { events(filter: { eventTypes: ["ASSET_CREATED"] }) }

# Avoid - unfiltered (high volume)
subscription { events }

4. Catalog Validation

Leverage catalog schemas for data validation:
# 1. Get schema from catalog
catalog { entry(id: "sensor-reading") { schema } }

# 2. Validate data client-side before submission
# 3. Submit validated data

5. Permission Checks

Always verify user permissions before restricted operations:
query CheckPermission($userId: ID!, $resource: String!, $action: String!) {
  user(id: $userId) {
    permissions {
      resource
      actions
    }
  }
}

Error Handling

Platform mutations return consistent error formats:
{
  "data": {
    "updateUser": {
      "user": null,
      "correlationId": "abc-123",
      "errors": [
        {
          "message": "Invalid email address format",
          "type": "VALIDATION_ERROR"
        }
      ]
    }
  }
}
Common error types:
  • AUTHENTICATION_FAILED: Invalid credentials
  • AUTHORIZATION_FAILED: Insufficient permissions
  • VALIDATION_ERROR: Input validation failed
  • NOT_FOUND: Resource does not exist
  • DUPLICATE: Resource already exists
  • RATE_LIMIT_EXCEEDED: Too many requests