> ## Documentation Index
> Fetch the complete documentation index at: https://docs.surfa.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# API Reference

> Complete API documentation for Surfa Ingest and Query APIs

## Overview

Surfa provides two main APIs:

1. **Ingest API** - Track events from your MCP server
2. **MCP Query API** - Query analytics with natural language

Both APIs use API key authentication with Bearer tokens.

***

## Ingest API

### POST /api/v1/ingest/events

Track events from your MCP server or application.

**Endpoint:**

```
POST https://surfa-web.vercel.app/api/v1/ingest/events
```

**Headers:**

```http theme={null}
Authorization: Bearer sk_live_your_key_here
Content-Type: application/json
```

**Request Body:**

```json theme={null}
{
  "session_id": "string (required)",
  "events": [
    {
      "kind": "string (required)",
      "subtype": "string (required)",
      // ... additional event fields
    }
  ],
  "execution_id": "string (optional)",
  "runtime": {
    "provider": "string (optional)",
    "model": "string (optional)",
    "mode": "string (optional)"
  }
}
```

**Field Descriptions:**

| Field          | Type   | Required | Description                                                               |
| -------------- | ------ | -------- | ------------------------------------------------------------------------- |
| `session_id`   | string | ✅        | Unique identifier for this session (e.g., `live_session_abc123`)          |
| `events`       | array  | ✅        | Array of event objects to track                                           |
| `execution_id` | string | ❌        | Execution ID (returned from first request, reuse for subsequent requests) |
| `runtime`      | object | ❌        | Runtime metadata (provider, model, mode)                                  |

**Event Object:**

| Field             | Type   | Required | Description                                                 |
| ----------------- | ------ | -------- | ----------------------------------------------------------- |
| `kind`            | string | ✅        | Event category: `tool`, `session`, `runtime`, `error`, etc. |
| `subtype`         | string | ✅        | Event type: `call_started`, `call_completed`, `error`, etc. |
| Additional fields | any    | ❌        | Any custom fields (tool\_name, status, latency\_ms, etc.)   |

**Response (Success):**

```json theme={null}
{
  "ok": true,
  "execution_id": "exec_abc123xyz",
  "events_received": 1
}
```

**Response (Error):**

```json theme={null}
{
  "ok": false,
  "error": "Invalid API key"
}
```

**Status Codes:**

| Code  | Meaning                                   |
| ----- | ----------------------------------------- |
| `200` | Success - events tracked                  |
| `401` | Unauthorized - invalid or missing API key |
| `403` | Forbidden - API key revoked               |
| `422` | Validation error - invalid payload        |
| `429` | Rate limit exceeded                       |
| `500` | Server error                              |

***

## Example Requests

### Track a Tool Call

```bash theme={null}
curl -X POST https://surfa-web.vercel.app/api/v1/ingest/events \
  -H "Authorization: Bearer sk_live_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "session_id": "live_session_abc123",
    "events": [
      {
        "kind": "tool",
        "subtype": "call_completed",
        "tool_name": "search",
        "status": "success",
        "latency_ms": 245
      }
    ]
  }'
```

### Track Multiple Events

```bash theme={null}
curl -X POST https://surfa-web.vercel.app/api/v1/ingest/events \
  -H "Authorization: Bearer sk_live_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "session_id": "live_session_abc123",
    "execution_id": "exec_xyz789",
    "events": [
      {
        "kind": "tool",
        "subtype": "call_started",
        "tool_name": "search",
        "query": "AI agents"
      },
      {
        "kind": "tool",
        "subtype": "call_completed",
        "tool_name": "search",
        "status": "success",
        "latency_ms": 245,
        "results_count": 10
      }
    ]
  }'
```

### Track with Runtime Info

```bash theme={null}
curl -X POST https://surfa-web.vercel.app/api/v1/ingest/events \
  -H "Authorization: Bearer sk_live_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "session_id": "live_session_abc123",
    "runtime": {
      "provider": "anthropic",
      "model": "claude-3-5-sonnet-20241022",
      "mode": "mcp"
    },
    "events": [
      {
        "kind": "session",
        "subtype": "started",
        "client_id": "claude_desktop_v1"
      }
    ]
  }'
```

***

## Event Types

### Tool Events

Track MCP tool calls:

```json theme={null}
{
  "kind": "tool",
  "subtype": "call_started" | "call_completed" | "call_failed",
  "tool_name": "string",
  "status": "success" | "error",
  "latency_ms": 123,
  "error_message": "string (if failed)"
}
```

### Session Events

Track session lifecycle:

