Skip to content
Back to skills

Api Discovery

ASecurity

Hidden API discovery and intelligence tool. Detects internal APIs, REST/GraphQL endpoints, WebSocket connections, and authentication patterns on any website. Useful for competitive intelligence, integration building, and understanding how SPA applications work under the hood. Triggers on: hidden API, discover APIs, endpoint, SPA, intercept, XHR, fetch requests, websocket, internal API, reverse engineer API, API patterns, API endpoints, API mapping.

  • 6 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added May 31, 2026
developmentjavascriptgojavabashreactvueangularnextjsawstesting

Works with

  • cursor
  • terminal
  • cli
  • api
  • mcp

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned May 31, 2026

npx -y skills add ceoimperiumprojects/imperium-brain --skill api-discovery --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Api Discovery?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Api Discovery
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/ceoimperiumprojects-api-discovery/badge)](https://www.skillsdirectory.com/skills/ceoimperiumprojects-api-discovery)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: api-discovery
description: 'Hidden API discovery and intelligence tool. Detects internal APIs, REST/GraphQL endpoints, WebSocket connections, and authentication patterns on any website. Useful for competitive intelligence, integration building, and understanding how SPA applications work under the hood. Triggers on: hidden API, discover APIs, endpoint, SPA, intercept, XHR, fetch requests, websocket, internal API, reverse engineer API, API patterns, API endpoints, API mapping.'
user-invocable: false
---

# API Discovery & Intelligence Skill

## Overview

Modern web applications — especially Single Page Applications (SPAs) — communicate almost entirely through hidden APIs. These APIs are never documented publicly, yet they power every feature: product listings, search, real-time updates, user authentication, notifications, and payment flows.

This skill systematically discovers and maps these APIs, turning opaque frontends into transparent, analyzable systems.

**Use Cases:**

- **Competitive intelligence** — Understand how competitors build their products at the API level. What data do they expose? How do they paginate? What real-time features use WebSockets?
- **Integration opportunities** — Find unofficial APIs that you can integrate with before official APIs exist (or when they never will)
- **Security research** — Map the attack surface of a web application by understanding every endpoint it calls
- **Architecture learning** — Study how successful apps architect their API layers, authentication flows, and real-time data systems
- **Product building** — Reverse-engineer data models and business logic from API responses to build better competing products

**Why This Matters for Startups:**

When you see a competitor's polished UI, you only see 20% of the product. The API layer reveals the other 80% — the data model, the business rules, the scalability approach, the edge cases they handle. This skill gives you X-ray vision into any web application.

---

## Core Capabilities

---

### 1. Discover APIs (`discover_apis`)

**Purpose:** Intercept all XHR/fetch requests a website makes, revealing hidden API endpoints that power the frontend.

#### When `imperium-crawl` is available:

```bash
# Basic discovery — load page and capture all API calls
imperium-crawl discover-apis --url "target.com" --wait-seconds 10

# Extended discovery — navigate multiple pages to find more endpoints
imperium-crawl discover-apis --url "target.com" --wait-seconds 15 --navigate-links 5

# Deep discovery — interact with forms, buttons, modals to trigger API calls
imperium-crawl discover-apis --url "target.com" --wait-seconds 20 --interact --max-depth 3

# Discovery with authentication (if you have an account)
imperium-crawl discover-apis --url "target.com" --wait-seconds 15 --cookies "session=abc123"
```

This loads the page in a headless browser, waits for API calls to fire, and returns all discovered endpoints with methods, headers, request/response bodies, and timing data.

#### When `imperium-crawl` is NOT available (manual approach):

Follow this systematic process:

**Step 1: Prepare the Browser**
1. Open Chrome/Edge → DevTools (F12) → Network tab
2. Check "Preserve log" (so navigation doesn't clear results)
3. Filter by "Fetch/XHR" to hide static assets
4. Optional: Enable "Disable cache" for cleaner results

**Step 2: Passive Discovery — Initial Page Load**
1. Clear the Network tab
2. Navigate to the target URL
3. Wait 10-15 seconds for all initial API calls to complete
4. Document every request that appears

**Step 3: Active Discovery — User Actions**
Trigger API calls by performing common user actions:
- Scroll down (lazy loading / infinite scroll)
- Use search functionality
- Click through navigation / categories
- Open modals and popups
- Toggle filters and sort options
- Switch between list/grid views
- Click "Load more" buttons
- Visit user profile / settings pages
- Check notification areas
- Try the signup/login flow (without submitting real data)

**Step 4: Document Each API Call**
For every request captured, record:
- Full URL (including query parameters)
- HTTP method (GET, POST, PUT, PATCH, DELETE)
- Request headers (especially Authorization, Content-Type, custom headers)
- Request body (for POST/PUT/PATCH)
- Response status code
- Response headers (rate limit headers, cache headers, CORS)
- Response body structure (field names, data types, nesting)
- Timing (how long the request took)

#### What to Look For:

**Base API URL patterns:**
- `api.company.com` — dedicated API subdomain (common in mature products)
- `company.com/api/v2/` — path-based API (common in monoliths)
- `company.com/graphql` — GraphQL endpoint
- `company.com/_next/data/` — Next.js data routes
- `company.com/__api/` — framework-specific internal routes
- Third-party APIs (analytics, payments, CDN) — useful to understand tech stack

**Authentication detection:**
- `Authorization: Bearer eyJ...` — JWT token (decode at jwt.io for claims)
- `Cookie: session=...` — Cookie-based session
- `X-API-Key: ...` or `?api_key=...` — API key authentication
- `Authorization: Basic ...` — Basic auth (rare in SPAs)
- OAuth redirect flows — watch for `/oauth/authorize` redirects
- CSRF tokens — `X-CSRF-Token` header or hidden form fields

**Pagination patterns:**
- Cursor-based: `?cursor=abc123` or `?after=abc123` (modern, scalable)
- Offset-based: `?offset=20&limit=10` (traditional, simple)
- Page-based: `?page=2&per_page=25` (traditional)
- Link headers: `Link: <url>; rel="next"` (RFC 5988)
- Response metadata: `{"next_cursor": "abc", "has_more": true}`

**Rate limiting detection:**
- `X-RateLimit-Limit` — max requests per window
- `X-RateLimit-Remaining` — requests left
- `X-RateLimit-Reset` — when window resets
- `Retry-After` header on 429 responses
- Custom rate limit headers (vary by provider)

**Real-time connections:**
- WebSocket URLs: `wss://ws.company.com/...`
- Server-Sent Events: `text/event-stream` content type
- Long polling: requests that hang for 30+ seconds
- Socket.IO: `/socket.io/?EIO=4&transport=polling`

---

### 2. Query APIs (`query_api`)

**Purpose:** Test discovered endpoints to understand their behavior, data models, and business logic.

#### When `imperium-crawl` is available:

```bash
# Simple GET request
imperium-crawl query-api --url "api.target.com/v1/products" --method GET

# GET with query parameters
imperium-crawl query-api --url "api.target.com/v1/products?category=electronics&limit=5" --method GET

# POST with JSON body
imperium-crawl query-api --url "api.target.com/v1/search" --method POST \
  --body '{"query": "test", "filters": {"price_min": 0}}'

# Request with custom headers
imperium-crawl query-api --url "api.target.com/v1/products" --method GET \
  --headers '{"Accept": "application/json", "X-Requested-With": "XMLHttpRequest"}'

# GraphQL introspection query
imperium-crawl query-api --url "target.com/graphql" --method POST \
  --body '{"query": "{__schema{types{name,fields{name,type{name}}}}}"}'
```

#### When `imperium-crawl` is NOT available:

Use WebFetch MCP tool or browser DevTools console:

```javascript
// From browser console (same-origin only)
fetch('/api/v1/products')
  .then(r => r.json())
  .then(data => console.log(JSON.stringify(data, null, 2)));
```

Or use curl from terminal:

```bash
curl -s "https://api.target.com/v1/products" \
  -H "Accept: application/json" | jq .
```

Note: Without proper authentication tokens or cookies, most endpoints will return 401/403.

#### Analysis Checklist:

For each endpoint you query, analyze:

- **Response format** — JSON (most common), XML (legacy), Protocol Buffers (high-performance), MessagePack (binary JSON)
- **Data richness** — What fields are exposed? Are there fields that shouldn't be public? Nested objects that reveal the data model?
- **Error response patterns** — What does a 400 look like? 404? 500? Consistent error schema indicates API maturity
- **Rate limiting behavior** — Make 5-10 rapid requests. Do you get throttled? At what threshold?
- **CORS headers** — `Access-Control-Allow-Origin: *` means callable from any browser. Specific domain means restricted
- **Caching headers** — `Cache-Control`, `ETag`, `Last-Modified` reveal caching strategy
- **API version in URL** — `v1`, `v2`, `v3` indicates maturity and iteration speed
- **Response size** — Are they over-fetching? Sending 50 fields when frontend shows 5? (common inefficiency)
- **Null handling** — Do they omit null fields or include them? Reveals backend conventions
- **ID formats** — Sequential integers (guessable), UUIDs (not guessable), or custom IDs (e.g., Stripe's `cus_...`)

---

### 3. Monitor WebSockets (`monitor_websocket`)

**Purpose:** Observe real-time data streams to understand live features like notifications, chat, price updates, collaborative editing, and live dashboards.

#### When `imperium-crawl` is available:

```bash
# Monitor WebSocket for 30 seconds
imperium-crawl monitor-websocket --url "wss://ws.target.com/stream" --duration 30

# Monitor with initial subscription message
imperium-crawl monitor-websocket --url "wss://ws.target.com/stream" --duration 30 \
  --send '{"type": "subscribe", "channel": "updates"}'

# Monitor Socket.IO connection
imperium-crawl monitor-websocket --url "wss://ws.target.com/socket.io/?EIO=4&transport=websocket" \
  --duration 60
```

#### When `imperium-crawl` is NOT available:

**Browser DevTools approach:**
1. Open DevTools → Network tab → Filter by "WS"
2. Navigate to a page with real-time features
3. Click on the WebSocket connection that appears
4. Switch to the "Messages" tab
5. Watch messages flow — green arrows are sent, red are received
6. Document message formats, frequency, and patterns

**What to analyze in WebSocket streams:**

- **Connection handshake** — What initial messages are exchanged? Authentication tokens sent?
- **Message format** — JSON, binary (Protocol Buffers), or plain text?
- **Message types** — What event categories exist? (`update`, `notification`, `ping`, `subscribe`)
- **Frequency** — How often do messages arrive? (every 100ms for real-time, every 30s for heartbeat)
- **Payload size** — Are messages compact (optimized) or verbose (over-sending)?
- **Reconnection behavior** — What happens when connection drops? Auto-reconnect with backoff?
- **Channel/room system** — Can you subscribe to specific data streams?

---

## SPA Detection

Before running API discovery, determine if the target is a Single Page Application. SPAs are the richest targets for API discovery because they make all data requests through JavaScript.

### Detection Methods:

**1. View Page Source Check**
Right-click → View Page Source. If the HTML body is mostly empty with a single mount point, it's an SPA:
```html
<!-- SPA indicator — nearly empty body -->
<body>
  <div id="root"></div>
  <script src="/static/js/main.abc123.js"></script>
</body>
```
vs.
```html
<!-- Server-rendered — content in HTML -->
<body>
  <header>...</header>
  <main>
    <h1>Product Name</h1>
    <div class="product-grid">...</div>
  </main>
</body>
```

**2. Framework Detection**
Check browser console for framework globals:
- **React:** `window.__REACT_DEVTOOLS_GLOBAL_HOOK__` or `document.querySelector('[data-reactroot]')`
- **Vue:** `window.__VUE_DEVTOOLS_GLOBAL_HOOK__` or `document.querySelector('[data-v-]')`
- **Angular:** `document.querySelector('[ng-version]')` or `window.ng`
- **Svelte:** check for `__svelte` attributes in DOM
- **Next.js:** `window.__NEXT_DATA__` (SSR + SPA hybrid — still rich API calls)
- **Nuxt:** `window.__NUXT__`

**3. Network Behavior**
SPAs have a distinctive network pattern:
- Initial load: 1 HTML file + many JS/CSS bundles
- After load: burst of XHR/fetch API calls to populate the page
- Navigation: URL changes without full page reload (History API)
- Subsequent pages: only API calls, no new HTML documents

**4. URL Pattern**
- Hash routing: `site.com/#/dashboard` (older SPAs)
- History API: `site.com/dashboard` but no full reload (modern SPAs)
- Check: click links and watch the Network tab. If no new `document` type appears, it's an SPA

### Hybrid Detection

Modern sites are often hybrids (SSR + SPA):
- **Next.js / Nuxt / Remix** — Server-render initial HTML, then hydrate into SPA
- These still make many API calls and are good targets for discovery
- Look for `__NEXT_DATA__` or similar hydration payloads in page source — these contain the initial API response data

---

## Common API Patterns Reference

### REST API Conventions

Standard CRUD pattern:
```
GET    /api/v1/resources              → List (with pagination)
GET    /api/v1/resources/:id          → Get single resource
POST   /api/v1/resources              → Create new resource
PUT    /api/v1/resources/:id          → Full update (replace)
PATCH  /api/v1/resources/:id          → Partial update
DELETE /api/v1/resources/:id          → Delete
```

Common extensions:
```
GET    /api/v1/resources/:id/children → Nested resources
POST   /api/v1/resources/search       → Complex search (body too large for GET query params)
POST   /api/v1/resources/batch        → Batch operations
GET    /api/v1/resources/count        → Count without fetching data
GET    /api/v1/resources/export       → CSV/PDF export
POST   /api/v1/resources/import       → Bulk import
```

### GraphQL APIs

GraphQL uses a single endpoint for everything:
```
POST /graphql

# Query — read operations
{"query": "{ products(first: 10) { id name price } }"}

# Mutation — write operations
{"query": "mutation { createProduct(input: {name: \"Test\"}) { id } }"}

# Introspection — discover the entire schema
{"query": "{__schema{types{name,fields{name,type{name}}}}}"}

# Named queries with variables
{"query": "query GetProduct($id: ID!) { product(id: $id) { id name } }", "variables": {"id": "123"}}
```

Detection clues:
- Single POST endpoint (usually `/graphql` or `/api/graphql`)
- Request body always has a `query` field
- Response always has a `data` field (and optionally `errors`)
- `Content-Type: application/json` both ways

### Authentication Patterns

**Bearer Token (JWT):**
Most common in SPAs. Token stored in localStorage or memory.
```
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
```
Decode the JWT payload at jwt.io to find: user ID, roles, expiration, issuer.

**Cookie-Based Sessions:**
Traditional web apps. Cookie set by server, sent automatically by browser.
```
Cookie: session=abc123def456; _csrf=xyz789
```

**API Key:**
Common for public/developer APIs. Usually in header or query param.
```
X-API-Key: sk_live_abc123
?api_key=sk_live_abc123
```

**OAuth 2.0 Flows:**
Watch for redirect chains:
1. App redirects to `provider.com/oauth/authorize?client_id=...&redirect_uri=...`
2. User authenticates at provider
3. Provider redirects back to `app.com/callback?code=...`
4. App exchanges code for access token (server-side)

---

## Output Format

For each target analyzed, generate a structured API intelligence report:

```json
{
  "target": "https://target.com",
  "scan_date": "2025-01-15",
  "is_spa": true,
  "framework": "React (Next.js)",
  "base_url": "https://api.target.com",
  "api_version": "v2",
  "auth_type": "bearer_jwt",
  "auth_details": {
    "token_location": "localStorage",
    "token_key": "auth_token",
    "jwt_algorithm": "RS256",
    "token_expiry": "24h",
    "refresh_mechanism": "POST /auth/refresh"
  },
  "total_endpoints": 15,
  "endpoints": [
    {
      "method": "GET",
      "path": "/v2/products",
      "full_url": "https://api.target.com/v2/products",
      "auth_required": true,
      "rate_limited": true,
      "rate_limit": "100/minute",
      "response_format": "json",
      "pagination": {
        "type": "cursor",
        "param": "after",
        "default_page_size": 50
      },
      "query_params": ["category", "sort", "search", "after", "limit"],
      "response_fields": ["id", "name", "price", "description", "images", "created_at"],
      "notes": "Returns product catalog. Supports filtering by category and full-text search."
    },
    {
      "method": "POST",
      "path": "/v2/search",
      "full_url": "https://api.target.com/v2/search",
      "auth_required": false,
      "rate_limited": true,
      "rate_limit": "30/minute",
      "response_format": "json",
      "request_body": {
        "query": "string",
        "filters": "object",
        "page": "number",
        "size": "number"
      },
      "notes": "Full-text search with faceted filtering. Uses Elasticsearch under the hood (visible in error responses)."
    }
  ],
  "websockets": [
    {
      "url": "wss://ws.target.com/updates",
      "purpose": "Real-time price and inventory updates",
      "protocol": "custom JSON",
      "message_format": "json",
      "message_types": ["price_update", "stock_change", "heartbeat"],
      "avg_frequency": "2 messages/second",
      "auth_required": true,
      "notes": "Requires auth token in initial connection as query param"
    }
  ],
  "graphql": {
    "endpoint": "/graphql",
    "introspection_enabled": true,
    "schema_types": 45,
    "notable_queries": ["products", "user", "orders", "recommendations"],
    "notable_mutations": ["createOrder", "updateProfile", "addToCart"],
    "notes": "Full introspection available. Schema suggests they use Shopify-style architecture."
  },
  "third_party_apis": [
    {"service": "Stripe", "endpoint": "api.stripe.com", "purpose": "Payments"},
    {"service": "Segment", "endpoint": "api.segment.io", "purpose": "Analytics"},
    {"service": "Algolia", "endpoint": "*.algolia.net", "purpose": "Search"},
    {"service": "Cloudinary", "endpoint": "res.cloudinary.com", "purpose": "Image CDN"}
  ],
  "security_observations": {
    "cors": "Restricted to target.com origins",
    "csp": "Present and strict",
    "hsts": true,
    "api_key_exposure": "No API keys visible in frontend code",
    "over_fetching": "User endpoint returns email and phone — potential PII concern"
  },
  "competitive_insights": [
    "Uses cursor pagination — indicates large datasets and modern architecture",
    "WebSocket for real-time pricing suggests dynamic pricing engine",
    "GraphQL with 45 types — complex data model, heavy investment in API layer",
    "Algolia for search instead of building in-house — focus on core product over infrastructure",
    "Auth token expires every 24h with silent refresh — good security practice"
  ]
}
```

---

## Discovery Workflow Summary

```
STEP 1: SPA Detection
  → View source, check framework globals, observe network behavior

STEP 2: Passive Discovery (page load)
  → Record all API calls made on initial page load
  → Note base URLs, auth patterns, response formats

STEP 3: Active Discovery (interaction)
  → Trigger API calls through search, navigation, scrolling, modals
  → Look for CRUD endpoints, pagination, error patterns

STEP 4: WebSocket Discovery
  → Check for real-time connections (WS tab in DevTools)
  → Monitor message formats and frequency

STEP 5: GraphQL Introspection
  → If GraphQL detected, try introspection query
  → Map queries, mutations, and types

STEP 6: Analysis & Report
  → Structure findings into the output format above
  → Add competitive insights and strategic observations
  → Flag security concerns or over-exposed data
```

---

## Ethics & Legal Guidelines

This skill is designed for **legitimate research and intelligence gathering** only.

**DO:**
- Only discover publicly accessible APIs (those called by the browser without special access)
- Use for competitive research, integration planning, and architecture learning
- Respect `robots.txt` and Terms of Service
- Rate-limit your own queries — don't hammer discovered endpoints
- Report genuine security vulnerabilities through responsible disclosure

**DO NOT:**
- Bypass or circumvent authentication mechanisms
- Access data you are not authorized to see
- Abuse rate limits or cause service degradation
- Scrape personal data or PII in bulk
- Violate CFAA (Computer Fraud and Abuse Act) or equivalent local laws
- Use discovered APIs for commercial scraping without permission
- Reverse-engineer APIs to build direct clones that violate IP

**Gray Areas:**
- Using public APIs that have no Terms of Service — generally OK for small-scale research
- Inspecting your own accounts' API traffic — always OK
- Testing endpoints with modified parameters — OK if you don't access unauthorized data
- GraphQL introspection — it's a feature, not a vulnerability, but don't abuse what you find

**When in doubt:** If an endpoint clearly isn't meant to be public, don't use it. The goal is intelligence and learning, not exploitation.

Files in this skill

  • SKILL.md20.4 KB
  • references/api-patterns.md22.5 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.