diff --git a/pages/reference/public-api/_meta.js b/pages/reference/public-api/_meta.js
index e37f8c77..1a752602 100644
--- a/pages/reference/public-api/_meta.js
+++ b/pages/reference/public-api/_meta.js
@@ -1,3 +1,4 @@
export default {
- "overview": "Overview"
-};
\ No newline at end of file
+ "overview": "Overview",
+ "inspector-issues": "Inspector Issues"
+};
diff --git a/pages/reference/public-api/inspector-issues.mdx b/pages/reference/public-api/inspector-issues.mdx
new file mode 100644
index 00000000..db3df2c6
--- /dev/null
+++ b/pages/reference/public-api/inspector-issues.mdx
@@ -0,0 +1,315 @@
+import { Callout } from 'nextra/components';
+
+# Inspector Issues
+
+_Read Inspector issues and the event shapes behind them over HTTP_
+
+Two GET endpoints: one returns a single Inspector issue, the other returns the event shapes ("variations") behind it. Both take an `issueId`, which you'll find in the Avo web app URL when you open an issue: `https://www.avo.app/schemas/{workspaceId}/inspector/issues/ii/{issueId}`.
+
+The base URL for the Avo public API is `https://api.avo.app`.
+
+## Endpoints
+
+| Method and path | Returns | Use it when |
+| --- | --- | --- |
+| `GET /workspaces/:workspaceId/inspector/issues/v3/:issueId` | A single issue | You need counts broken down per app version, or a window other than 24 hours. |
+| `GET /workspaces/:workspaceId/inspector/issues/:issueId/variations` | The event shapes behind an issue, as JSON or CSV | You want to see exactly what the event looked like when it triggered the issue. |
+
+`:workspaceId` is the ID of your workspace, from the URL of your Avo tab after `/schemas/`.
+
+
+**Inspector data takes a few minutes to arrive**, so an event sent moments ago won't be in a response yet. To check an implementation as you ship it, use the [Inspector Debugger](/inspector/inspector-debugger).
+
+
+## Authentication
+
+Both endpoints require an [authorization header](/public-api/authentication#authenticating-with-avo-api) containing a Base64 encoded service account name and secret.
+
+| Code | Body | Condition |
+| --- | --- | --- |
+| `401` | `{"message": "Authorization header missing"}` | No `Authorization` header. |
+| `401` | `{"message": "Invalid authorization"}` | Bad secret, unknown service account, or a service account not registered in this workspace. |
+
+An `issueId` from another workspace returns 404, the same as an id that doesn't exist.
+
+### Rate limits
+
+Treat these endpoints as rate limited. Design for **1 request per second per service account**, the limit soft-enforced across the rest of the Avo public API. Retry on `429 Too Many Requests` with exponential backoff, and respect `Retry-After` if it's there.
+
+If you need a higher sustained rate, [reach out](/help/troubleshooting).
+
+## Retrieving a single issue
+
+```Url
+GET https://api.avo.app/workspaces/:workspaceId/inspector/issues/v3/:issueId
+```
+
+Returns one issue, with its counts broken down per app version.
+
+### Query parameters
+
+| Parameter | Type | Default | Accepted values |
+| --- | --- | --- | --- |
+| `time` | string | `24h` | A number followed by `h` or `d`, such as `12h` or `7d`. Anything else falls back to `24h`. |
+
+### Response
+
+| Field | Type | Notes |
+| --- | --- | --- |
+| `issueId` | string | Identifies this issue on this source. |
+| `sharedIssueId` | string | Groups the same problem across sources. |
+| `schemaId` | string | Your workspace ID. |
+| `sourceId` | string | The source this issue was found on. |
+| `eventName` | string | The event name as sent. |
+| `propertyName` | string \| null | `null` for event-level issue types. |
+| `issueType` | object | What kind of issue this is. See below. |
+| `oldestAppVersion` | string | |
+| `newestAppVersion` | string | |
+| `firstSeen` | string (ISO 8601) | |
+| `lastSeen` | string (ISO 8601) | |
+| `issueCount` | number | Occurrences that violated, summed across versions. |
+| `eventCount` | number | **Total** occurrences of that event on that source, including the ones that were fine. |
+| `appVersions` | object | Keyed by version string, **not an array**. Each value is `{"appVersion": string, "issueCount": number, "eventCount": number, "lastSeen": string \| null}`. |
+| `issueStatus` | object | `{status, updatedAt: string \| null, updatedBy: string \| null}`. See below. |
+| `regression` | boolean | See below. |
+| `branchIds` | string[] | `[]` when the issue isn't linked to a branch. |
+
+
+**`eventCount` is not the number of events affected by the issue.** It is the total volume of that event on that source, healthy occurrences included. `issueCount` is the part that violated. Report the ratio between them: `issueCount: 1428` out of `eventCount: 96204` is a 1.5% violation rate, not 96,204 broken events.
+
+
+#### `issueType`
+
+A `type` plus a payload key. For what each type means, see [issue types in Inspector](/inspector/issue-types-in-inspector).
+
+```json
+{ "type": "EventNotInTrackingPlan" }
+{ "type": "UnexpectedEvent" }
+{ "type": "MissingExpectedProperty", "missingExpectedProperty": { "eventId": "...", "propertyId": "...", "propertyName": "..." } }
+{ "type": "PropertyTypeInconsistentWithTrackingPlan", "PropertyTypeInconsistentWithTrackingPlan": { "eventId": "..." , "propertyId": "...", "propertyName": "...", "expectedPropertyType": "...", "actualPropertyType": "..." } }
+{ "type": "UnexpectedProperty", "unexpectedProperty": { "eventId": "...", "propertyName": "...", "propertyType": "..." } }
+{ "type": "InconsistentType", "inconsistentType": { "propertyName": "...", "propertyTypes": ["string", "int"] } }
+```
+
+Payload keys are camelCase, except on `PropertyTypeInconsistentWithTrackingPlan`, where the key repeats the PascalCase type name.
+
+#### `issueStatus.status`
+
+```json
+{ "type": "Unresolved" }
+{ "type": "Ignored", "validateIn": { "type": "NextAppVersion", "appVersion": "8.15.0" } }
+{ "type": "Resolved", "validateIn": { "type": "Never" } }
+```
+
+`validateIn` is one of `{"type":"CurrentAppVersion","appVersion":string}`, `{"type":"NextAppVersion","appVersion":string}`, `{"type":"CustomAppVersion","appVersion":string}`, `{"type":"Date","date":ISO 8601}` or `{"type":"Never"}`.
+
+The status labelled **Ignore** in the Avo web app reads back as `Ignored`. An issue that never had a status set reads as `Unresolved`. See [issue status](/inspector/inspector-issues-view#issue-status) for what each one means.
+
+#### `regression`
+
+`true` when an issue that was marked **Resolved** came back after the point it was meant to be fixed, which is the `validateIn` recorded when it was resolved. Inspector moves the issue back to `Unresolved` and sets the flag.
+
+Setting the status again clears it, and an `Ignored` issue that comes back never sets it. It only means anything while the status is `Unresolved`.
+
+### Status codes
+
+| Code | Body | Condition |
+| --- | --- | --- |
+| `200` | The issue object | |
+| `401` | See [authentication](#authentication) | Missing or invalid credential. |
+| `404` | `{"error": "Issue Not found"}` | No issue with this id in your workspace. |
+| `500` | `{"error": "Internal Server Error"}` | |
+
+### Example
+
+```sh
+$ curl -H "authorization: Basic " \
+ -X GET "https://api.avo.app/workspaces/hAtPI0dEsq/inspector/issues/v3/2f1c9b8e4d7a05c3e6b1a94f8d2c70b5e93a17d4c8f0b62a5d1e7c3948fb0a26?time=7d"
+```
+
+```json
+{
+ "issueId": "2f1c9b8e4d7a05c3e6b1a94f8d2c70b5e93a17d4c8f0b62a5d1e7c3948fb0a26",
+ "sharedIssueId": "8b4d0f6a1c93e57204ab8d1f6e3c9057b24da8f1093c6e5b7d20a41fc8e93b56",
+ "schemaId": "hAtPI0dEsq",
+ "sourceId": "9Zq7YAo0R",
+ "eventName": "Checkout Completed",
+ "propertyName": "revenue",
+ "issueType": {
+ "type": "PropertyTypeInconsistentWithTrackingPlan",
+ "PropertyTypeInconsistentWithTrackingPlan": {
+ "eventId": "yT2rKpQ4Xa",
+ "propertyId": "Bv8nLm1Zq0",
+ "propertyName": "revenue",
+ "expectedPropertyType": "float",
+ "actualPropertyType": "string"
+ }
+ },
+ "oldestAppVersion": "8.13.1",
+ "newestAppVersion": "8.14.2",
+ "firstSeen": "2026-08-11T09:42:18.000Z",
+ "lastSeen": "2026-08-24T06:00:00.000Z",
+ "issueCount": 9871,
+ "eventCount": 644390,
+ "appVersions": {
+ "8.13.1": {
+ "appVersion": "8.13.1",
+ "issueCount": 7204,
+ "eventCount": 402118,
+ "lastSeen": "2026-08-23T21:00:00.000Z"
+ },
+ "8.14.2": {
+ "appVersion": "8.14.2",
+ "issueCount": 2667,
+ "eventCount": 242272,
+ "lastSeen": "2026-08-24T06:00:00.000Z"
+ }
+ },
+ "issueStatus": {
+ "status": { "type": "Unresolved" },
+ "updatedAt": null,
+ "updatedBy": null
+ },
+ "regression": false,
+ "branchIds": []
+}
+```
+
+## Listing event variations
+
+```Url
+GET https://api.avo.app/workspaces/:workspaceId/inspector/issues/:issueId/variations
+```
+
+A **variation** is one observed shape of an event: a particular combination of property names and types, per app version, per source. This endpoint returns every shape the event was seen in over the last 24 hours, each with a `causingIssue` flag and a count, so you can compare a shape that triggered the issue against one that didn't.
+
+The window is always 24 hours and can't be changed.
+
+### Query parameters
+
+| Parameter | Type | Default | Accepted values |
+| --- | --- | --- | --- |
+| `format` | string | `json` | `csv` returns CSV. Anything else returns JSON. |
+| `sourceId` | string | No filter | One source ID. |
+| `appVersion` | string | No filter | One app version. |
+
+`sourceId` and `appVersion` take a single value each and match exactly, so `?sourceId=a,b` finds nothing. Repeating a parameter is ignored.
+
+
+**Without `?sourceId=`, you get the event across every source in your workspace**, not just the source the issue was reported on. Pass the issue's own `sourceId` if that's what you want.
+
+
+The response is capped at 400 rows, and each shape produces one row per app version per source. `variationsTruncated: true` means you hit the cap and are only seeing part of the picture. Narrow the query with `sourceId` and `appVersion`, then check the flag again.
+
+### Response
+
+`{"variations": [...], "variationsTruncated": bool}`, where each row has:
+
+| Field | Type | Notes |
+| --- | --- | --- |
+| `eventVariationKey` | string | Identifies this shape on this source and app version. |
+| `causingIssue` | boolean | Whether this shape is one of the shapes causing the issue. |
+| `count` | number | Occurrences in the window. An estimate on sampled sources. |
+| `eventName` | string | The event name as sent. |
+| `sourceId` | string | The Avo Source ID. |
+| `schemaId` | string | Your workspace ID. |
+| `appVersion` | string \| null | |
+| `minCreatedAt` | string \| null | ISO 8601. |
+| `maxCreatedAt` | string \| null | ISO 8601. |
+| `propertyNameSignature` | string[] | The property names that were sent, sorted by name. |
+| `propertyTypeSignature` | string[] | Their types, in the same order, so `propertyTypeSignature[i]` is the type of `propertyNameSignature[i]`. |
+
+Rows also carry `eventKey` and `sourceKey`, which you can ignore.
+
+
+**`propertyNameSignature` holds the names the SDK actually sent, not your tracking plan's names.** Line them up before comparing, or you'll report differences that aren't real. Names that look like data are redacted and come back as `
+
+Nothing in the response says which event [variant](/data-design/avo-tracking-plan/event-variants) Inspector matched against.
+
+### CSV output
+
+`?format=csv` returns the same rows arranged for comparison, as `text/csv; charset=utf-8`:
+
+1. `# variationsTruncated: true` or `false`.
+2. `# Variations causing the issue`, a header row, then the causing rows.
+3. `# Variations not causing the issue`, the same header row, then the rest.
+
+Both sections appear even when empty. Columns are `event_variation_key`, `causing_issue`, `count`, `event_name`, `source_id`, `app_version`, `min_created_at`, `max_created_at`, then one column per property name, in the order the names first appear.
+
+Each property cell holds that property's type in that row, or is empty if the row doesn't carry it. Every cell is quoted, including the header row; empty cells stay bare.
+
+```csv
+# variationsTruncated: false
+# Variations causing the issue
+"event_variation_key","causing_issue","count","event_name","source_id","app_version","min_created_at","max_created_at","currency","payment_method","revenue"
+"5d2b81f0a37c94e618df05b2c7a3e9410fb86d24c503a1e79b0d4f6238ca7e15","true","1428","Checkout Completed","9Zq7YAo0R","8.14.2","2026-08-23T07:00:00.000Z","2026-08-24T06:00:00.000Z","string","string","string"
+"b0f47ac125d3e896402fc7b13a5d90e648127cf3ab05d9e7261340bfc85a92d6","true","96","Checkout Completed","9Zq7YAo0R","8.13.1","2026-08-23T07:00:00.000Z","2026-08-24T05:00:00.000Z","string",,"string"
+# Variations not causing the issue
+"event_variation_key","causing_issue","count","event_name","source_id","app_version","min_created_at","max_created_at","currency","payment_method","revenue"
+"e93c4a70b1d582f6047ae3c9128d5b0f76a2e841c30f9b57d6812ac4053e7fb9","false","94776","Checkout Completed","9Zq7YAo0R","8.14.2","2026-08-23T07:00:00.000Z","2026-08-24T06:00:00.000Z","string","string","float"
+```
+
+### Status codes
+
+| Code | Body | Condition |
+| --- | --- | --- |
+| `200` | JSON or CSV | |
+| `400` | `{"error": "Invalid request"}` | Malformed request parameters. |
+| `401` | See [authentication](#authentication) | Missing or invalid credential. |
+| `404` | `{"error": "Issue not found"}` | No issue with this id in your workspace. |
+| `500` | `{"error": "Internal Server Error"}` | |
+
+### Example
+
+```sh
+$ curl -H "authorization: Basic " \
+ -X GET "https://api.avo.app/workspaces/hAtPI0dEsq/inspector/issues/2f1c9b8e4d7a05c3e6b1a94f8d2c70b5e93a17d4c8f0b62a5d1e7c3948fb0a26/variations?sourceId=9Zq7YAo0R&appVersion=8.14.2"
+```
+
+```json
+{
+ "variations": [
+ {
+ "eventVariationKey": "5d2b81f0a37c94e618df05b2c7a3e9410fb86d24c503a1e79b0d4f6238ca7e15",
+ "causingIssue": true,
+ "count": 1428,
+ "eventName": "Checkout Completed",
+ "sourceId": "9Zq7YAo0R",
+ "schemaId": "hAtPI0dEsq",
+ "appVersion": "8.14.2",
+ "minCreatedAt": "2026-08-23T07:00:00.000Z",
+ "maxCreatedAt": "2026-08-24T06:00:00.000Z",
+ "eventKey": "a4e1c07b93d5f28601ab7c4e9d0f3b2586c1a97e4f0b3d8c25e6a1470bf9d3c8",
+ "sourceKey": "hAtPI0dEsq-9Zq7YAo0R",
+ "propertyNameSignature": ["currency", "payment_method", "revenue"],
+ "propertyTypeSignature": ["string", "string", "string"]
+ },
+ {
+ "eventVariationKey": "e93c4a70b1d582f6047ae3c9128d5b0f76a2e841c30f9b57d6812ac4053e7fb9",
+ "causingIssue": false,
+ "count": 94776,
+ "eventName": "Checkout Completed",
+ "sourceId": "9Zq7YAo0R",
+ "schemaId": "hAtPI0dEsq",
+ "appVersion": "8.14.2",
+ "minCreatedAt": "2026-08-23T07:00:00.000Z",
+ "maxCreatedAt": "2026-08-24T06:00:00.000Z",
+ "eventKey": "a4e1c07b93d5f28601ab7c4e9d0f3b2586c1a97e4f0b3d8c25e6a1470bf9d3c8",
+ "sourceKey": "hAtPI0dEsq-9Zq7YAo0R",
+ "propertyNameSignature": ["currency", "payment_method", "revenue"],
+ "propertyTypeSignature": ["string", "string", "float"]
+ }
+ ],
+ "variationsTruncated": false
+}
+```
+
+Both shapes carry the same property names. The only difference is the type of `revenue`: `string` on the shape causing the issue, `float` on the healthy one.
+
+## What's next?
+
+- [Issue types in Inspector](/inspector/issue-types-in-inspector): what each `issueType` detects.
+- [Inspector issues view](/inspector/inspector-issues-view): the same issues in the Avo web app.
+- [Fixing issues found in Inspector](/inspector/inspector-fix-issues): turning a shape difference into a fix.
+- [Authentication](/public-api/authentication#authenticating-with-avo-api): creating a service account.
diff --git a/pages/reference/public-api/overview.mdx b/pages/reference/public-api/overview.mdx
index f6489968..4241463c 100644
--- a/pages/reference/public-api/overview.mdx
+++ b/pages/reference/public-api/overview.mdx
@@ -9,3 +9,4 @@ Avo API Uses [Basic Authentication](https://en.wikipedia.org/wiki/Basic_access_a
- [Export Branch Stats](/public-api/export-branch-stats): Export your Avo branch stats as CSV for all branches in the workspace
- [Create Branch](/public-api/create-branch): Create a new branch in your Avo workspace
- [Import Tracking Plan](/reference/public-api/import-tracking-plan): Import a tracking plan from a CSV file into a specific branch in your Avo workspace
+- [Inspector Issues](/reference/public-api/inspector-issues): Read a single Inspector issue by ID and the observed event shapes behind it