Heap track calls need app_id and one identity
app_id is the environment ID. event is the custom name, at most 1024 characters. Send identity for a known user or a numeric user_id for Heap's anonymous id, not both. properties must not reuse user_id, session_id, or screen_name. Identify is vendor/heap-identify. Add user properties is vendor/heap-user-properties. Add account properties is vendor/heap-account-properties.
identity and user_id are exclusive
Heap documents one identifier. Sending both is rejected.
What this pack matches
Rules
Codes are stable. A finding in CI, MCP, or the playground lands on the same id.
| Field | Required | What it checks | Rule ids | Source |
|---|---|---|---|---|
app_id |
required | It is the Heap environment ID. Heap documents it as required on every track call. Native JSON type: string. Fix: Set `app_id` to the environment ID from Heap Projects. | vendor.heap-track.body.app_id.missingvendor.heap-track.body.app_id.emptyvendor.heap-track.body.app_id.invalid |
docs |
events |
optional | Native JSON type: array. Maximum array items: 1000. | vendor.heap-track.body.events.invalid |
docs |
events[] |
optional | Native JSON type: object. | vendor.heap-track.body.events[].invalid |
docs |
root |
optional | Native JSON type: object. | vendor.heap-track.body.root.invalid |
docs |
event |
required | It is the server-side event name. Heap documents it as required, limited to 1024 characters. Body scope: ["events[]",""]. Native JSON type: string. Maximum decoded characters: 1024. Fix: Set `event` to the custom event name, such as `Purchase Completed`, in at most 1024 characters. | vendor.heap-track.body.event.missingvendor.heap-track.body.event.emptyvendor.heap-track.body.event.invalid |
docs |
identity |
optional | It identifies the user. Heap documents a case-sensitive string of at most 255 characters, and requires either `identity` or `user_id`, not both. Body scope: ["events[]",""]. Native JSON type: string. Maximum decoded characters: 255. Fix: Send the same identity you use in Heap Identify, at most 255 characters. | vendor.heap-track.body.identity.emptyvendor.heap-track.body.identity.invalid |
docs |
user_id |
optional | It is Heap's anonymous user id. Heap documents the string form of a number from 0 through 2^53-1. Body scope: ["events[]",""]. Native JSON type: string. Minimum numeric value: 0. Maximum numeric value: 9007199254740991. Fix: Send the numeric `user_id` from the Heap SDK, digits only. | vendor.heap-track.body.user_id.emptyvendor.heap-track.body.user_id.invalid |
docs |
timestamp |
optional | Heap documents `timestamp` as an ISO 8601 datetime. When omitted, Heap stamps the arrival time. Body scope: ["events[]",""]. Native JSON type: string. Fix: Send an ISO 8601 timestamp, such as `2026-07-26T06:00:00Z`. | vendor.heap-track.body.timestamp.emptyvendor.heap-track.body.timestamp.invalid |
docs |
session_id |
optional | It is an identifier for the user's session. Heap documents `session_id` as a top-level field, not a property key. Body scope: ["events[]",""]. Native JSON type: string. Fix: Send `session_id` at the top level, or drop the empty pair. | vendor.heap-track.body.session_id.emptyvendor.heap-track.body.session_id.invalid |
docs |
idempotency_key |
optional | Heap uses it to drop duplicate track calls. Body scope: ["events[]",""]. Native JSON type: string. | vendor.heap-track.body.idempotency_key.emptyvendor.heap-track.body.idempotency_key.invalid |
docs |
properties.user_id |
forbidden | Heap reserves `user_id` as a top-level field. Reusing it inside `properties` produces unexpected behavior. Body scope: ["events[]",""]. Fix: Rename the property. Send `user_id` at the top level when you have the SDK id. | vendor.heap-track.body.properties.user_id.forbidden |
docs |
properties.session_id |
forbidden | Heap reserves `session_id` as a top-level field. Reusing it inside `properties` produces unexpected behavior. Body scope: ["events[]",""]. Fix: Rename the property. Send `session_id` at the top level when you have a session id. | vendor.heap-track.body.properties.session_id.forbidden |
docs |
properties.screen_name |
forbidden | Heap documents `screen_name` as reserved because it conflicts with autocaptured Screen Name on mobile. Body scope: ["events[]",""]. Fix: Rename the property. | vendor.heap-track.body.properties.screen_name.forbidden |
docs |
properties |
optional | The vendor documents `properties` in the request contract. Body scope: ["events[]",""]. Native JSON type: object. | vendor.heap-track.body.properties.invalid |
docs |
property_value… |
optional | The vendor documents `property_value` in the request contract. Body scope: ["events[]",""]. Native JSON type: number or string or array. Maximum decoded characters: 1023. | vendor.heap-track.body.property_value.invalid |
docs |
root |
optional | The vendor documents `` in the request contract. Body scope: ["events[]",""]. Native JSON type: object. | vendor.heap-track.body.root.invalid |
docs |
overlong_property_names… |
forbidden | Property keys must have fewer than1024characters, counted afterJSONdecoding. Body scope: ["events[]",""]. Presence diagnostic severity: error. | vendor.heap-track.body.overlong_property_names.forbidden |
docs |
body.identity_or_user_required |
required | The track call has neither `identity` nor `user_id`. Heap documents one of them as required. Body scope: ["events[]",""]. Fix: Send `identity` for a known user, or `user_id` for an anonymous Heap id. | vendor.heap-track.body.identity_or_user_required |
docs |
body.identity_and_user_exclusive |
required | The track call sends both `identity` and `user_id`. Heap documents those as mutually exclusive. Body scope: ["events[]",""]. Fix: Send one identifier, not both. | vendor.heap-track.body.identity_and_user_exclusive |
docs |
root |
optional | String arrays are joined with || and values beyond1024Unicodecharacters aretruncated. Body scope: ["events[].properties.*","properties.*"]. Value diagnostic severity: warning. Native JSON type: string or number or boolean or array or object or null. Maximum joined string length: 1024. | vendor.heap-track.body.root.invalid |
docs |
method |
required | This published ingestion operation uses HTTP POST. Complete HTTP capture contract. Native JSON type: string. | vendor.heap-track.http.method.missingvendor.heap-track.http.method.emptyvendor.heap-track.http.method.invalid |
docs |
content_type |
recommended | Use a published request media type. Complete HTTP capture contract. Presence diagnostic severity: warning. Value diagnostic severity: warning. Native JSON type: string. | vendor.heap-track.http.content_type.missingvendor.heap-track.http.content_type.emptyvendor.heap-track.http.content_type.invalid |
docs |
body |
required | The request body is a JSON object. Complete HTTP capture contract. Native JSON type: object. | vendor.heap-track.http.body.missingvendor.heap-track.http.body.invalid |
docs |
Validate a payload
pixellint validate json @payload.json --rulepack vendor/heap-track
Try this failing payload in the playground. Heap track with reserved properties.user_id.
{"app_id":"1234567890","identity":"user-10024","event":"Purchase Completed","properties":{"user_id":"nested"}}
cargo install pixellint
·
npm install pixellint