> 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/guides-monitoring/monitor/retrieve-platform-logs.md).

# Retrieve platform logs

Find, filter, and export The Wallet Crew platform logs from the back office, the Insights API, or an AI assistant connected over MCP.

Platform logs trace platform activity for a tenant. They cover pass renders, scheduled pushes, connector calls, configuration reloads, and failing imports.

Logs are available through three systems:

| System           | Best for                                                             | Access                               |
| ---------------- | -------------------------------------------------------------------- | ------------------------------------ |
| **Admin UI**     | Fast lookups, day-to-day support, and CSV exports                    | A Back-office account                |
| **Insights API** | Repeatable queries, aggregation, alerting, and BI pipelines          | An API key with `Insights:Read`      |
| **MCP**          | Plain-language investigations across logs, configuration, and passes | A Back-office account and MCP client |

## Shared log data source

The Admin UI, Insights API, and MCP all read the same `Logs` table. Each request is scoped to one tenant. Another tenant's data is unreachable.

Platform logs are retained for **45 days**. Export evidence needed for audits, post-mortems, or disputes before that window closes.

<details>

<summary><strong>Real-world examples</strong></summary>

* A support agent checks whether a push notification left the platform.
* An integration engineer traces a failing API call with its operation identifier.
* An operations team counts component errors before escalating an incident.
* An AI assistant investigates an incident and summarises relevant log lines.

</details>

{% hint style="warning" %}
Platform logs can contain identifiers, request paths, user agents, and error payloads. Treat them as sensitive operational data. Share extracts, not exports, and only with people who need them.
{% endhint %}

{% hint style="danger" %}
Platform logs remain available for **45 days only**. Older lines cannot be recovered.
{% endhint %}

## What a log record contains

Every route exposes the same record. The back office shows a subset of these columns. The Insights API and MCP expose all columns.

| Column                              | Type     | What it holds                                                                    |
| ----------------------------------- | -------- | -------------------------------------------------------------------------------- |
| `Timestamp`                         | datetime | When the line was emitted, in UTC                                                |
| `Message`                           | string   | Rendered human-readable message                                                  |
| `SeverityLevel`                     | int      | Severity level; see below                                                        |
| `CategoryName`                      | string   | Emitting platform component, such as `Neo.Runtime.Wallet.Apple.ApplePassHandler` |
| `OperationName`                     | string   | Active operation, such as `HTTP POST /api/mcp` or a scheduled task name          |
| `OperationId`                       | string   | Correlation identifier for tracing one request end to end                        |
| `RequestId`                         | string   | Individual request identifier within an operation                                |
| `Properties`                        | dynamic  | Structured fields, such as `requestPath` and `originalFormat`                    |
| `UserAgent`                         | string   | Triggering client, where available                                               |
| `UserId` / `UserName` / `SessionId` | string   | Actor context, where attributed                                                  |
| `AppRoleName`                       | string   | Platform role that produced the line                                             |
| `TenantId`                          | string   | Current tenant identifier                                                        |
| `Id`                                | guid     | Unique record identifier                                                         |

### Severity levels

`SeverityLevel` is stored as a number. The back office renders a labelled badge.

| Value | Label       | Read it as                                |
| ----- | ----------- | ----------------------------------------- |
| `0`   | Verbose     | Low-level detail, rarely emitted          |
| `1`   | Information | Normal operation and most log volume      |
| `2`   | Warning     | Something recovered, degraded, or retried |
| `3`   | Error       | An operation failed                       |
| `4`   | Critical    | A failure with broad impact               |

{% hint style="info" %}
Healthy tenants generate many `Information` lines. Filter on `SeverityLevel >= 2` before drawing conclusions.
{% endhint %}

## Admin UI: Application logs

The Admin UI is the fastest route for support work.

{% stepper %}
{% step %}

#### Open the page

In the back office, go to **Settings → Monitoring → Logs**.

```
https://admin.thewalletcrew.io/tenant/~/settings/tools/logs
```

The `~` resolves to the signed-in user's current tenant. This link can be shared without editing.
{% endstep %}

{% step %}

#### Set the period

The date selector defaults to **Last 30 Days**. Presets include Today, Last 7 Days, This Week, Last 30 Days, This Month, This Year, Last Month, Last 3 Months, Last 12 Months, Last Year, and All time. A **Custom** range is also available.

Ranges wider than 45 days return nothing beyond retention. Narrow the period first.
{% endstep %}

{% step %}

#### Search

The search box matches text across every column, including `Properties`. There is no field selector.

Useful search terms include a pass serial number, an `OperationId`, an error fragment, or a request path such as `/api/mcp`.

