# BotTalk Publishers API

## API documentation redirect

> Redirects to the API documentation page

```json
{"openapi":"3.0.3","info":{"title":"BotTalk Publishers API","version":"1.0.0"},"servers":[{"url":"https://bottalk.io","description":"Production"}],"security":[],"paths":{"/api":{"get":{"summary":"API documentation redirect","description":"Redirects to the API documentation page","operationId":"apiRedirect","responses":{"302":{"description":"Redirect to https://bottalk.io/docs/api/"}}}}}}
```

## List articles

> Returns a paginated list of articles for the authenticated project. Deleted articles are excluded.

```json
{"openapi":"3.0.3","info":{"title":"BotTalk Publishers API","version":"1.0.0"},"servers":[{"url":"https://bottalk.io","description":"Production"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"API token from project settings"}},"schemas":{"ArticleListItem":{"type":"object","description":"Abbreviated article object returned in list responses","properties":{"id":{"type":"string"},"external_id":{"type":"string","nullable":true},"title":{"type":"string"},"text":{"type":"string"},"added":{"type":"integer"},"updated":{"type":"integer","nullable":true},"status":{"type":"string"},"url":{"type":"string","nullable":true},"isRaw":{"type":"boolean"},"voice":{"type":"string"},"lang":{"type":"string"},"audio":{"type":"string","nullable":true},"audio_duration":{"type":"number","nullable":true},"audio_preview":{"type":"string","nullable":true},"audio_preview_duration":{"type":"number","nullable":true}}},"ErrorResult":{"type":"object","properties":{"result":{"type":"string","enum":["error","fail"]},"message":{"type":"string"}}}}},"paths":{"/api/articles":{"get":{"summary":"List articles","description":"Returns a paginated list of articles for the authenticated project. Deleted articles are excluded.","operationId":"getArticles","parameters":[{"name":"limit","in":"query","description":"Number of articles to return (min 10, max 100)","schema":{"type":"integer","minimum":10,"maximum":100,"default":10}},{"name":"offset","in":"query","description":"Number of articles to skip","schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"List of articles","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"string"},"count":{"type":"integer"},"articles":{"type":"array","items":{"$ref":"#/components/schemas/ArticleListItem"}}}}}}},"403":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResult"}}}}}}}}}
```

## Create article

