> For the complete documentation index, see [llms.txt](https://docs.thewalletcrew.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.thewalletcrew.io/api-reference/tenant-configuration/device-telemetry.md).

# Device Telemetry

## Upload telemetry

> Logs, errors and product events recorded on the device. Requires the \`tenant.device:connect\` scope with the API key issued to \`deviceId\`; a device cannot submit for another.\
> &#x20;           \
> \## Timestamps\
> Item timestamps are shifted by the gap between the batch's \`sentAt\` and server receipt time, so a wrong device clock keeps item spacing and the batch lands in real time.\
> &#x20;           \
> \## Idempotency\
> Batches are deduplicated on \`batchId\`; a replay succeeds and reports its items as deduplicated.\
> &#x20;           \
> \## Sessions and traces\
> Each item carries the \`sessionId\` it was recorded under; the upload itself is attributed to no session, whatever its \`session.id\` baggage. An item with \`traceId\` and \`spanId\` is linked to that trace.

```json
{"openapi":"3.1.1","info":{"title":"Neostore internal API","version":"v1"},"tags":[{"name":"DeviceTelemetry"}],"servers":[{"url":"https://app.neostore.cloud","description":"Production Server"},{"url":"https://app-qa.neostore.cloud","description":"Staging Server"}],"security":[{"admin-bearer":["tenant.device:connect"]},{"apiKey":[]}],"components":{"securitySchemes":{"admin-bearer":{"type":"oauth2","flows":{"implicit":{"authorizationUrl":"https://auth.neostore.cloud/authorize?audience=https://app.neostore.cloud/api/","scopes":{}}}},"apiKey":{"type":"apiKey","name":"X-API-KEY","in":"header"}},"schemas":{"DeviceTelemetryBatch":{"required":["batchId","items","sentAt"],"type":"object","properties":{"batchId":{"type":"string","description":"Client-generated batch identifier, used as the idempotency key: re-send a batch with the same id after a\ntimeout, and a batch id recently received from the same device is not recorded again and its items are\nreported as deduplicated. Blank returns 400."},"sentAt":{"type":"string","description":"Device clock reading when the batch was sent. The difference against arrival time is the clock\nskew applied to every item.","format":"date-time"},"appSessionId":{"type":["null","string"],"description":"Identifier of the app launch the items came from. Not the profile session: that is\nNeo.Runtime.Devices.Telemetry.DeviceTelemetryItem.SessionId."},"appVersion":{"type":["null","string"],"description":"App version string, e.g. `1.0.3+1`."},"platform":{"type":["null","string"],"description":"Device platform, `android` or `ios`."},"osVersion":{"type":["null","string"],"description":"Operating system version."},"deviceModel":{"type":["null","string"],"description":"Manufacturer and model, e.g. `Zebra TC22`."},"items":{"type":"array","items":{"description":"One telemetry item as the device recorded it.","$ref":"#/components/schemas/DeviceTelemetryItem"},"description":"The items carried by this batch, at most the limit in the device's telemetry settings (500 by\ndefault); a larger batch is refused whole with 413. Each item is validated on its own: an invalid one\nis counted as rejected without failing the others."}},"additionalProperties":false,"description":"A batch of telemetry uploaded by one device in one request."},"DeviceTelemetryItem":{"required":["timestamp","type"],"type":"object","properties":{"type":{"description":"Telemetry kind, deciding which fields are required. An unrecognised kind is counted as rejected.","$ref":"#/components/schemas/DeviceTelemetryItemType"},"timestamp":{"type":"string","description":"Device clock reading when the item was recorded. Corrected by the batch's clock skew and capped at\nthe time the batch arrived. An item without one is counted as rejected.","format":"date-time"},"severity":{"description":"Severity of the item; `information` when omitted. An exception item is always recorded at\n`error` or above, whatever it says here.","$ref":"#/components/schemas/DeviceTelemetrySeverity"},"name":{"type":["null","string"],"description":"Item name. Required (non-blank) for Neo.Runtime.Devices.Telemetry.DeviceTelemetryItemType.Event,\nNeo.Runtime.Devices.Telemetry.DeviceTelemetryItemType.Dependency and Neo.Runtime.Devices.Telemetry.DeviceTelemetryItemType.PageView;\nan item without one is counted as rejected."},"message":{"type":["null","string"],"description":"Message body. Required (non-blank) for\nNeo.Runtime.Devices.Telemetry.DeviceTelemetryItemType.Trace and Neo.Runtime.Devices.Telemetry.DeviceTelemetryItemType.Exception; an\nitem without one is counted as rejected."},"sessionId":{"type":["null","string"],"description":"Profile session the device ran when it recorded the item, as a GUID; an item without a valid one is\nattributed to no session."},"traceId":{"type":["null","string"],"description":"W3C trace id (32 hex characters) the device span belonged to. With a valid Neo.Runtime.Devices.Telemetry.DeviceTelemetryItem.SpanId, the\nitem is correlated with the API requests of that trace."},"spanId":{"type":["null","string"],"description":"W3C span id (16 hex characters) of the device span. Only used together with Neo.Runtime.Devices.Telemetry.DeviceTelemetryItem.TraceId."},"durationMs":{"type":["null","number"],"description":"Duration of the operation in milliseconds, rounded to the millisecond. Meaningful for\ndependency and page-view items.","format":"double"},"success":{"type":["null","boolean"],"description":"Whether a dependency call succeeded."},"resultCode":{"type":["null","string"],"description":"Result code of a dependency call, typically an HTTP status."},"properties":{"type":["null","object"],"additionalProperties":{"type":"string"},"description":"Custom properties recorded with the item. Keys that match a property the platform sets (compared\ncase-insensitively) are not recorded."}},"additionalProperties":false,"description":"One telemetry item as the device recorded it."},"DeviceTelemetryItemType":{"enum":["trace","exception","event","dependency","pageView","unknown"],"type":"string","description":"Kind of telemetry an item carries."},"DeviceTelemetrySeverity":{"enum":["verbose","information","warning","error","critical"],"type":"string","description":"Severity of a telemetry item, in the vocabulary the client logger uses. Ordered: each value is more\nsevere than the one before, which is what a device's minimum severity setting compares against."},"ProblemDetails":{"type":"object","properties":{"type":{"type":["null","string"]},"title":{"type":["null","string"]},"status":{"type":["null","integer"],"format":"int32"},"detail":{"type":["null","string"]},"instance":{"type":["null","string"]}},"additionalProperties":{}},"HttpValidationProblemDetails":{"type":"object","allOf":[{"$ref":"#/components/schemas/ProblemDetails"}],"properties":{"errors":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}},"additionalProperties":{}}}},"paths":{"/api/{tenantId}/devices/{deviceId}/telemetry":{"post":{"tags":["DeviceTelemetry"],"summary":"Upload telemetry","description":"Logs, errors and product events recorded on the device. Requires the `tenant.device:connect` scope with the API key issued to `deviceId`; a device cannot submit for another.\n            \n## Timestamps\nItem timestamps are shifted by the gap between the batch's `sentAt` and server receipt time, so a wrong device clock keeps item spacing and the batch lands in real time.\n            \n## Idempotency\nBatches are deduplicated on `batchId`; a replay succeeds and reports its items as deduplicated.\n            \n## Sessions and traces\nEach item carries the `sessionId` it was recorded under; the upload itself is attributed to no session, whatever its `session.id` baggage. An item with `traceId` and `spanId` is linked to that trace.","parameters":[{"name":"deviceId","in":"path","description":"Device id.","required":true,"schema":{"type":"string"}},{"name":"tenantId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"description":"Telemetry batch.","content":{"application/json":{"schema":{"description":"A batch of telemetry uploaded by one device in one request.","$ref":"#/components/schemas/DeviceTelemetryBatch"}},"text/json":{"schema":{"description":"A batch of telemetry uploaded by one device in one request.","$ref":"#/components/schemas/DeviceTelemetryBatch"}},"application/*+json":{"schema":{"description":"A batch of telemetry uploaded by one device in one request.","$ref":"#/components/schemas/DeviceTelemetryBatch"}}}},"responses":{"202":{"description":"Batch processed; counts say what was kept."},"400":{"description":"Malformed batch, or no `batchId`.","content":{"text/plain":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"text/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"401":{"description":"The caller is not authenticated.","content":{"application/problem+json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"403":{"description":"Missing `tenant.device:connect` scope, API key issued to another device, or endpoint disabled for the tenant.","content":{"text/plain":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"text/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"413":{"description":"Body over 1 MB, or more items than the device's `maxBatchSize` telemetry setting.","content":{"text/plain":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}},"text/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/ProblemDetails"},{"$ref":"#/components/schemas/HttpValidationProblemDetails"}]}}}},"429":{"description":"Too many requests; see `Retry-After`."}}}}}}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.thewalletcrew.io/api-reference/tenant-configuration/device-telemetry.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
