# Search competitors

Search the stored iOS competitor catalogue with bounded, cursor-based filters.

## Contract status

Preview contract: these routes and tools are implemented in the shared contract, but the public host, customer API access and OAuth flow have not been deployment verified.

## Endpoint: GET /v1/competitors

- Method: `GET`
- Path: `/v1/competitors`
- Authentication: Bearer API credential or OAuth access token
- Required scope: `context:read`
- MCP tool: `search_competitors`

## Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `search` | query | string, max 120 | no | Product-name search text. |
| `category` | query | string, 1–120 | no | Exact catalogue category filter. |
| `platform` | query | ios | no | The preview supports iOS only. |
| `cursor` | query | opaque string | no | Cursor returned by the previous page. |
| `limit` | query | integer, 1–100 | no | Page size; defaults to 24. |

## Known errors

- 400 invalid_request for an invalid filter, identity or limit.
- 401 authentication_required for a missing or invalid credential.
- 402 subscription_required when access is not entitled.
- 403 authorization_required for a missing scope or unavailable preview access.
- 404 not_found when the record is outside the accessible catalogue.
- 429 rate_limited; honor Retry-After when present.

## Request

Send filters as query parameters. Keep them unchanged when following an opaque cursor.

```
curl --get 'https://api.peekpanda.com/v1/competitors' \
  --header "Authorization: Bearer $PEEKPANDA_TOKEN" \
  --header 'x-genviral-tenancy: personal' \
  --data-urlencode 'platform=ios' \
  --data-urlencode 'search=calorie tracker' \
  --data-urlencode 'limit=24'
```

## Response

Paginated catalogue listings. 0000000000 is a synthetic valid-format store ID.

```
{
  "data": [
    {
      "platform": "ios",
      "storeId": "0000000000",
      "appName": "Example Calorie Tracker",
      "category": "Health & Fitness",
      "developerId": "example-developer",
      "price": 0,
      "adSupported": null,
      "inAppPurchases": true,
      "totalRatings": 12450,
      "rating": 4.7,
      "installs": {
        "kind": "ratings_proxy",
        "value": 622500
      },
      "releaseDate": "2024-05-01",
      "storeUpdatedAt": "2026-09-06",
      "sourceUpdatedAt": "2026-09-06",
      "descriptionUpdatedAt": null,
      "description": null,
      "shortDescription": null,
      "source": "itunes",
      "snapshotDate": "2026-03-01"
    }
  ],
  "pagination": {
    "nextCursor": null,
    "hasMore": false
  }
}

```

## Source

March dump listings may still say source appgoblin; current Apple lookups use itunes. Installs kind ratings_proxy is lifetime ratings × 50, not store-reported downloads.

## Refresh

list/get may enqueue a US iTunes lookup when today's tape row is missing. The GET itself never waits on Apple.