> Creates a new article and queues it for audio generation.\
> Requires a full API token (not readonly).\
> If \`externalId\` is provided it must be unique across all articles.<br>

```json
{"openapi":"3.0.3","info":{"title":"BotTalk Publishers API","version":"1.0.0"},"servers":[{"url":"https://bottalk.io","description":"Production"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"API token from project settings"}},"schemas":{"ArticleCreateRequest":{"type":"object","required":["title","text"],"properties":{"title":{"type":"string","description":"Article title"},"text":{"type":"string","description":"Article body text (HTML allowed if parse=true)"},"url":{"type":"string","description":"Original article URL"},"externalId":{"type":"string","description":"Unique ID for external control. If an article with this ID already exists, a 400 error is returned."},"voice":{"type":"string","description":"TTS voice name. Must be used together with `lang`.\nAvailable voices: `echo`, `fable`, `alloy`, `onyx`, `nova`, `shimmer` (support `de-DE`, `en-US`),\n`de-DE-ConradNeural`, `de-DE-KatjaNeural` (support `de-DE`)\n"},"lang":{"type":"string","description":"Voice language/locale. Must be used together with `voice`.\nExamples: `de-DE`, `en-US`\n"},"parse":{"type":"boolean","description":"If true, HTML is stripped and text is cleaned before processing","default":false},"isRaw":{"type":"boolean","description":"If true, text is treated as raw (no additional processing)","default":false},"prompt":{"type":"string","description":"Individual prompt for audio generation (valid for Gemini Vertex model)"},"labels":{"type":"array","description":"List of labels to attach to this article","items":{"type":"string"}}}},"ErrorResult":{"type":"object","properties":{"result":{"type":"string","enum":["error","fail"]},"message":{"type":"string"}}}}},"paths":{"/api/articles":{"post":{"summary":"Create article","description":"Creates a new article and queues it for audio generation.\nRequires a full API token (not readonly).\nIf `externalId` is provided it must be unique across all articles.\n","operationId":"createArticle","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArticleCreateRequest"}}}},"responses":{"200":{"description":"Article created successfully","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"string"},"id":{"type":"string","description":"Slug of the newly created article"}}}}}},"400":{"description":"Validation error or duplicate externalId","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResult"}}}},"403":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResult"}}}}}}}}}
```

## Get article by ID

> Returns full article details by its internal slug ID.

```json
{"openapi":"3.0.3","info":{"title":"BotTalk Publishers API","version":"1.0.0"},"servers":[{"url":"https://bottalk.io","description":"Production"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"API token from project settings"}},"schemas":{"Article":{"type":"object","properties":{"id":{"type":"string","description":"Article slug (internal ID)"},"externalId":{"type":"string","nullable":true,"description":"Unique ID for external control. If an article with this ID already exists, a 400 error is returned."},"title":{"type":"string"},"text":{"type":"string"},"prompt":{"type":"string","nullable":true,"description":"Individual prompt for audio generation (valid for Gemini Vertex model)"},"added":{"type":"integer","description":"Unix timestamp when article was created"},"updated":{"type":"integer","nullable":true,"description":"Unix timestamp of last processing"},"status":{"type":"string","enum":["waiting","processing","ready","errored","deleted","retry","fallback","no_money","limit_reached","rejected","parsed","recrawling"],"description":"Article processing status:\n- `ready` — article is ready and audio file exists\n- `processing` — audification is in progress\n- `waiting` — article is waiting to be audified\n- `retry` — TTS provider returned an error, will retry automatically\n- `rejected` — article rejected by audio automation rules\n- `errored` — error which prevented audification\n- `deleted` — article has been deleted\n- `fallback` — using fallback TTS provider\n- `no_money` — insufficient balance\n- `limit_reached` — daily article limit reached\n- `parsed` — article parsed, awaiting audification\n- `recrawling` — article content is being re-fetched\n"},"url":{"type":"string","nullable":true,"description":"Original article URL"},"isRaw":{"type":"boolean","description":"Whether article text is raw (no HTML stripping)"},"voice":{"type":"string","description":"TTS voice name. Available voices:\n`echo`, `fable`, `alloy`, `onyx`, `nova`, `shimmer` (support `de-DE`, `en-US`),\n`de-DE-ConradNeural`, `de-DE-KatjaNeural` (support `de-DE`)\n"},"lang":{"type":"string","description":"Voice language/locale. Must match the selected voice.\nExamples: `de-DE`, `en-US`\n"},"type":{"type":"array","nullable":true,"description":"Content type scores from comprehend analysis (only if detected)","items":{"type":"object","properties":{"Name":{"type":"string"},"Score":{"type":"number","format":"float"}}}},"audio":{"type":"string","nullable":true,"description":"Full audio MP3 URL (only when ready)"},"audio_duration":{"type":"number","nullable":true,"description":"Full audio duration in seconds"},"audio_preview":{"type":"string","nullable":true,"description":"Preview audio MP3 URL (only when ready)"},"audio_preview_duration":{"type":"number","nullable":true,"description":"Preview audio duration in seconds"},"error":{"type":"string","nullable":true,"description":"Last error message (only when status=errored)"},"errors":{"type":"array","nullable":true,"description":"Error history (only when status=errored)","items":{"type":"object","properties":{"error":{"type":"string"},"date":{"type":"string","format":"date-time"}}}}}},"ErrorResult":{"type":"object","properties":{"result":{"type":"string","enum":["error","fail"]},"message":{"type":"string"}}}}},"paths":{"/api/articles/{articleId}":{"get":{"summary":"Get article by ID","description":"Returns full article details by its internal slug ID.","operationId":"getArticle","parameters":[{"name":"articleId","in":"path","required":true,"description":"Article slug (internal ID returned on create)","schema":{"type":"string"}}],"responses":{"200":{"description":"Article found","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"string"},"article":{"$ref":"#/components/schemas/Article"}}}}}},"403":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResult"}}}},"200 (not found)":{"description":"Article not found (returns 200 with error result)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResult"}}}}}}}}}
```

## Update article by ID

> Updates article content and triggers audio re-generation.\
> Requires a full API token (not readonly).\
> Labels are fully replaced — any existing labels not present in the request will be removed.<br>

```json
{"openapi":"3.0.3","info":{"title":"BotTalk Publishers API","version":"1.0.0"},"servers":[{"url":"https://bottalk.io","description":"Production"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"API token from project settings"}},"schemas":{"ArticleUpdateRequest":{"type":"object","required":["title","text"],"properties":{"title":{"type":"string"},"text":{"type":"string"},"url":{"type":"string"},"externalId":{"type":"string","description":"Update the external ID (must be unique)"},"voice":{"type":"string"},"lang":{"type":"string"},"parse":{"type":"boolean","default":false},"isRaw":{"type":"boolean"},"prompt":{"type":"string","nullable":true,"description":"Individual prompt for audio generation (valid for Gemini Vertex model). Set to null to remove."},"labels":{"type":"array","description":"Full replacement of labels (existing labels not in list will be removed)","items":{"type":"string"}}}},"ErrorResult":{"type":"object","properties":{"result":{"type":"string","enum":["error","fail"]},"message":{"type":"string"}}}}},"paths":{"/api/articles/{articleId}":{"put":{"summary":"Update article by ID","description":"Updates article content and triggers audio re-generation.\nRequires a full API token (not readonly).\nLabels are fully replaced — any existing labels not present in the request will be removed.\n","operationId":"updateArticle","parameters":[{"name":"articleId","in":"path","required":true,"description":"Article slug (internal ID)","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArticleUpdateRequest"}}}},"responses":{"200":{"description":"Article updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"string"},"id":{"type":"string"}}}}}},"400":{"description":"Validation error or duplicate externalId","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResult"}}}},"401":{"description":"Article belongs to a different project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResult"}}}},"403":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResult"}}}}}}}}}
```

## Delete article

> Marks the article as deleted. Deleted articles are excluded from list responses.\
> Requires a full API token (not readonly).<br>

```json
{"openapi":"3.0.3","info":{"title":"BotTalk Publishers API","version":"1.0.0"},"servers":[{"url":"https://bottalk.io","description":"Production"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"API token from project settings"}},"schemas":{"SuccessResult":{"type":"object","properties":{"result":{"type":"string","enum":["ok"]}}},"ErrorResult":{"type":"object","properties":{"result":{"type":"string","enum":["error","fail"]},"message":{"type":"string"}}}}},"paths":{"/api/articles/{articleId}":{"delete":{"summary":"Delete article","description":"Marks the article as deleted. Deleted articles are excluded from list responses.\nRequires a full API token (not readonly).\n","operationId":"deleteArticle","parameters":[{"name":"articleId","in":"path","required":true,"description":"Article slug (internal ID)","schema":{"type":"string"}}],"responses":{"200":{"description":"Article deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResult"}}}},"403":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResult"}}}},"404":{"description":"Article not found or already deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResult"}}}}}}}}}
```

## Get article by external ID

> Returns full article details by the external ID you provided on creation.

```json
{"openapi":"3.0.3","info":{"title":"BotTalk Publishers API","version":"1.0.0"},"servers":[{"url":"https://bottalk.io","description":"Production"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"API token from project settings"}},"schemas":{"Article":{"type":"object","properties":{"id":{"type":"string","description":"Article slug (internal ID)"},"externalId":{"type":"string","nullable":true,"description":"Unique ID for external control. If an article with this ID already exists, a 400 error is returned."},"title":{"type":"string"},"text":{"type":"string"},"prompt":{"type":"string","nullable":true,"description":"Individual prompt for audio generation (valid for Gemini Vertex model)"},"added":{"type":"integer","description":"Unix timestamp when article was created"},"updated":{"type":"integer","nullable":true,"description":"Unix timestamp of last processing"},"status":{"type":"string","enum":["waiting","processing","ready","errored","deleted","retry","fallback","no_money","limit_reached","rejected","parsed","recrawling"],"description":"Article processing status:\n- `ready` — article is ready and audio file exists\n- `processing` — audification is in progress\n- `waiting` — article is waiting to be audified\n- `retry` — TTS provider returned an error, will retry automatically\n- `rejected` — article rejected by audio automation rules\n- `errored` — error which prevented audification\n- `deleted` — article has been deleted\n- `fallback` — using fallback TTS provider\n- `no_money` — insufficient balance\n- `limit_reached` — daily article limit reached\n- `parsed` — article parsed, awaiting audification\n- `recrawling` — article content is being re-fetched\n"},"url":{"type":"string","nullable":true,"description":"Original article URL"},"isRaw":{"type":"boolean","description":"Whether article text is raw (no HTML stripping)"},"voice":{"type":"string","description":"TTS voice name. Available voices:\n`echo`, `fable`, `alloy`, `onyx`, `nova`, `shimmer` (support `de-DE`, `en-US`),\n`de-DE-ConradNeural`, `de-DE-KatjaNeural` (support `de-DE`)\n"},"lang":{"type":"string","description":"Voice language/locale. Must match the selected voice.\nExamples: `de-DE`, `en-US`\n"},"type":{"type":"array","nullable":true,"description":"Content type scores from comprehend analysis (only if detected)","items":{"type":"object","properties":{"Name":{"type":"string"},"Score":{"type":"number","format":"float"}}}},"audio":{"type":"string","nullable":true,"description":"Full audio MP3 URL (only when ready)"},"audio_duration":{"type":"number","nullable":true,"description":"Full audio duration in seconds"},"audio_preview":{"type":"string","nullable":true,"description":"Preview audio MP3 URL (only when ready)"},"audio_preview_duration":{"type":"number","nullable":true,"description":"Preview audio duration in seconds"},"error":{"type":"string","nullable":true,"description":"Last error message (only when status=errored)"},"errors":{"type":"array","nullable":true,"description":"Error history (only when status=errored)","items":{"type":"object","properties":{"error":{"type":"string"},"date":{"type":"string","format":"date-time"}}}}}},"ErrorResult":{"type":"object","properties":{"result":{"type":"string","enum":["error","fail"]},"message":{"type":"string"}}}}},"paths":{"/api/articles_external_id/{externalId}":{"get":{"summary":"Get article by external ID","description":"Returns full article details by the external ID you provided on creation.","operationId":"getArticleByExternalId","parameters":[{"name":"externalId","in":"path","required":true,"description":"Your external article identifier","schema":{"type":"string"}}],"responses":{"200":{"description":"Article found","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"string"},"article":{"$ref":"#/components/schemas/Article"}}}}}},"403":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResult"}}}},"200 (not found)":{"description":"Article not found (returns 200 with error result)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResult"}}}}}}}}}
```

## Update article by external ID

> Updates article by external ID and triggers audio re-generation.\
> Requires a full API token (not readonly).<br>

```json
{"openapi":"3.0.3","info":{"title":"BotTalk Publishers API","version":"1.0.0"},"servers":[{"url":"https://bottalk.io","description":"Production"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"API token from project settings"}},"schemas":{"ArticleUpdateRequest":{"type":"object","required":["title","text"],"properties":{"title":{"type":"string"},"text":{"type":"string"},"url":{"type":"string"},"externalId":{"type":"string","description":"Update the external ID (must be unique)"},"voice":{"type":"string"},"lang":{"type":"string"},"parse":{"type":"boolean","default":false},"isRaw":{"type":"boolean"},"prompt":{"type":"string","nullable":true,"description":"Individual prompt for audio generation (valid for Gemini Vertex model). Set to null to remove."},"labels":{"type":"array","description":"Full replacement of labels (existing labels not in list will be removed)","items":{"type":"string"}}}},"ErrorResult":{"type":"object","properties":{"result":{"type":"string","enum":["error","fail"]},"message":{"type":"string"}}}}},"paths":{"/api/articles_external_id/{externalId}":{"put":{"summary":"Update article by external ID","description":"Updates article by external ID and triggers audio re-generation.\nRequires a full API token (not readonly).\n","operationId":"updateArticleByExternalId","parameters":[{"name":"externalId","in":"path","required":true,"description":"Your external article identifier","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArticleUpdateRequest"}}}},"responses":{"200":{"description":"Article updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"string"},"id":{"type":"string"}}}}}},"400":{"description":"Validation error or duplicate externalId","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResult"}}}},"403":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResult"}}}},"404":{"description":"Article not found by externalId","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResult"}}}}}}}}}
```

## Get article by URL

> Returns full article details by the original article URL.

```json
{"openapi":"3.0.3","info":{"title":"BotTalk Publishers API","version":"1.0.0"},"servers":[{"url":"https://bottalk.io","description":"Production"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"API token from project settings"}},"schemas":{"Article":{"type":"object","properties":{"id":{"type":"string","description":"Article slug (internal ID)"},"externalId":{"type":"string","nullable":true,"description":"Unique ID for external control. If an article with this ID already exists, a 400 error is returned."},"title":{"type":"string"},"text":{"type":"string"},"prompt":{"type":"string","nullable":true,"description":"Individual prompt for audio generation (valid for Gemini Vertex model)"},"added":{"type":"integer","description":"Unix timestamp when article was created"},"updated":{"type":"integer","nullable":true,"description":"Unix timestamp of last processing"},"status":{"type":"string","enum":["waiting","processing","ready","errored","deleted","retry","fallback","no_money","limit_reached","rejected","parsed","recrawling"],"description":"Article processing status:\n- `ready` — article is ready and audio file exists\n- `processing` — audification is in progress\n- `waiting` — article is waiting to be audified\n- `retry` — TTS provider returned an error, will retry automatically\n- `rejected` — article rejected by audio automation rules\n- `errored` — error which prevented audification\n- `deleted` — article has been deleted\n- `fallback` — using fallback TTS provider\n- `no_money` — insufficient balance\n- `limit_reached` — daily article limit reached\n- `parsed` — article parsed, awaiting audification\n- `recrawling` — article content is being re-fetched\n"},"url":{"type":"string","nullable":true,"description":"Original article URL"},"isRaw":{"type":"boolean","description":"Whether article text is raw (no HTML stripping)"},"voice":{"type":"string","description":"TTS voice name. Available voices:\n`echo`, `fable`, `alloy`, `onyx`, `nova`, `shimmer` (support `de-DE`, `en-US`),\n`de-DE-ConradNeural`, `de-DE-KatjaNeural` (support `de-DE`)\n"},"lang":{"type":"string","description":"Voice language/locale. Must match the selected voice.\nExamples: `de-DE`, `en-US`\n"},"type":{"type":"array","nullable":true,"description":"Content type scores from comprehend analysis (only if detected)","items":{"type":"object","properties":{"Name":{"type":"string"},"Score":{"type":"number","format":"float"}}}},"audio":{"type":"string","nullable":true,"description":"Full audio MP3 URL (only when ready)"},"audio_duration":{"type":"number","nullable":true,"description":"Full audio duration in seconds"},"audio_preview":{"type":"string","nullable":true,"description":"Preview audio MP3 URL (only when ready)"},"audio_preview_duration":{"type":"number","nullable":true,"description":"Preview audio duration in seconds"},"error":{"type":"string","nullable":true,"description":"Last error message (only when status=errored)"},"errors":{"type":"array","nullable":true,"description":"Error history (only when status=errored)","items":{"type":"object","properties":{"error":{"type":"string"},"date":{"type":"string","format":"date-time"}}}}}},"ErrorResult":{"type":"object","properties":{"result":{"type":"string","enum":["error","fail"]},"message":{"type":"string"}}}}},"paths":{"/api/articles_external_url/{externalUrl}":{"get":{"summary":"Get article by URL","description":"Returns full article details by the original article URL.","operationId":"getArticleByExternalUrl","parameters":[{"name":"externalUrl","in":"path","required":true,"description":"Original article URL (URL-encoded)","schema":{"type":"string"}}],"responses":{"200":{"description":"Article found","content":{"application/json":{"schema":{"type":"object","properties":{"result":{"type":"string"},"article":{"$ref":"#/components/schemas/Article"}}}}}},"403":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResult"}}}},"200 (not found)":{"description":"Article not found (returns 200 with error result)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResult"}}}}}}}}}
```
