---
name: product
description: >-
  Use when an external agent or third-party tool needs to drive Snooplytics —
  an AI competitive/market-monitoring platform — over its public API or MCP
  server. Activate when the user mentions creating a monitoring project,
  managing an organization or its members, configuring SSO/MFA, handling
  subscriptions or credits, or managing API keys on Snooplytics. Covers MCP
  (OAuth) setup, REST authentication, and the cross-cutting rules an external
  caller must know (org context, pagination, response envelope, rate limits).
  Do NOT use for product engineering work on the Snooplytics codebase — this
  skill is for external API/MCP consumers only.
license: MIT
metadata:
  author: Snooplytics
  version: 2.0.0
  homepage: https://www.snooplytics.com
  api: https://api.snooplytics.com
  docs: https://docs.snooplytics.com
  mcp: https://mcp.snooplytics.com
inputs:
  - API_KEY:
      required: false
      description: >-
        Personal access token starting with `tkn_`, sent on the REST API via
        the `x-api-key` header. Create one at
        https://www.snooplytics.com/settings/api-keys or with the
        `create_api_key` tool once authenticated. NOTE: PATs are NOT accepted by
        the MCP server — MCP uses OAuth (see "Connect (MCP)" below).
references:
  - workflows
---

# Snooplytics

An AI-driven competitive and market-monitoring platform. You describe what you
want to watch; Snooplytics runs recurring monitoring and surfaces relevant
changes. External agents drive it through MCP tools or the REST API — no
codebase access needed.

## Connect (MCP — recommended)

The MCP server is hosted at **https://mcp.snooplytics.com** and is an OAuth 2.1
**resource server** (RFC 9728). It does **not** accept `tkn_` personal access
tokens — clients authenticate with an OAuth JWT:

1. The client fetches protected-resource metadata:
   `GET https://mcp.snooplytics.com/.well-known/oauth-protected-resource`
2. It follows `authorization_servers` to the Snooplytics authorization server
   (Better Auth OIDC at `https://api.snooplytics.com/api/auth`), runs OAuth 2.1
   + PKCE (with dynamic client registration via RFC 7591 if needed), and
   receives a JWT access token.
3. It sends `Authorization: Bearer <jwt>` on every MCP call.

Most MCP clients (Claude Desktop, Cursor, etc.) perform this handshake
automatically once you point them at the server URL:

```json
{
  "mcpServers": {
    "snooplytics": {
      "url": "https://mcp.snooplytics.com"
    }
  }
}
```

Sessions last 1 hour. On the initial handshake the server returns an
`mcp-session-id` header; send it back on subsequent requests (most clients
handle this automatically). A 401 always includes a `WWW-Authenticate: Bearer …`
header pointing at the resource-metadata URL so the client can (re)discover the
authorization server. Request bodies are capped at 1 MB.

## Connect (REST — alternative)

```
Base URL: https://api.snooplytics.com/api/
Auth:     x-api-key: tkn_your_token        (personal access token)
          Authorization: Bearer <jwt>      (OAuth / session token)
Content-Type: application/json
```

PATs (`tkn_`) and OAuth tokens travel on **separate** headers — `x-api-key` for
PATs, `Authorization: Bearer` for OAuth/session JWTs — so the two channels stay
distinct. Org-scoped endpoints carry the organization id in the URL path:
`GET /api/user/organizations/{organizationId}/projects`.

## Documentation

- Full API reference + OpenAPI: **https://docs.snooplytics.com**
- Live tool catalog: your MCP client's `tools/list` (always current — do not cache)
- Token management: https://www.snooplytics.com/settings/api-keys

## Capabilities

- **Projects** — create, read, update, delete monitoring projects. A project
  carries a `name` and a `monitoringIntent` (what to watch); it runs on a weekly
  cadence with status `draft` / `active` / `paused`.
- **Organizations** — create teams, invite/manage members and roles, configure
  SSO/MFA and security settings, manage custom domains, read/export audit logs.
- **Billing** — start plan subscriptions and credit-pack purchases via Stripe,
  open the Stripe billing portal, inspect the current subscription and usage.
- **API keys** — create, list, update, and delete personal access tokens.
- **User profile** — manage account settings, export your data, view login history.

## When NOT to use this skill

- Product engineering / codebase work — this skill knows nothing about source
- Admin-tier operations — those require an admin account in the dashboard, not API keys
- Direct payment processing — billing returns Stripe URLs; the user pays in their browser
- File uploads (logos, avatars, photos) — **not** exposed on the public API /
  MCP surface; there are no upload tools
- Endpoints not exposed externally — the MCP `tools/list` is the source of truth
  for what's callable