The term is stored in the address as `?search=...`. A filtered view can therefore be shared as-is.
{% endstep %}

{% step %}

#### Read the results

Results are newest first. The **Timestamp** header changes the sort order. Expand a **Properties** cell to view structured fields.

Copy an **Operation ID** and search for it to follow one request. Each line written during that request shares the identifier.
{% endstep %}

{% step %}

#### Export

**Export logs** downloads the current view as CSV, limited to **10,000 lines**. Narrow the period and search term before exporting.

Use the Insights API for larger or recurring exports.
{% endstep %}
{% endstepper %}

## Insights API

The [Insights API](/developers-guides/integration-guides/insights-api.md) queries the shared log data with [Kusto Query Language (KQL)](https://learn.microsoft.com/en-us/kusto/query/). The Admin UI uses this API.

### Authenticate

Create an API key in **Settings → Security → API Keys**. Grant the **`Insights:Read`** permission. Copy the key when shown because it is not displayed again.

{% hint style="info" %}
The back office calls the permission `Insights:Read`. The endpoint reference calls it `Insights.Read`. Both names identify the same scope.
{% endhint %}

```http
POST /api/{tenantId}/insights/query
X-API-KEY: <API_KEY>
Content-Type: application/json
```

| Environment | Base URL                        |
| ----------- | ------------------------------- |
| Production  | `https://app.neostore.cloud`    |
| QA          | `https://app-qa.neostore.cloud` |

### First query

```bash
curl -X POST "https://app.neostore.cloud/api/<TENANT_ID>/insights/query" \
  -H "X-API-KEY: <API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "Logs | where Timestamp > ago(1h) and SeverityLevel >= 3 | project Timestamp, CategoryName, OperationId, Message | order by Timestamp desc | take 50"
  }'
```

The response is tabular:

```json
{
  "columns": ["Timestamp", "CategoryName", "OperationId", "Message"],
  "rows": [
    ["2026-09-14T19:15:02.117Z", "Neo.Runtime.Http...", "4454c9229...", "..."]
  ]
}
```

{% hint style="warning" %}
Every Insights table, `Logs` and `Events` included, uses **PascalCase** column names. KQL is case-sensitive, so `timestamp` does not resolve where `Timestamp` does.
{% endhint %}

### Query recipes

**Errors and warnings over time**

```kql
Logs
| where Timestamp > ago(7d)
| summarize Errors = countif(SeverityLevel >= 3),
          Warnings = countif(SeverityLevel == 2)
  by bin(Timestamp, 1h)
| order by Timestamp asc
```

**Which component is failing**

```kql
Logs
| where Timestamp > ago(7d) and SeverityLevel >= 3
| summarize Failures = count() by CategoryName
| order by Failures desc
| take 20
```

**Trace one request end to end**

```kql
Logs
| where OperationId == "<OPERATION_ID>"
| project Timestamp, SeverityLevel, CategoryName, OperationName, Message, Properties
| order by Timestamp asc
```

**Everything touching one pass**

```kql
Logs
| where Timestamp > ago(30d)
| where * contains "<PASS_SERIAL>"
| project Timestamp, SeverityLevel, CategoryName, Message
| order by Timestamp desc
```

**Filter on a structured property**

```kql
Logs
| where Timestamp > ago(2d)
| where tostring(Properties.requestPath) startswith "/api/"
| summarize Calls = count() by tostring(Properties.requestPath)
| order by Calls desc
| take 25
```

**Error rate as a percentage**

```kql
Logs
| where Timestamp > ago(24h)
| summarize Total = count(), Failures = countif(SeverityLevel >= 3)
| extend ErrorRate = round(100.0 * Failures / Total, 2)
```

### Parameterised queries

Pass values separately from query text. Parameters arrive as **strings**, so cast them in the query.

```json
{
  "query": "Logs\n| where Timestamp between (todatetime(start) .. todatetime(stop))\n| where * contains searchQuery\n| order by Timestamp desc\n| take toint(pageSize)\n| project Timestamp, Message, OperationName, OperationId, SeverityLevel, CategoryName, Properties",
  "parameters": {
    "start": "2026-09-01T00:00:00.000Z",
    "stop": "2026-09-14T23:59:59.999Z",
    "searchQuery": "outdated",
    "pageSize": "100"
  }
}
```

Page through large results by numbering and slicing rows:

```kql
| serialize rowNum = row_number()
| where rowNum > (toint(pageIndex) * toint(pageSize))
  and rowNum <= ((toint(pageIndex) + 1) * toint(pageSize))
```

### Limits

| Limit          | Value                                                                                                                                                            |
| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Scope required | `Insights:Read`                                                                                                                                                  |
| Rate limit     | 60 requests per minute                                                                                                                                           |
| Tenant scope   | Single tenant; another tenant's data is unreachable                                                                                                              |
| Row cap        | A `maxRows` option guards against runaway queries. Exceeding it fails the request rather than returning a truncated sample. Raise it deliberately for an export. |
| Caching        | None. Cache client-side when polling.                                                                                                                            |

{% hint style="info" %}
A query exceeding `maxRows` fails by design. A trimmed result can appear complete while omitting rows.
{% endhint %}

## MCP: for AI assistants

An MCP-connected assistant can read the shared logs. It can also check configuration, pass history, and automation runs during one investigation. See [Model Context Protocol (MCP)](/connectors/model-context-protocol-mcp.md) for setup instructions.

| Environment | Endpoint                                    |
| ----------- | ------------------------------------------- |
| Production  | `https://admin.thewalletcrew.io/api/mcp`    |
| QA          | `https://admin-qa.thewalletcrew.io/api/mcp` |

Sign in with Back-office credentials. The connection is read-only.

### The tools that matter for logs

| Tool                      | Use                                  |
| ------------------------- | ------------------------------------ |
| `insights_schema`         | Confirm available tables and columns |
| `insights_query_examples` | Retrieve working query patterns      |
| `insights_query`          | Run KQL and return results           |

### Prompt patterns

> Show every error and warning from the last 24 hours, grouped by component. For the three noisiest, explain the component and messages.

> Find log lines for pass `<PASS_ID>` from the last 7 days. Reconstruct what happened and identify failed steps.

> Operation `<OPERATION_ID>` failed. Pull its lines in order and identify where it broke.

> Compare this week’s error volume with last week. Flag components whose failures more than doubled.

{% hint style="info" %}
Keep the time range narrow. Each tool call is capped at two minutes. Broad `Logs` queries can reach that limit.
{% endhint %}

## Troubleshooting

| What appears                         | Meaning                                                                               |
| ------------------------------------ | ------------------------------------------------------------------------------------- |
| `401 Unauthorized`                   | The API key is missing, mistyped, or revoked.                                         |
| `403 Forbidden`                      | The key or account lacks `Insights:Read` for this tenant.                             |
| No rows when rows were expected      | Check the 45-day retention window, then column casing. Every table uses PascalCase.   |
| `400` on an apparently correct query | A column name is wrong or a parameter lacks a cast. Use `todatetime()` or `toint()`.  |
| The query times out                  | Narrow the time range, filter by `SeverityLevel`, and project only needed columns.    |
| Rate-limit errors                    | The limit is 60 requests per minute. Batch with `summarize` instead of polling loops. |
| Unfamiliar numbers                   | Confirm the environment. QA holds test data, not production data.                     |

## Good practice

* Start narrow. A time range and severity filter make later steps faster.
* Correlate with `OperationId`, not timestamps. Timestamps interleave between requests.
* Export audit evidence before its 45-day window closes.
* Quote relevant lines in tickets, chats, and AI prompts. Avoid full exports.
* Rehearse queries in QA. Use production when production evidence is required.

## FAQ

<details>

<summary>How long are logs kept?</summary>

Logs are kept for 45 days. Wallet events in `Events` remain available indefinitely. Export anything with lasting value before the window closes.

</details>

<details>

<summary>Can more than 10,000 rows be exported?</summary>

The back office cannot export more than 10,000 rows. Use the Insights API, page results with `row_number()`, and raise `maxRows` deliberately.

</details>

<details>

<summary>Why does an `Events` query not work against `Logs`?</summary>

The two tables hold different columns. `Events` carries the event in `Name` and its payload in `EventData`, while `Logs` carries `SeverityLevel`, `Message`, `CategoryName` and `Properties`. Both use PascalCase. The [Insights API](/developers-guides/integration-guides/insights-api.md) page lists the columns of every table.

</details>

<details>

<summary>Can another tenant's logs be queried?</summary>

No. Every route is scoped to one tenant and enforced server-side.

</details>

<details>

<summary>Is a live tail available?</summary>

No self-service live tail is available. Set the period to **Today** and refresh the back office, or poll the Insights API over a narrow range.

</details>

<details>

<summary>Should logs or the Insights API be used for reporting?</summary>

Use wallet events for reporting. Platform logs describe system behaviour, not programme performance. For adoption, installs, and scans, see Query your data — Insights API and KPI definitions.

</details>


---

# 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/guides-monitoring/monitor/retrieve-platform-logs.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.