```json theme={null}
{
  "kind": "session",
  "subtype": "started" | "ended",
  "client_id": "string",
  "total_calls": 10
}
```

### Error Events

Track errors:

```json theme={null}
{
  "kind": "error",
  "subtype": "error",
  "error_type": "string",
  "error_message": "string",
  "stack_trace": "string (optional)"
}
```

### Custom Events

Track anything:

```json theme={null}
{
  "kind": "custom",
  "subtype": "your_event_type",
  "custom_field_1": "value",
  "custom_field_2": 123
}
```

***

## MCP Query API

Used by the Surfa MCP Server to query analytics. You typically don't call these directly - use the MCP server instead.

### GET /api/v1/mcp/analytics/metrics

Get high-level analytics metrics.

**Headers:**

```http theme={null}
Authorization: Bearer sk_live_your_key
```

**Response:**

```json theme={null}
{
  "ok": true,
  "data": {
    "totalSessions": 150,
    "successRate": 85,
    "avgExecutionTime": 245,
    "activeSessions": 12
  }
}
```

### GET /api/v1/mcp/analytics/events

Query events with filters.

**Query Parameters:**

| Parameter   | Type   | Description                          |
| ----------- | ------ | ------------------------------------ |
| `status`    | string | Filter by status: `success`, `error` |
| `tool_name` | string | Filter by tool name                  |
| `limit`     | number | Max results (default: 100)           |

**Response:**

```json theme={null}
{
  "ok": true,
  "data": {
    "events": [...],
    "total": 150
  }
}
```

### GET /api/v1/mcp/analytics/sessions/:sessionId

Get all events for a specific session.

**Response:**

```json theme={null}
{
  "ok": true,
  "data": {
    "session_id": "live_session_abc123",
    "status": "completed",
    "events": [...],
    "event_count": 10
  }
}
```

***

## Rate Limits

### Ingest API

The Ingest API has rate limiting to prevent abuse:

* **Limit:** 1,000 events per minute per API key
* **Window:** 60 seconds (sliding window)
* **Response:** `429 Too Many Requests` when exceeded

**Rate Limit Response:**

```json theme={null}
{
  "ok": false,
  "error": "Rate limit exceeded"
}
```

The SDK automatically retries with exponential backoff when rate limited.

### MCP Query API

The MCP Query API currently has no rate limits. Use responsibly.

***

## Error Handling

### Authentication Errors (401, 403)

```json theme={null}
{
  "ok": false,
  "error": "Invalid API key"
}
```

**Don't retry** - fix your API key.

### Validation Errors (422)

```json theme={null}
{
  "ok": false,
  "error": "Missing required field: session_id"
}
```

**Don't retry** - fix your payload.

### Rate Limit Errors (429)

```json theme={null}
{
  "ok": false,
  "error": "Rate limit exceeded"
}
```

**Retry with exponential backoff.**

### Server Errors (500, 502, 503, 504)

```json theme={null}
{
  "ok": false,
  "error": "Internal server error"
}
```

**Retry with exponential backoff** (max 3 attempts).

***

## SDK vs Direct API

### Using the SDK (Recommended)

```python theme={null}
from surfa_ingest import SurfaClient

analytics = SurfaClient(
    ingest_key="sk_live_your_key",
    api_url="https://surfa-web.vercel.app"
)

analytics.track({
    "kind": "tool",
    "subtype": "call_completed",
    "tool_name": "search",
    "status": "success"
})
```

**Benefits:**

* ✅ Automatic retries
* ✅ Buffering and batching
* ✅ Session management
* ✅ Error handling
* ✅ Runtime metadata

### Direct API Calls

Use direct API calls if:

* You're not using Python
* You need custom behavior
* You're building your own SDK

**Example (JavaScript):**

```javascript theme={null}
const response = await fetch('https://surfa-web.vercel.app/api/v1/ingest/events', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${apiKey}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    session_id: 'live_session_abc123',
    events: [{
      kind: 'tool',
      subtype: 'call_completed',
      tool_name: 'search',
      status: 'success'
    }]
  })
});

const data = await response.json();
console.log(data);
```

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Authentication" icon="key" href="/authentication">
    Get your API key and set up authentication
  </Card>

  <Card title="Quickstart" icon="rocket" href="/quickstart">
    Start tracking events in 5 minutes
  </Card>

  <Card title="SDK Reference" icon="code" href="/sdk/python-sdk">
    Explore the Python SDK
  </Card>

  <Card title="Privacy & PII" icon="shield" href="/privacy-and-pii">
    Learn what data Surfa tracks
  </Card>
</CardGroup>