## Authentication

| Method | Header | Use case |
|---|---|---|
| Personal access token | `x-api-key: tkn_...` | REST automation, CI (REST only) |
| OAuth 2.0 / OIDC | `Authorization: Bearer <jwt>` | MCP, third-party app integrations |

OAuth scopes: `user:read`, `user:write`, `projects:read`, `projects:write`,
`subscription:read`, `subscription:write`, `api-keys:read`, `api-keys:write`,
`api-keys:delete`, `*` (full access). The MCP resource server itself does not
gate by these scopes (`scopes_supported: []`); authorization is enforced
API-side by the user's role-derived permissions.

## Org context — the most important rule

Most operations are scoped to an organization. Failing to set org context is the
#1 cause of new-agent errors. The flow is always:

1. `get_current_user` — confirm auth works
2. `list_user_organizations` — pick the target org
3. Run org-scoped tools using that org's id

**Account-level tools** (no org required): `get_current_user`,
`update_current_user`, `delete_current_user`, `export_user_data`,
`get_login_history`, `list_user_organizations`, `create_organization`,
`accept_organization_invite`, `create_api_key`, `list_api_keys`, `get_api_key`,
`update_api_key`, `delete_api_key`, `identify_email`, `discover_sso`,
`complete_sso_auth`.

**Everything else is org-scoped** (its path contains `{organizationId}`). If you
see `TENANT_CONTEXT_MISSING` or `NOT_ORGANIZATION_MEMBER`, you skipped step 2.

## Core concepts

| Concept | Description |
|---|---|
| Organization | Tenant boundary. Owns projects, members, billing, settings. |
| Member | User's membership in an org with role: `owner` (1 per org), `admin`, `member`. Seats are pre-purchased; absolute ceiling is 100 members/org. |
| Project | A monitoring target within an org. Lifecycle: `draft` → `active` ⇄ `paused`. |
| Subscription | Stripe-managed plan tied to an organization. |
| Credits | Org-level fuel for monitoring runs: `available = base + topUp − used`. Base resets monthly; top-up (credit packs) persists. |

## Tool disambiguation

When two tools sound similar, pick by scope:

| Confused between | Use this | Not this | Why |
|---|---|---|---|
| `create_checkout_session` / `create_credits_checkout_session` | First for plans (recurring) | Second for credit packs (one-time top-up) | Billing model differs |
| `update_subscription` / `create_billing_portal_session` | First to change/cancel the plan via API | Second to hand the user Stripe's hosted management page | API change vs self-serve portal |
| `get_organization` / `get_my_organization_membership` | First for org info | Second for your own role | Different data returned |
| `list_user_organizations` / `list_user_projects` | First to find orgs | Second for projects within a chosen org | Different resource, different scope |

For the full tool list with arguments, call `tools/list` on the MCP server.

## Common mistakes

| # | Mistake | Fix |
|---|---|---|
| 1 | Calling org-scoped tools without picking an org | Run `list_user_organizations` first |
| 2 | Using `page` / `pageSize` for pagination | Use `offset` (default 0) and `limit` (default 20, max 100) |
| 3 | Creating a project without required fields | `name` and `monitoringIntent` are both required |
| 4 | Trying to process payment directly | `create_checkout_session` returns a Stripe URL — the user must pay in their browser |
| 5 | Expecting upload tools | None exist on the public surface — uploads are dashboard-only |
| 6 | Expecting `data` on error responses | Errors return `success: false` + `code` + `message` + optional `meta.errors` — no `data` |
| 7 | Ignoring `meta.hasMore` | Always check before assuming you have all results |
| 8 | Forgetting `verify_checkout_session` after payment | Webhooks may lag — always verify |
| 9 | Putting a `tkn_` PAT in the MCP `Authorization` header | MCP is OAuth-only; PATs work on REST via `x-api-key` |
| 10 | Tight-loop retry on rate limit | Honor `429` + `Retry-After` (default budget 500 req / 15 min per IP; deployments may tune it) |

## Response envelope (quick reference)

```json
// Success
{ "success": true, "code": "OK", "data": { ... } }

// Paginated
{ "success": true, "data": [ ... ], "meta": { "total": 42, "offset": 0, "limit": 20, "hasMore": true } }

// Error
{ "success": false, "code": "VALIDATION_ERROR", "message": "...", "meta": { "errors": [...] } }
```

Full error-code table, header reference, and rate-limit specifics are at
**https://docs.snooplytics.com**.

## Workflows

For step-by-step guides on common multi-tool operations (project lifecycle, team
setup, billing & credits, domain verification, audit, API key management), see
[workflows.md](references/workflows.md).
