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

# Blog Articles API

> Fetch generated YALG blog articles from your server application.

Use the Blog Articles API when your site wants to pull finished YALG articles and render them in its own blog. Your application calls YALG from a trusted server environment with a Developer API key.

<Note>
  This is the pull-based integration. If you want YALG to push completed articles to your own endpoint, see Blog Delivery.
</Note>

## 1. Create a Developer API key

1. Sign in to YALG.
2. Open `Settings > Developer`.
3. Create a named API key for the site or environment that will read blog articles.
4. Copy the full key immediately. It is shown once.
5. Store it server-side, for example as `YALG_BLOG_API_KEY`.

```bash theme={null}
YALG_BLOG_API_KEY="yalg_live_PUBLIC_ID.SECRET"
```

<Warning>
  API keys are shown once. Store them in a server-side secret manager or
  environment variable, and never expose them in client-side code.
</Warning>

<Warning>
  Do not expose this key in browser JavaScript. Fetch YALG articles from your backend, server component, serverless function, or worker.
</Warning>

## 2. List blog articles

```http theme={null}
GET https://api.yalg.ai/v1/blog/articles
x-api-key: yalg_live_PUBLIC_ID.SECRET
```

The request is scoped to the API key owner. You do not send a user id.

```bash theme={null}
curl https://api.yalg.ai/v1/blog/articles \
  -H "x-api-key: $YALG_BLOG_API_KEY"
```

The response is an array of article summaries. It includes metadata needed to render cards and choose which articles are public, but it does not include the full Markdown body.

```json theme={null}
[
  {
    "id": "123e4567-e89b-12d3-a456-426614174000",
    "userId": "user_abc",
    "topic": "How to write a LinkedIn post with ChatGPT",
    "angle": null,
    "articleTitle": "How to write a LinkedIn post with ChatGPT in 2026",
    "slug": "how-to-write-linkedin-post-chatgpt",
    "seoDescription": "A practical guide to writing better LinkedIn posts with ChatGPT.",
    "excerpt": "Learn how to turn an idea into a structured LinkedIn post with ChatGPT.",
    "coverImageUrl": "https://api.yalg.ai/uploads/blog-cover-images/article.webp",
    "coverImageAlt": "Editorial cover image for the article",
    "coverImagePrompt": "Create a premium realistic editorial blog cover image.",
    "coverImageError": null,
    "coverImageGeneratedAt": "2026-06-24T12:30:00.000Z",
    "status": "FINISHED",
    "currentStep": "IMAGE_GENERATION",
    "qualityScore": 91,
    "seoScore": 84,
    "riskLevel": "low",
    "warningsCount": 0,
    "version": 1,
    "language": "en",
    "deliveryStatus": "NOT_CONFIGURED",
    "deliveryAttempts": 0,
    "deliveryLastError": null,
    "deliveryResponseStatus": null,
    "deliveryClientPostId": null,
    "deliveryClientPostUrl": null,
    "deliveredAt": null,
    "createdAt": "2026-06-24T12:00:00.000Z",
    "updatedAt": "2026-06-24T12:30:00.000Z"
  }
]
```

### Public rendering filter

The list endpoint returns all blog article jobs for the key owner, including drafts, running jobs, failed jobs, and completed jobs. For a public blog, filter before rendering:

* `status` should be `FINISHED` or `PUBLISHED`.
* `language` should match the current site locale, such as `en`, `fr`, or `es`.
* `slug` should be present.
* `articleTitle` or `topic` should be present.

## 3. Get one article with Markdown

Use the article id from the list response:

```http theme={null}
GET https://api.yalg.ai/v1/blog/articles/{id}
x-api-key: yalg_live_PUBLIC_ID.SECRET
```

```bash theme={null}
curl https://api.yalg.ai/v1/blog/articles/123e4567-e89b-12d3-a456-426614174000 \
  -H "x-api-key: $YALG_BLOG_API_KEY"
```

The detail response contains the same metadata plus generation details and `articleMarkdown`.

```json theme={null}
{
  "id": "123e4567-e89b-12d3-a456-426614174000",
  "topic": "How to write a LinkedIn post with ChatGPT",
  "articleTitle": "How to write a LinkedIn post with ChatGPT in 2026",
  "slug": "how-to-write-linkedin-post-chatgpt",
  "seoDescription": "A practical guide to writing better LinkedIn posts with ChatGPT.",
  "excerpt": "Learn how to turn an idea into a structured LinkedIn post with ChatGPT.",
  "status": "FINISHED",
  "language": "en",
  "version": 1,
  "qualityScore": 91,
  "seoScore": 84,
  "warnings": [],
  "articleMarkdown": "# How to write a LinkedIn post with ChatGPT in 2026\n\n...",
  "coverImageUrl": "https://api.yalg.ai/uploads/blog-cover-images/article.webp",
  "deliveryStatus": "NOT_CONFIGURED",
  "startedAt": "2026-06-24T12:00:00.000Z",
  "completedAt": "2026-06-24T12:30:00.000Z",
  "createdAt": "2026-06-24T12:00:00.000Z",
  "updatedAt": "2026-06-24T12:30:00.000Z",
  "artifacts": []
}
```

`articleMarkdown` can be `null` while an article is still running, blocked, or failed. Treat it as the canonical article body once the article is `FINISHED` or `PUBLISHED`.

## Download raw Markdown

If you only need the article body as a Markdown file, use:

```http theme={null}
GET https://api.yalg.ai/v1/blog/articles/{id}/export-markdown
x-api-key: yalg_live_PUBLIC_ID.SECRET
```

This returns `text/markdown; charset=utf-8` and a `Content-Disposition` attachment filename based on the article topic. The endpoint returns an error if Markdown is not available yet.

## 4. Example server-side fetch

```javascript theme={null}
const API_BASE_URL = process.env.YALG_API_BASE_URL || "https://api.yalg.ai";

async function fetchYalgBlogArticles(locale = "en") {
  const response = await fetch(`${API_BASE_URL}/v1/blog/articles`, {
    headers: {
      "x-api-key": process.env.YALG_BLOG_API_KEY,
    },
  });

  if (!response.ok) {
    throw new Error(`YALG blog request failed: ${response.status}`);
  }

  const articles = await response.json();

  return articles.filter((article) =>
    ["FINISHED", "PUBLISHED"].includes(article.status) &&
    article.language?.toLowerCase().startsWith(locale) &&
    article.slug &&
    (article.articleTitle || article.topic)
  );
}
```

## Headers

| Header         | Required | Description                                                                 |
| -------------- | -------- | --------------------------------------------------------------------------- |
| `x-api-key`    | Yes      | Developer API key created in `Settings > Developer`.                        |
| `Content-Type` | No       | Not needed for `GET` requests. Use `application/json` for write operations. |

## Common errors

| Status                  | Meaning                                                     |
| ----------------------- | ----------------------------------------------------------- |
| `401 Unauthorized`      | Missing, revoked, or malformed API key.                     |
| `403 Forbidden`         | The API key owner does not have access to the Blog feature. |
| `404 Not Found`         | The article id does not exist or belongs to another user.   |
| `429 Too Many Requests` | Rate limit or monthly quota exceeded.                       |

## Difference from Blog Delivery

There are two API keys involved in blog integrations:

* Developer API key: created in `Settings > Developer`, sent by your server to YALG as `x-api-key`, used for `GET /v1/blog/articles`.
* Delivery API key: configured in YALG blog delivery settings, sent by YALG to your receiver endpoint as `x-api-key` when YALG pushes an article to your app.
