---
name: talkgenai
description: Write a researched, SEO-structured article and publish it to a WordPress, Webflow, Shopify or Wix site. Use when the user wants a blog post written, drafted, or published to their own site.
homepage: https://app.talkgen.ai
---

# TalkGenAI

Generate a full SEO article and put it on the user's site.

Agents can already write. What they usually cannot do is get the result onto someone's
WordPress with a hero image, FAQ schema, internal links and a meta description in place.
That is what this API is for.

**Base URL:** `https://app.talkgen.ai`
**Auth:** `Authorization: Bearer tgai_...` on every request.

**Where the key is:** look for `TALKGENAI_API_KEY` in the environment or in a local `.env`
file. If it is not there, stop and ask the user for it rather than guessing. They create one
at <https://app.talkgen.ai/connect-agent> (free account, no card, about 3 articles of
starting credit). Treat it like a password: it can publish to the user's live site. Never
print it, log it, or write it into a file you commit.

**Cost:** 5 credits per article, 8 with an image. Reading and publishing are free.

---

## If your client speaks MCP, use that instead

There is a Model Context Protocol server at `https://app.talkgen.ai/mcp`. It exposes the same
commands as native tools, so the client discovers them itself and you can ignore the rest of
this file.

```bash
# Claude Code
claude mcp add --transport http talkgenai https://app.talkgen.ai/mcp \
  --header "Authorization: Bearer $TALKGENAI_API_KEY"
```

```jsonc
// Cursor (.cursor/mcp.json) or VS Code (.vscode/mcp.json)
{
  "mcpServers": {
    "talkgenai": {
      "type": "http",
      "url": "https://app.talkgen.ai/mcp",
      "headers": { "Authorization": "Bearer tgai_your_key_here" }
    }
  }
}
```

Claude Desktop reaches remote servers through `mcp-remote`:

```jsonc
{
  "mcpServers": {
    "talkgenai": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://app.talkgen.ai/mcp",
               "--header", "Authorization: Bearer tgai_your_key_here"]
    }
  }
}
```

Tools: `list_sites` · `get_content_plan` · `generate_article` · `get_article` ·
`publish_article` · `check_credits` · `get_rankings`. Same key, same credits, same
draft-by-default rule.

The rest of this file is the plain HTTP version, for agents without an MCP client.

---

## The whole loop

Write an article and leave it as a draft on the user's site:

```bash
# The key lives here. Set it once per shell.
export TALKGENAI_API_KEY=tgai_your_key_here
AUTH="Authorization: Bearer $TALKGENAI_API_KEY"

# 1. Which sites can I publish to?  (copy connection_id from the response)
curl -s -H "$AUTH" https://app.talkgen.ai/api/v1/sites

# 2. Start the article (costs 5 credits, returns immediately)
JOB=$(curl -s -X POST https://app.talkgen.ai/api/v1/articles \
  -H "$AUTH" -H "Content-Type: application/json" \
  -d '{"title":"How to choose a CRM for a 5-person agency","length":"medium"}' \
  | jq -r .job_id)

# 3. Poll every 10s until status is "completed" (45-360s depending on length)
curl -s -H "$AUTH" https://app.talkgen.ai/api/v1/articles/$JOB

# 4. Publish it as a DRAFT to the site from step 1
curl -s -X POST https://app.talkgen.ai/api/v1/articles/$JOB/publish \
  -H "$AUTH" -H "Content-Type: application/json" \
  -d '{"connection_id":"wpc_abc123"}'
```

Every example below assumes `$AUTH` is set as above.

