Data Export Integration

Configure and manage Parquet data exports using the GraphQL API

The Data Export Integration controls how Haltian IoT exports data as Parquet files to AWS S3. You configure it through the GraphQL API — there is exactly one integration per organization.

Prerequisites

Your user account must have the manager or sysoperator role within the organization.

Fields

FieldTypeDescription
idUUIDRead-only. Unique identifier of the integration.
descriptionStringA label for the integration. Maximum 100 characters.
dataExportStateStringControls whether exports run. See States.
metadataExportIntervalIntHow often (in minutes) to export full entity snapshots. Min 15, max 1440.
measurementExportIntervalIntHow often (in minutes) to export time-windowed sensor data. Min 15, max 1440.
stateMessageStringRead-only. Set by the system when dataExportState is error.
createdAtTimestampRead-only. When the integration was created.
updatedAtTimestampRead-only. When the integration was last updated.

States

ValueMeaning
activeExports are running on the configured schedule.
inactiveExports are paused. No data is written to S3.
errorExports are paused due to a persistent failure. The stateMessage field contains details. Setting state to error manually has the same effect as inactive. To resume, set state back to active.

Enable Exports

Create the integration with dataExportState: "active" to start exporting immediately.

mutation {
  createDataExportIntegration(object: {
    description: "My organization export"
    dataExportState: "active"
    metadataExportInterval: 1440
    measurementExportInterval: 60
  }) {
    id
    description
    dataExportState
    metadataExportInterval
    measurementExportInterval
    createdAt
  }
}

Check Status

Query the current state and last export timestamps:

query {
  dataExportIntegration {
    id
    description
    dataExportState
    stateMessage
    metadataExportInterval
    measurementExportInterval
    createdAt
    updatedAt
  }
}

If dataExportState is error, check stateMessage for the reason set by the system. To attempt recovery, set dataExportState to active again.

Update Settings

Change intervals or description without disrupting active exports:

mutation {
  updateDataExportIntegration(
    where: { id: { _eq: "your-integration-id" } }
    _set: {
      metadataExportInterval: 720
      measurementExportInterval: 30
      description: "Updated export config"
    }
  ) {
    returning {
      id
      metadataExportInterval
      measurementExportInterval
      updatedAt
    }
  }
}

Pause Exports

Set dataExportState to inactive to stop exports without deleting the integration. Resume by setting it back to active.

mutation {
  updateDataExportIntegration(
    where: { id: { _eq: "your-integration-id" } }
    _set: { dataExportState: "inactive" }
  ) {
    returning {
      id
      dataExportState
    }
  }
}

Delete the Integration

Deleting the integration permanently removes it. No further exports will run until a new integration is created.

mutation {
  deleteDataExportIntegration(
    where: { id: { _eq: "your-integration-id" } }
  ) {
    returning {
      id
    }
  }
}

How Intervals Work

There are two independent export intervals. Both are specified in minutes, with a minimum of 15 and a maximum of 1440 (24 hours).

Metadata exports (metadataExportInterval)

Each metadata export is a point-in-time snapshot of all entity data for the organization: devices, spaces, zones, device groups, keywords, and notes.

  • Each file reflects the complete state of all entities at the moment the export ran — not a delta.
  • Entity changes (such as device renames or space reassignments) that occur between two exports will not appear until the next scheduled run. Use a shorter interval if your pipeline requires low-latency visibility into entity changes.
  • The exact capture time is recorded in the snapshot_ts field of the Parquet file footer.
  • During normal operation, the S3 write is skipped if the data is unchanged from the previous run (detected via content hashing). After a service restart, the first run always writes a file regardless.
  • Every written file embeds a content_hash in its Parquet footer so consumers can determine whether the data actually changed between two exports.

Measurement exports (measurementExportInterval)

Each measurement export covers a time-windowed slice of sensor data: CO₂, temperature, occupancy, battery, position, and more.

  • Each export covers exactly one interval window of data.
  • If the exporter is temporarily unavailable or exports are paused for a short time, the exporter automatically catches up on missed windows when it resumes. The number of catch-up runs is limited to prevent overload; windows missed during a long pause may be skipped.

Valid interval values

Values that don’t evenly divide into 60 minutes or 24 hours are automatically rounded to the nearest valid divisor.

Valid sub-hour intervals (minutes): 15, 20, 30, 60

Valid multi-hour intervals (minutes): 60, 120, 180, 240, 360, 480, 720, 1440

S3 File Location

Exported files are written to the S3 bucket using the following path structure:

parquet/v1/{organizationId}/{dataType}/{YYYY}/{MM}/{YYYY_MM_DD_HHMM}_{YYYY_MM_DD_HHMM}_{dataType}.parquet

Example — measurement export for 1 hour window:

parquet/v1/9a2f3fba-e1cf-4adb-b9ce-6fcea775ceae/measurementCO2/2026/03/2026_03_20_1400_2026_03_20_1500_measurementCO2.parquet

Example — metadata snapshot (1 hour export interval):

parquet/v1/9a2f3fba-e1cf-4adb-b9ce-6fcea775ceae/devices/2026/03/2026_03_20_0000_2026_03_20_0100_devices.parquet

See Folder Structure for the full list of data types and path conventions.

Schema Versioning

The v1 segment in the S3 path is a schema version label. It allows breaking changes to be introduced in the future without disrupting existing pipelines.

When a new schema version is released, both the old and new versions will be written in parallel for a transition period, giving you time to migrate your pipelines before the old version is retired. The deprecation timeline will be communicated in advance.