# API Endpoints Reference

API endpoints for querying agents, managing data sources, and retrieving analytics.

## Base URL

```
https://api.twig.so
```

**Protocol**: HTTPS only (HTTP requests redirect to HTTPS)

**API Version**: v1 (included in path: `/api/v1/...` or legacy `/api/...`)

## Authentication

Include API key in Authorization header:

```bash
curl -H "Authorization: Bearer twigsk_live_abc123..." \
     https://api.twig.so/api/agents
```

**Key format**: `twigsk_live_...` (production) or `twigsk_test_...` (test)

**Generate key**: Settings → API Keys → Generate New Key

See [Authentication](/product/developer-api/authentication.md) for key management.

## Rate Limits

Enforced per API key:

| Scope                 | Requests/Minute | Burst Allowance |
| --------------------- | --------------- | --------------- |
| Execute (queries)     | 100             | 120             |
| Write (create/update) | 10              | 15              |
| Read (list/get)       | 200             | 250             |
| Admin (org settings)  | 50              | 60              |

**Headers in response**:

```
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1610708100
```

**When exceeded**: `429 Too Many Requests` with reset timestamp

See [Rate Limits](/product/developer-api/rate-limits.md) for optimization strategies.

## API Endpoints

### Chat & Completion

#### POST /api/v1/query

Generate agent response. Replaces legacy `/api/chat`.

**Request:**

```json
{
  "agent_id": "agent_abc123",
  "query": "What is your refund policy?",
  "session_id": "sess_xyz789",
  "stream": false,
  "temperature": 0.7,
  "max_tokens": 500
}
```

**Required fields**: `agent_id`, `query`

**Optional fields**:

* `session_id`: For multi-turn conversations (creates new if omitted)
* `stream`: Boolean, SSE streaming (default: false)
* `temperature`: 0-2 (default: agent config value)
* `max_tokens`: Response length limit (default: agent config value)

**Response** (200 OK):

```json
{
  "response": "Our refund policy allows returns within 30 days...",
  "sources": [{
    "chunk_id": "chk_abc123",
    "document_title": "Refund Policy",
    "document_url": "https://example.com/refund",
    "similarity_score": 0.89,
    "chunk_text": "Refunds are processed within..."
  }],
  "metadata": {
    "interaction_id": "int_xyz456",
    "latency_ms": 1432,
    "tokens_input": 523,
    "tokens_output": 145,
    "cost_usd": 0.0042,
    "rag_strategy": "cedar",
    "model": "gpt-4"
  }
}
```

**Error responses**:

* `400`: Missing required field, invalid agent\_id format
* `401`: Invalid API key
* `403`: API key lacks Execute scope
* `404`: Agent not found
* `429`: Rate limit exceeded
* `500`: Internal error

**Latency**: 1-5s depending on RAG strategy

#### POST /api/v1/semantic-search

Retrieve chunks without LLM generation.

**Request:**

```json
{
  "query": "pricing information",
  "org_id": "org_123",
  "top_k": 10,
  "similarity_threshold": 0.7,
  "data_source_ids": ["ds_1", "ds_2"]
}
```

**Required**: `query`, `org_id`

**Response** (200 OK):

```json
{
  "chunks": [{
    "chunk_id": "chk_abc123",
    "text": "Pricing starts at $99/month...",
    "similarity_score": 0.85,
    "document_id": "doc_456",
    "document_title": "Pricing Page"
  }],
  "query_embedding": [0.123, -0.456, ...],
  "metadata": {
    "total_chunks_searched": 15234,
    "latency_ms": 234
  }
}
```

### Agents

#### GET /api/v1/agents

List agents. Requires Read scope.

**Query params**:

* `limit`: Max results (default: 50, max: 200)
* `offset`: Pagination (default: 0)

**Response** (200):

```json
{
  "agents": [{
    "id": "agent_abc123",
    "name": "Support Agent",
    "rag_strategy": "cedar",
    "model": "gpt-4",
    "status": "active",
    "data_source_ids": ["ds_1", "ds_2"],
    "created_at": "2024-01-15T10:30:00Z"
  }],
  "total": 5,
  "limit": 50,
  "offset": 0
}
```

#### POST /api/v1/agents

Create agent. Requires Write scope.

**Request**:

```json
{
  "name": "Support Agent",
  "system_prompt": "You are a helpful support assistant.",
  "rag_strategy": "cedar",
  "model": "gpt-4",
  "temperature": 0.7,
  "max_tokens": 500,
  "data_source_ids": ["ds_1", "ds_2"]
}
```

**Required**: `name`, `data_source_ids`

**Response** (201): Agent object with generated `id`

#### GET /api/v1/agents/:id

Get agent details. Requires Read scope.

#### PUT /api/v1/agents/:id

Update agent. Requires Write scope.

**Request**: Same fields as POST, all optional

**Response** (200): Updated agent object

#### DELETE /api/v1/agents/:id

Delete agent. Requires Write scope.

**Response** (204): No content

### Data Sources

#### GET /api/v1/data-sources

List data sources. Requires Read scope.

**Query params**: `limit`, `offset`, `status` (active/processing/failed)

#### POST /api/v1/data-sources

Create data source. Requires Write scope.

**Request**:

```json
{
  "type": "website",
  "name": "Product Documentation",
  "config": {
    "url": "https://docs.example.com",
    "max_pages": 1000
  },
  "sync_frequency": "daily"
}
```

**Types**: `website`, `file`, `confluence`, `slack`, `google_drive`, `sharepoint`

**Sync frequency**: `hourly`, `daily`, `weekly`, `manual`

**Response** (201): Data source object with ID, status "pending"

#### POST /api/v1/data-sources/:id/sync

Trigger sync. Requires Write scope.

**Response** (202): Sync job queued