Step 4 creates a **draft**, not a live post. To publish live, pass
`{"connection_id":"wpc_abc123","status":"publish"}` — see [Publishing safely](#publishing-safely).

---

## Working the content plan (the better loop)

If the user has a content plan, work from it instead of inventing titles. The plan already
holds the target keyword, the H2 outline, the word count and the strategic reason, and the
card is marked off automatically when you write it.

```bash
# 1. What is still open?
curl -s -H "$AUTH" https://app.talkgen.ai/api/v1/content-plan
```

```json
{
  "has_plan": true,
  "plan_id": "plan_7f3a2b",
  "domain": "example.com",
  "totals": { "planned": 21, "manually_written": 2, "published": 9 },
  "matching": 21,
  "cards": [
    {
      "card_index": 4,
      "title": "How to choose a CRM for a 5-person agency",
      "keyword": "crm for small agency",
      "month": 3,
      "status": "planned",
      "search_intent": "Commercial",
      "content_type": "Comparison",
      "suggested_length": "long",
      "h2_outline": ["Start with cost per seat", "Onboarding time", "Verdict"],
      "strategic_reason": "Buyers compare tools here before choosing.",
      "search_volume": 450,
      "keyword_difficulty": 12
    }
  ]
}
```

```bash
# 2. Write that card. No title needed - the brief comes from the plan.
curl -s -X POST https://app.talkgen.ai/api/v1/articles \
  -H "$AUTH" -H "Content-Type: application/json" \
  -d '{"plan_id":"plan_7f3a2b","card_index":4}'
```

The card is marked `manually_written` when generation finishes and `published` when you
publish it. You do not have to report anything back.

Filters: `?status=planned` · `?month=3` · `?limit=20` · `?include_done=true` ·
`?domain=example.com`. By default only OPEN cards are returned, so you will not repeat work.

⚠️ Agents cannot create a plan or change its schedule. A plan costs 20 credits and some
tiers get only one, so that stays a human decision.

---

## Commands

### List sites

```bash
curl -s -H "$AUTH" https://app.talkgen.ai/api/v1/sites
```

```json
{
  "sites": [
    {
      "connection_id": "wpc_9f2c41d7a8b3e05c6d1f2a4b",
      "site_url": "https://example.com",
      "site_name": "Example Blog",
      "platform": "wordpress",
      "auth_method": "plugin_token"
    }
  ],
  "count": 1
}
```

If `count` is 0, the user has not connected a site yet. Send them to
<https://app.talkgen.ai/dashboard> to connect one. You can still generate articles without
a site and hand back the HTML.

### Generate an article

```bash
curl -s -X POST https://app.talkgen.ai/api/v1/articles \
  -H "$AUTH" -H "Content-Type: application/json" \
  -d '{
    "title": "How to choose a CRM for a 5-person agency",
    "topic": "Practical buying guide for small agencies, focused on cost per seat and onboarding time",
    "length": "medium",
    "image": true,
    "focus_keyword": "crm for small agency"
  }'
```

| Field | Default | Notes |
|---|---|---|
| `title` | required | The article's headline. |
| `topic` | falls back to `title` | The angle or brief. Worth writing: it drives the whole piece. |
| `length` | `medium` | `short` (~500w) · `medium` (~900w) · `long` (~1400w) · `very_large` · `pillar` |
| `image` | `false` | Generates a hero image. Costs 3 extra credits. |
| `focus_keyword` | none | Target keyword for on-page SEO. |
| `instructions` | none | Free text: tone, audience, things to avoid. |
| `include_faq` | `true` | Appends an FAQ block with FAQ schema. |
| `include_external_link` | `true` | Cites outbound sources. |
| `brand_voice_id` | none | Use a brand voice the user trained in the dashboard. |
| `plan_id` + `card_index` | none | Write a content-plan card. Fills in title, keyword, length, outline and angle, and marks the card off. |

```json
{
  "success": true,
  "job_id": "job_1a2b3c4d5e6f",
  "status": "pending",
  "estimated_time": 90,
  "credits_remaining": 26,
  "poll_url": "https://app.talkgen.ai/api/v1/articles/job_1a2b3c4d5e6f"
}
```

### Poll for the result

```bash
curl -s -H "$AUTH" https://app.talkgen.ai/api/v1/articles/job_1a2b3c4d5e6f
```

While it runs:

```json
{ "job_id": "job_1a2b3c4d5e6f", "status": "processing", "progress": 30 }
```

When it finishes:

```json
{
  "job_id": "job_1a2b3c4d5e6f",
  "status": "completed",
  "progress": 100,
  "title": "How to Choose a CRM for a 5-Person Agency",
  "html": "<h2>Start with cost per seat</h2><p>...",
  "seo_title": "How to Choose a CRM for a Small Agency (2026 Guide)",
  "meta_description": "A practical buying guide for agencies under 10 people...",
  "focus_keyword": "crm for small agency",
  "word_count": 912,
  "has_image": true
}
```

`status` is one of `pending`, `processing`, `completed`, `failed`. On `failed` there is an
`error` field. **Poll every 5 to 10 seconds, not continuously** — free endpoints are limited
to roughly 60 requests a minute per key.

### Publish

```bash
curl -s -X POST https://app.talkgen.ai/api/v1/articles/job_1a2b3c4d5e6f/publish \
  -H "$AUTH" -H "Content-Type: application/json" \
  -d '{"connection_id":"wpc_9f2c41d7a8b3e05c6d1f2a4b"}'
```

```json
{
  "success": true,
  "post_id": 4471,
  "post_url": "https://example.com/?p=4471",
  "edit_url": "https://example.com/wp-admin/post.php?post=4471&action=edit",
  "status": "draft",
  "note": "Saved as a draft. It is not public yet. Open edit_url to review, or publish with {\"status\": \"publish\"}."
}
```

The hero image is uploaded and set as the featured image automatically. Publishing the same
article to the same site twice updates the existing post instead of creating a duplicate, so
a retry after a timeout is safe.

### Check credits

```bash
curl -s -H "$AUTH" https://app.talkgen.ai/api/v1/credits
```

```json
{
  "plan": "free",
  "credits_remaining": 24,
  "bonus_credits": 11,
  "total_available": 35,
  "costs": { "article": 5, "article_with_image": 8, "publish": 0, "read": 0 }
}
```

### Rankings (Growth plan and above)

```bash
curl -s -H "$AUTH" "https://app.talkgen.ai/api/v1/rankings?site=https://example.com"
```

Returns Google Search Console positions, clicks and impressions for the connected site.
Useful for deciding what to write next rather than guessing. Returns `403
plan_upgrade_required` on Free and Starter.

---

## Publishing safely

**`status` defaults to `draft`.** You have to ask for a live post:

```json
{ "connection_id": "wpc_...", "status": "publish" }
```

This is deliberate, and it overrides whatever default the user set in their dashboard.
Publishing to someone's real website is not reversible in the way a draft is — the post can
be indexed, shared or seen before anyone notices a mistake.

**If you are an agent running without a human watching each step, publish drafts.** Give the
user the `edit_url` and let them press the button. Only pass `status: "publish"` when the
user has actually asked for the post to go live.

A workspace can also switch live publishing off for agents entirely. If it has,
`status: "publish"` returns `403 live_publish_disabled` and there is no way around it. Save
a draft and tell the user.

---

## Errors

Every error is JSON with a `code` and a `message` you can show the user.

| Status | `code` | What to do |
|---|---|---|
| 401 | `unauthorized` | Key is missing, malformed or revoked. Get a new one at `/connect-agent`. |
| 403 | `insufficient_credits` | Out of credits. The response has `credit_cost` and `upgrade_url`. |
| 403 | `domain_mismatch` | You are using a WordPress *plugin* key, which is locked to one site. Create an **agent key** at `/connect-agent` instead. |
| 403 | `plan_upgrade_required` | Feature is on a higher plan. `upgrade_url` is in the response. |
| 400 | `not_ready` | The article has not finished generating. Keep polling. |
| 404 | `site_not_found` | Bad `connection_id`. Re-read `GET /api/v1/sites`. |
| 404 | `plan_not_found` / `card_not_found` | Re-read `GET /api/v1/content-plan`. |
| 409 | `card_already_published` | That card is done. Pick another. |
| 403 | `live_publish_disabled` | This workspace forbids agents publishing live. Save a draft instead. |
| 429 | `rate_limited` | Slow the polling down. Retry after 60s. |

A free account cannot spend its monthly credits on images: image generation has to be
covered by bonus credits. If `image: true` returns `insufficient_credits` on a free plan
while `total_available` looks sufficient, generate without the image, or upgrade.

---

## Notes

- Generation is asynchronous. There is no synchronous "give me the article now" call, and a
  `long` or `pillar` article genuinely takes several minutes.
- The article HTML is returned to you as well as published, so you can post it somewhere
  else, save it to a file, or show it to the user before publishing.
- WordPress, Webflow, Shopify and Wix are all supported through the same `connection_id`.
- Read endpoints are free but limited to about 60 requests per minute per key. That limit is
  best effort, not a hard guarantee.
