Change Tracking
Change Tracking gives you a continuous audit trail of what changed on every managed device. The Breeze agent monitors six categories of system changes — software installs and removals, Windows service modifications, startup item additions, network adapter changes, scheduled task updates, and user account mutations — and ships them to the API in compressed batches. Every change is fingerprinted with a SHA-256 hash to prevent duplicates, then stored with before/after snapshots so you can see exactly what was modified.
This feature is designed for compliance auditing, troubleshooting, and drift detection. When a user reports that something stopped working, you can pull up the device’s change timeline and see that a critical service was disabled 20 minutes earlier. When you need to prove to an auditor that no unauthorized software was installed, the change log provides cryptographically deduplicated evidence.
Key Concepts
Section titled “Key Concepts”Change Types
Section titled “Change Types”| Type | Description |
|---|---|
software | Application installed, removed, or updated |
service | Windows service or system daemon added, removed, or modified |
startup | Startup program or launch agent added, removed, or changed |
network | Network adapter configuration changed (IP, DNS, gateway) |
scheduled_task | Scheduled task or cron job added, removed, or modified |
user_account | Local user account created, deleted, or modified |
Change Actions
Section titled “Change Actions”| Action | Description |
|---|---|
added | A new item was detected (software installed, user created, etc.) |
removed | An existing item was deleted (software uninstalled, user removed, etc.) |
modified | An existing item’s properties changed (service startup type, scheduled task trigger, etc.) |
updated | A version update was applied (software upgraded, definition file refreshed, etc.) |
Change Record Fields
Section titled “Change Record Fields”| Field | Type | Description |
|---|---|---|
id | UUID | Unique identifier for the change record |
deviceId | UUID | Device where the change was detected |
orgId | UUID | Organization the device belongs to |
fingerprint | string (64 chars) | SHA-256 hash for deduplication |
timestamp | datetime | When the change occurred on the device |
changeType | enum | One of the six change types above |
changeAction | enum | One of the four change actions above |
subject | string (max 500) | Human-readable description of what changed (e.g., “Google Chrome 122.0.6261.69”) |
beforeValue | JSON | State before the change (null for added actions) |
afterValue | JSON | State after the change (null for removed actions) |
details | JSON | Additional context (installer path, registry key, etc.) |
createdAt | datetime | When the record was stored in the database |
How Changes Are Collected
Section titled “How Changes Are Collected”-
Agent detects a change. The agent periodically snapshots system state (installed software, services, startup items, etc.) and compares against the previous snapshot. Differences are formatted as change records.
-
Agent ships changes in a batch. Changes are serialized as JSON, gzip-compressed, and sent to the API via
PUT /api/v1/agents/:id/changes. Up to 1,000 changes per request, with a 5 MB compressed body limit and 10 MB decompressed limit. -
API deduplicates and stores. Each change is fingerprinted by hashing the combination of timestamp, change type, action, subject, before/after values, and details. A unique constraint on
(deviceId, fingerprint)prevents the same change from being inserted twice. Changes are inserted in batches of 200. -
Partial success handling. If some changes in a batch fail to insert (e.g., database error on a subset), the API returns HTTP 207 with a
partial: trueflag, the count of successfully inserted records, and the total submitted.
Querying Changes
Section titled “Querying Changes”The changes API supports filtering by device, time range, change type, and action, with cursor-based pagination for efficient iteration through large result sets.
Basic Query
Section titled “Basic Query”curl "/api/v1/changes?deviceId=DEVICE_UUID&changeType=software&limit=50" \ -H "Authorization: Bearer $TOKEN"Available Filters
Section titled “Available Filters”| Parameter | Type | Description |
|---|---|---|
deviceId | UUID | Filter to a single device |
startTime | ISO 8601 datetime | Only changes at or after this time |
endTime | ISO 8601 datetime | Only changes at or before this time |
changeType | enum | One of: software, service, startup, network, scheduled_task, user_account |
changeAction | enum | One of: added, removed, modified, updated |
limit | integer | Results per page (1 — 500, default 100) |
cursor | string | Opaque cursor for the next page |
Response Format
Section titled “Response Format”{ "changes": [ { "id": "uuid", "deviceId": "uuid", "hostname": "DESKTOP-ABC123", "timestamp": "2026-02-15T14:30:00.000Z", "changeType": "software", "changeAction": "added", "subject": "Visual Studio Code 1.96.2", "beforeValue": null, "afterValue": { "version": "1.96.2", "vendor": "Microsoft Corporation", "installLocation": "C:\\Program Files\\Microsoft VS Code" }, "details": null } ], "total": 1847, "showing": 50, "hasMore": true, "nextCursor": "eyJ0aW1lc3RhbXAiOiIyMDI2..."}Cursor-Based Pagination
Section titled “Cursor-Based Pagination”The API uses cursor-based pagination for stable results when new changes arrive during iteration. The nextCursor field is a base64url-encoded JSON object containing the timestamp and ID of the last returned record. Pass it as the cursor query parameter to get the next page.
# First pagecurl "/api/v1/changes?deviceId=DEVICE_UUID&limit=100" \ -H "Authorization: Bearer $TOKEN"
# Next page (using nextCursor from the previous response)curl "/api/v1/changes?deviceId=DEVICE_UUID&limit=100&cursor=eyJ0aW1lc3RhbXAi..." \ -H "Authorization: Bearer $TOKEN"Agent Ingest Endpoint
Section titled “Agent Ingest Endpoint”The agent pushes changes directly to the API using bearer token authentication.
PUT /api/v1/agents/:agentId/changesContent-Type: application/jsonContent-Encoding: gzipAuthorization: Bearer AGENT_TOKEN
{ "changes": [ { "timestamp": "2026-02-15T14:30:00.000Z", "changeType": "software", "changeAction": "added", "subject": "Visual Studio Code 1.96.2", "afterValue": { "version": "1.96.2", "vendor": "Microsoft Corporation" } } ]}Ingest Response Codes
Section titled “Ingest Response Codes”| Status | Meaning |
|---|---|
200 | All changes accepted (or empty batch) |
207 | Partial success — some changes inserted, some failed |
400 | Invalid request body or decompression failure |
404 | Agent/device not found |
413 | Request body exceeds 5 MB compressed or 10 MB decompressed |
500 | All changes failed to insert |
Fingerprint Deduplication
Section titled “Fingerprint Deduplication”Every change is assigned a SHA-256 fingerprint computed from a stable concatenation of:
- Canonical ISO 8601 timestamp
- Change type
- Change action
- Subject
- Stable-sorted JSON of
beforeValue - Stable-sorted JSON of
afterValue - Stable-sorted JSON of
details
This fingerprint is stored in a VARCHAR(64) column with a unique index on (deviceId, fingerprint). When the agent ships the same change twice (e.g., after a retry), the database ON CONFLICT DO NOTHING clause silently skips the duplicate.
Within a single request, the API also deduplicates by fingerprint before attempting insertion, so batch payloads with repeated entries are handled efficiently.
API Reference
Section titled “API Reference”| Method | Path | Description |
|---|---|---|
GET | /api/v1/changes | List changes with filters and cursor pagination |
PUT | /api/v1/agents/:id/changes | Agent ingest endpoint for shipping change batches |
Troubleshooting
Section titled “Troubleshooting”Changes not appearing for a device
Verify the agent is enrolled and the device exists in the platform. The ingest endpoint looks up the device by agentId, not by device UUID. If the agent is not enrolled, the endpoint returns 404.
Duplicate changes appearing This should not happen due to fingerprint deduplication. If you see exact duplicates, check whether the agent is sending changes with different timestamps for the same event (e.g., using local time vs. UTC). The fingerprint includes the timestamp, so a one-second difference produces a different hash.
Large change volumes after a software deployment
This is expected. Mass deployments (e.g., pushing a new application to 500 devices) will generate 500 software:added change records. Use the changeType and changeAction filters to focus on specific categories, and cursor pagination to iterate efficiently.
207 partial success responses A 207 means some changes in the batch were inserted and some failed. This can happen if the database has transient issues. The agent should not retry the entire batch because the successfully inserted changes would be deduplicated anyway. Check server logs for the underlying database error.
Request body too large (413)
The ingest endpoint limits compressed payloads to 5 MB and decompressed payloads to 10 MB. If agents are hitting this limit, reduce the batch size or increase the shipping frequency. These limits can be tuned with the CHANGE_INGEST_MAX_BODY_BYTES and CHANGE_INGEST_MAX_DECOMPRESSED_BYTES environment variables.