# TJ Hughes GSC property curl findings

## Endpoint

- URL: `https://seo.helixscribe.cloud/api/search-analytics/property`
- Auth header: `Authorization: Bearer $SEO_JWT`
- Content type: `application/json`

## Minimum required payload

The endpoint returns HTTP 400 with field errors unless the JSON body includes:
- `siteUrl`
- `startDate`
- `endDate`

Observed missing-field response pattern:

```json
{
  "ok": false,
  "error": {
    "formErrors": [],
    "fieldErrors": {
      "siteUrl": ["Required"],
      "startDate": ["Required"],
      "endDate": ["Required"]
    }
  }
}
```

This is useful as a smoke test because it shows the JWT and route are valid even when the body is incomplete.

## Confirmed working request shapes

### Last 7 days, query only

Payload fields used successfully:
- `siteUrl: "https://www.tjhughes.co.uk/"`
- `startDate: "2026-05-05"`
- `endDate: "2026-05-11"`

Returned HTTP 200 and live query rows.

### Query + page for 31-day range

Payload fields used successfully:
- `siteUrl: "https://www.tjhughes.co.uk"`
- `startDate: "2026-04-11"`
- `endDate: "2026-05-11"`
- `dimensions: ["query", "page"]`
- `rowLimit: 50`

Returned HTTP 200 and query-page pair rows.

### Query-only filter for a single brand phrase

Payload fields used successfully:
- `dimensions: ["query"]`
- `rowLimit: 100`
- `dimensionFilterGroups`
- one `notContains` filter on `tj hughes`

Returned HTTP 200, but many brand variants still remained.

### Query + page filter with multiple brand exclusions

Payload fields used successfully:
- `dimensions: ["query", "page"]`
- `rowLimit: 100`
- `dimensionFilterGroups`
- multiple `notContains` filters

Returned HTTP 200, but brand-ish variants still remained.

## Confirmed-supported payload features

- `dimensions`
- `rowLimit`
- `dimensionFilterGroups`
- `groupType: "and"`
- `filters`
- `operator: "notContains"`
- multiple filters in one group

## Brand filter findings

### Single-filter exclusion that worked syntactically but was too narrow

```json
{ "dimension": "query", "operator": "notContains", "expression": "tj hughes" }
```

Queries still returned after this filter included:
- `tjhughes`
- `t j hughes`
- `tj huges`
- `tg hughes`
- `tj hughs`

### Broader exclusion set that still leaked brand variants

Exclusions used:
- `tj hughes`
- `t j hughes`
- `tjhughes`
- `tj huges`
- `tj hughs`
- `tg hughes`
- `tghughes`
- `t j huges`
- `tj highes`

Brand-like queries still returned included:
- `tjs`
- `tj`
- `tjhughs`
- `tjhuges`
- `th hughes`
- `t hughes`
- `tk hughes`
- `t g hughes`
- `jt hughes`
- `tj hugges`
- `t j hughs`
- `t. j. hughes`
- `tj hughed`
- `tj jughes`
- `thj hughes`
- `t.j hughes`
- `t.j. hughes`
- `tj hues`
- `ty hughes`
- `j d hughes`
- `t k hughes`
- `tg hughs`
- `tj higes`
- `tj hu`
- `tj hudges`

## Genuine non-brand examples surfaced by the broader filter

Examples that looked genuinely non-brand:
- `warehouse sales near me`
- `warehouse clearance`
- `ready assembled furniture clearance`
- `it suitcases`
- `alto suitcase`
- `life and glory jeans`
- `suitcase sale`
- `potting bench`
- `assembled wardrobes`
- `homcom uk`

## Practical guidance

- Use `$SEO_JWT` directly in shell examples unless the user explicitly exports another variable such as `JWT`.
- Prefer multiline curl examples for reuse in chat.
- Treat API filtering as a first pass, not a final non-brand classifier.
- For repeatable reporting, combine API-side exclusions with post-processing against a maintained brand-variant list.