#### GET /api/v1/data-sources/:id/status

Check processing status.

**Response**:

```json
{
  "status": "processing",
  "chunks_indexed": 450,
  "progress_pct": 75,
  "estimated_completion": "2024-01-15T10:45:00Z"
}
```

### Interactions

#### GET /api/v1/interactions

List query history. Requires Read scope.

**Query params**:

* `limit`, `offset`: Pagination
* `agent_id`: Filter by agent
* `start_date`, `end_date`: Date range (YYYY-MM-DD)
* `feedback`: Filter by positive/negative/null

**Response**:

```json
{
  "interactions": [{
    "id": "int_xyz123",
    "agent_id": "agent_abc",
    "query": "What is pricing?",
    "response": "Pricing starts at...",
    "feedback": "positive",
    "latency_ms": 1432,
    "created_at": "2024-01-15T10:30:00Z"
  }],
  "total": 1250
}
```

#### POST /api/v1/interactions/:id/feedback

Submit feedback. Requires Execute scope.

**Request**:

```json
{
  "feedback": "positive",
  "comment": "Very helpful!"
}
```

**feedback values**: `positive`, `negative`

### Analytics

#### GET /api/v1/analytics

Get metrics. Requires Admin scope.

**Query params**:

* `start_date`, `end_date`: Date range (required, YYYY-MM-DD)
* `agent_id`: Filter by agent (optional)
* `granularity`: `hour`, `day`, `week`, `month` (default: day)

**Response**:

```json
{
  "metrics": {
    "total_queries": 10250,
    "unique_users": 1523,
    "avg_latency_ms": 1843,
    "accuracy_rate": 0.82,
    "citation_rate": 0.91,
    "total_cost_usd": 42.50
  },
  "time_series": [{
    "timestamp": "2024-01-15T00:00:00Z",
    "queries": 450,
    "latency_p50": 1432,
    "latency_p95": 2890
  }]
}
```

### Users

#### GET /api/v1/users

List users. Requires Admin scope.

#### POST /api/v1/users

Create user. Requires Admin scope.

**Request**:

```json
{
  "email": "user@example.com",
  "name": "John Doe",
  "role": "train"
}
```

**Roles**: `readonly`, `train`, `configure`, `admin`

### Knowledge Base

#### GET /api/v1/kb

List KB articles. Requires Read scope.

**Query params**: `status` (draft/published), `limit`, `offset`

#### POST /api/v1/kb

Create KB article. Requires Write scope.

**Request**:

```json
{
  "title": "How to reset password",
  "content": "Steps: 1. Click Forgot Password...",
  "tags": ["auth", "password"],
  "status": "published"
}
```

#### PUT /api/v1/kb/:id

Update article. Creates new version. Requires Write scope.

## Error Responses

Standard format:

```json
{
  "error": {
    "code": "invalid_request",
    "message": "Agent not found",
    "details": {
      "agent_id": "agent_123",
      "org_id": "org_456"
    }
  },
  "request_id": "req_xyz789"
}
```

**request\_id**: Include when contacting support

### Error Codes

| HTTP Status | Code                  | Description                            | Action                                                      |
| ----------- | --------------------- | -------------------------------------- | ----------------------------------------------------------- |
| 400         | `invalid_request`     | Missing required field, invalid format | Check request body against docs                             |
| 401         | `unauthorized`        | Invalid/missing API key                | Verify key format, regenerate if needed                     |
| 403         | `forbidden`           | Insufficient scope                     | Check key permissions (Settings → API Keys)                 |
| 404         | `not_found`           | Resource doesn't exist                 | Verify ID, check resource wasn't deleted                    |
| 429         | `rate_limit_exceeded` | Too many requests                      | Wait for reset (check X-RateLimit-Reset header)             |
| 500         | `internal_error`      | Server error                           | Retry with exponential backoff, contact support if persists |
| 503         | `service_unavailable` | Maintenance or overload                | Retry after 5-10 minutes                                    |

**Retry logic**: Use exponential backoff for 429, 500, 503 errors. Do NOT retry 400, 401, 403, 404.

## Webhooks

Receive event notifications via HTTP POST to your endpoint.

**Configure**: Settings → Webhooks → Add Endpoint

**Events**:

* `interaction.completed`: Query processed, response generated
* `data_source.synced`: Data source sync finished
* `agent.updated`: Agent configuration changed
* `eval.completed`: Evaluation run finished

**Payload example**:

```json
{
  "event": "interaction.completed",
  "timestamp": "2024-01-15T10:30:00Z",
  "data": {
    "interaction_id": "int_xyz123",
    "agent_id": "agent_abc",
    "latency_ms": 1432
  }
}
```

**Security**: Webhook signature in `X-Twig-Signature` header (HMAC-SHA256)

See [Webhooks Guide](/product/developer-api/webhooks.md) for verification and retry logic.

## SDKs

**TypeScript/JavaScript**:

```bash
npm install @twig/sdk
```

**Python**:

```bash
pip install twig-sdk
```

**Usage example** (TypeScript):

```typescript
import { TwigClient } from '@twig/sdk';

const client = new TwigClient({ apiKey: process.env.TWIG_API_KEY });

const response = await client.query({
  agentId: 'agent_abc123',
  query: 'What is pricing?'
});

console.log(response.response);
```

See [SDK Documentation](/product/developer-api/sdks.md) for full API reference.

## Next Steps

* [Authentication Guide](/product/developer-api/authentication.md) - API key generation and rotation
* [Rate Limiting](/product/developer-api/rate-limits.md) - Optimization strategies, caching
* [Webhooks Setup](/product/developer-api/webhooks.md) - Event-driven integrations
* [SDK Reference](/product/developer-api/sdks.md) - Client library docs


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://help.twig.so/product/developer-api/rest-api.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
