# History

The History API is one read-only surface over everything you've done on the platform — **transcriptions**, **TTS renders**, and **voice conversations** — under a single host. Use it to list, page, filter, and search your activity, and to fetch download links for the underlying audio and transcripts.

All history endpoints require authentication — see [Overview](#overview) for API key setup.

**Base URL:** `https://api.fluxions.ai`

## One shape for everything

Every **list** response uses the same envelope:

```json
{
  "object": "list",
  "page": 1,
  "limit": 20,
  "total": 137,
  "has_more": true,
  "data": [ /* items */ ]
}
```

Every **item** carries an `object` field telling you its type (`"transcription"`, `"tts"`, or `"conversation"`) plus its native `id`. To fetch one item's detail, call `/history/{type}s/{id}` (e.g. `/history/tts/123`). Timestamps are ISO-8601 UTC; costs are in US dollars.

## Shared query parameters

These work on every collection (and the unified feed):

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `page` | integer | `1` | Page number (1-based) |
| `limit` | integer | `20` | Results per page (max: 100) |
| `order` | string | `desc` | Sort by time: `asc` or `desc` |
| `since` | string | — | Only items at/after this time (ISO-8601 or epoch seconds) |
| `until` | string | — | Only items at/before this time (ISO-8601 or epoch seconds) |

Collection-specific filters: `voice` (tts, conversations), `status` (transcriptions), `type` (the unified feed).

## GET /history — Unified Feed

A merged, reverse-chronological feed across all three types. Filter the streams with `type` (comma-separated).

### Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `type` | string | *(all)* | Restrict to `transcription`, `tts`, and/or `conversation` (csv) |

*(plus all shared parameters above)*

### Request

**Bash (.sh)**
```bash
curl "https://api.fluxions.ai/history?limit=10&type=tts,conversation" \
  -H "Authorization: YOUR_API_KEY"
```

**Python (.py)**
```python
import requests

r = requests.get(
    'https://api.fluxions.ai/history',
    headers={'Authorization': 'YOUR_API_KEY'},
    params={'limit': 10, 'type': 'tts,conversation'},
)
for item in r.json()['data']:
    print(item['object'], item['id'], item['created_at'])
```

**JavaScript (.js)**
```javascript
const res = await fetch('https://api.fluxions.ai/history?limit=10&type=tts,conversation', {
  headers: {'Authorization': 'YOUR_API_KEY'}
});
const { data } = await res.json();
data.forEach(i => console.log(i.object, i.id, i.created_at));
```

### Response

```json
{
  "object": "list",
  "page": 1, "limit": 10, "total": 84, "has_more": true,
  "data": [
    { "object": "conversation", "id": "sess_abc", "created_at": "2026-06-29T10:40:00Z",
      "cost_usd": null, "voice": "maeve.en-us", "duration_secs": 312.4, "turn_count": 18 },
    { "object": "tts", "id": 123, "created_at": "2026-06-29T10:32:00Z",
      "cost_usd": 0.0123, "voice": "maeve.en-us", "chars": 842, "audio_secs": 58.4 }
  ]
}
```

> The feed is lightweight: it does **not** include presigned `download_url`s. Use the typed collection or detail endpoints to get them.

## GET /history/transcriptions — Transcription History

List your transcriptions.

### Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `status` | string | — | Filter by status (e.g. `completed`) |
| `include_download_url` | boolean | `false` | Include a presigned audio URL per item |

*(plus all shared parameters)*

### Request

**Bash (.sh)**
```bash
curl "https://api.fluxions.ai/history/transcriptions?status=completed&limit=5" \
  -H "Authorization: YOUR_API_KEY"
```

**Python (.py)**
```python
import requests

r = requests.get(
    'https://api.fluxions.ai/history/transcriptions',
    headers={'Authorization': 'YOUR_API_KEY'},
    params={'status': 'completed', 'limit': 5},
)
print(r.json()['total'], 'transcriptions')
```

**JavaScript (.js)**
```javascript
const res = await fetch('https://api.fluxions.ai/history/transcriptions?status=completed&limit=5', {
  headers: {'Authorization': 'YOUR_API_KEY'}
});
console.log((await res.json()).total, 'transcriptions');
```

### Response

```json
{
  "object": "list",
  "page": 1, "limit": 5, "total": 42, "has_more": true,
  "data": [
    {
      "object": "transcription",
      "id": 456,
      "created_at": "2026-06-29T10:35:00Z",
      "cost_usd": 0.10,
      "status": "completed",
      "filename": "interview.mp3",
      "audio_duration_secs": 1800.0,
      "audio_format": "opus",
      "language": "en",
      "num_speakers": 2,
      "num_segments": 142
    }
  ]
}
```

## GET /history/transcriptions/{id} — One Transcription

Returns the full record with presigned `download_url` (audio), `text_url`, and `segments_url`. `404` if it isn't yours.

```bash
curl "https://api.fluxions.ai/history/transcriptions/456" \
  -H "Authorization: YOUR_API_KEY"
```

## GET /history/tts — TTS Render History

List your text-to-speech renders.

### Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `voice` | string | — | Filter by voice id |
| `include_download_url` | boolean | `true` | Include a presigned Opus URL per item |

*(plus all shared parameters)*

### Request

**Bash (.sh)**
```bash
curl "https://api.fluxions.ai/history/tts?voice=maeve.en-us&limit=10" \
  -H "Authorization: YOUR_API_KEY"
```

**Python (.py)**
```python
import requests

r = requests.get(
    'https://api.fluxions.ai/history/tts',
    headers={'Authorization': 'YOUR_API_KEY'},
    params={'voice': 'maeve.en-us', 'limit': 10},
)
for render in r.json()['data']:
    print(render['id'], render['chars'], render['download_url'])
```

**JavaScript (.js)**
```javascript
const res = await fetch('https://api.fluxions.ai/history/tts?voice=maeve.en-us&limit=10', {
  headers: {'Authorization': 'YOUR_API_KEY'}
});
const { data } = await res.json();
data.forEach(r => console.log(r.id, r.chars, r.download_url));
```

### Response

```json
{
  "object": "list",
  "page": 1, "limit": 10, "total": 60, "has_more": true,
  "data": [
    {
      "object": "tts",
      "id": 123,
      "created_at": "2026-06-29T10:32:00Z",
      "cost_usd": 0.0123,
      "voice": "maeve.en-us",
      "chars": 842,
      "audio_secs": 58.4,
      "download_url": "https://...r2.cloudflarestorage.com/...opus"
    }
  ]
}
```

## GET /history/tts/{id} — One Render

Returns one render with a fresh signed `download_url`. `404` if it isn't yours.

```bash
curl "https://api.fluxions.ai/history/tts/123" \
  -H "Authorization: YOUR_API_KEY"
```

## GET /history/conversations — Conversation History

List your voice conversations (agent calls).

### Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `voice` | string | — | Filter by voice id |

*(plus all shared parameters)*

### Request

**Bash (.sh)**
```bash
curl "https://api.fluxions.ai/history/conversations?limit=10" \
  -H "Authorization: YOUR_API_KEY"
```

**Python (.py)**
```python
import requests

r = requests.get(
    'https://api.fluxions.ai/history/conversations',
    headers={'Authorization': 'YOUR_API_KEY'},
    params={'limit': 10},
)
for c in r.json()['data']:
    print(c['id'], c['turn_count'], c['duration_secs'])
```

**JavaScript (.js)**
```javascript
const res = await fetch('https://api.fluxions.ai/history/conversations?limit=10', {
  headers: {'Authorization': 'YOUR_API_KEY'}
});
const { data } = await res.json();
data.forEach(c => console.log(c.id, c.turn_count, c.duration_secs));
```

### Response

```json
{
  "object": "list",
  "page": 1, "limit": 10, "total": 23, "has_more": true,
  "data": [
    {
      "object": "conversation",
      "id": "sess_abc123",
      "created_at": "2026-06-29T10:40:00Z",
      "cost_usd": null,
      "voice": "maeve.en-us",
      "started_at": "2026-06-29T10:40:00Z",
      "ended_at": "2026-06-29T10:45:12Z",
      "duration_secs": 312.4,
      "turn_count": 18
    }
  ]
}
```

## GET /history/conversations/{id} — One Conversation

Returns the session plus its turn-by-turn transcript. `404` if it isn't yours.

### Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `include_turns` | boolean | `true` | Include the transcript turns |
| `include_tool_calls` | boolean | `false` | Include tool invocations (calendar, email, …) |
| `turns_limit` | integer | `500` | Max turns to return (max: 2000) |

### Request

```bash
curl "https://api.fluxions.ai/history/conversations/sess_abc123?include_tool_calls=true" \
  -H "Authorization: YOUR_API_KEY"
```

### Response

```json
{
  "object": "conversation",
  "id": "sess_abc123",
  "created_at": "2026-06-29T10:40:00Z",
  "voice": "maeve.en-us",
  "duration_secs": 312.4,
  "turn_count": 18,
  "turns": [
    { "object": "conversation_turn", "id": 9001, "session_id": "sess_abc123",
      "role": "user", "text": "What's on my calendar today?", "created_at": "2026-06-29T10:40:05Z" },
    { "object": "conversation_turn", "id": 9002, "session_id": "sess_abc123",
      "role": "assistant", "text": "You have two meetings...", "created_at": "2026-06-29T10:40:08Z" }
  ],
  "tool_calls": [
    { "object": "tool_call", "id": 51, "tool": "calendar",
      "args": {"range": "today"}, "result": "2 events", "created_at": "2026-06-29T10:40:07Z" }
  ]
}
```

## GET /history/conversations/search — Search Turns

Full-text search across your conversation turns (Postgres `websearch_to_tsquery`).

### Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `q` | string | *(required)* | Search query |
| `limit` | integer | `20` | Max results (max: 100) |

### Request

```bash
curl "https://api.fluxions.ai/history/conversations/search?q=dentist+appointment" \
  -H "Authorization: YOUR_API_KEY"
```

### Response

```json
{
  "object": "list",
  "query": "dentist appointment",
  "data": [
    { "object": "conversation_turn", "id": 9100, "session_id": "sess_def456",
      "role": "user", "text": "remind me about the dentist appointment",
      "created_at": "2026-06-20T14:02:00Z" }
  ]
}
```

## GET /history/search — Cross-Domain Search

Search across your whole history in one call. Conversation turns are matched by full text; transcriptions are matched by filename (their text lives in object storage, not the database). Results are type-tagged via `object`.

### Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `q` | string | *(required)* | Search query |
| `limit` | integer | `20` | Max results per domain (max: 100) |

### Request

```bash
curl "https://api.fluxions.ai/history/search?q=interview" \
  -H "Authorization: YOUR_API_KEY"
```

### Response

```json
{
  "object": "list",
  "query": "interview",
  "data": [
    { "object": "conversation_turn", "id": 9200, "session_id": "sess_ghi",
      "role": "assistant", "text": "...the interview went well...", "created_at": "2026-06-25T09:00:00Z" },
    { "object": "transcription", "id": 456, "created_at": "2026-06-29T10:35:00Z",
      "status": "completed", "filename": "interview.mp3", "audio_duration_secs": 1800.0 }
  ]
}
```
