REST API Reference
Access your ChatFeatured articles programmatically. List articles by status, fetch individual articles, publish from review, and receive webhook notifications.
Authentication
All API requests require authentication via an API key. You can create an API key from the Integrations > REST API page in your dashboard.
Pass your API key using either method:
# Bearer token (recommended)
curl https://chatfeatured.com/api/v1/articles \
-H "Authorization: Bearer cf_your_api_key"
# x-api-key header
curl https://chatfeatured.com/api/v1/articles \
-H "x-api-key: cf_your_api_key"Keep your API key secret. Do not expose it in client-side code or public repositories. If compromised, you can regenerate it from the dashboard.
Base URL
https://chatfeatured.com/api/v1Endpoints
/api/v1/articlesList articles for your brand, filtered by status.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
status | string | No | Filter by status: "published" (default), "review", or "scheduled" |
limit | number | No | Number of articles to return (default: 20, max: 100) |
offset | number | No | Number of articles to skip for pagination (default: 0) |
Example
curl "https://chatfeatured.com/api/v1/articles?status=review&limit=10" \
-H "Authorization: Bearer cf_your_api_key"Response
{
"data": [
{
"id": "abc123",
"title": "How to Optimize for AI Search",
"slug": "how-to-optimize-for-ai-search",
"status": "review",
"excerpt": "A comprehensive guide...",
"metaDescription": "Learn how to optimize...",
"content": "<p>HTML content...</p>",
"featuredImageUrl": "https://example.com/image.jpg",
"scheduledAt": null,
"publishedAt": null,
"priority": "medium",
"wordCount": 1200,
"readingTimeMinutes": 5,
"createdAt": "2026-03-19T10:00:00.000Z",
"updatedAt": "2026-03-20T12:00:00.000Z",
"metadata": {
"articleType": "guide",
"description": "A comprehensive guide to AI search optimization"
}
}
],
"pagination": {
"total": 42,
"limit": 10,
"offset": 0,
"hasMore": true
}
}/api/v1/articles/:idOrSlugFetch a single article by ID or slug.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
idOrSlug | string | Yes | The article ID or slug |
Example
curl "https://chatfeatured.com/api/v1/articles/how-to-optimize-for-ai-search" \
-H "Authorization: Bearer cf_your_api_key"Response
{
"data": {
"id": "abc123",
"title": "How to Optimize for AI Search",
"slug": "how-to-optimize-for-ai-search",
"status": "published",
"excerpt": "A comprehensive guide...",
"metaDescription": "Learn how to optimize...",
"content": "<p>Full HTML content of the article...</p>",
"featuredImageUrl": "https://example.com/image.jpg",
"scheduledAt": null,
"publishedAt": "2026-03-20T12:00:00.000Z",
"priority": "medium",
"wordCount": 1200,
"readingTimeMinutes": 5,
"createdAt": "2026-03-19T10:00:00.000Z",
"updatedAt": "2026-03-20T12:00:00.000Z",
"metadata": {
"articleType": "guide",
"description": "A comprehensive guide to AI search optimization"
}
}
}/api/v1/articles/:idOrSlug/publishPublish an article. Only articles in "review" status can be published.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
idOrSlug | string | Yes | The article ID or slug of the article to publish |
Example
curl -X POST "https://chatfeatured.com/api/v1/articles/abc123/publish" \
-H "Authorization: Bearer cf_your_api_key"Response
{
"success": true,
"data": {
"id": "abc123",
"status": "published",
"publishedAt": "2026-03-20T12:00:00.000Z"
}
}Error Responses
All errors return a JSON object with an error field:
{
"error": "Article not found"
}| Status | Meaning |
|---|---|
401 | Missing or invalid API key |
400 | Invalid request (e.g. publishing an article not in review) |
404 | Article not found |
500 | Internal server error |
Webhooks
Configure webhooks from the Integrations > REST API page to receive real-time notifications when articles change status. You can enable notifications for two events independently.
Events
| Event | Description |
|---|---|
article.review | Fired when an article finishes generating and is ready for review |
article.published | Fired when an article is published (manually, via API, or via schedule) |
Payload
Webhooks are sent as POST requests with a JSON body:
{
"event": "article.published",
"timestamp": "2026-03-20T12:00:00.000Z",
"data": {
"id": "abc123",
"title": "How to Optimize for AI Search",
"slug": "how-to-optimize-for-ai-search",
"status": "published",
"excerpt": "A comprehensive guide...",
"metaDescription": "Learn how to optimize...",
"content": "<p>Full HTML content...</p>",
"featuredImageUrl": "https://example.com/image.jpg",
"scheduledAt": null,
"publishedAt": "2026-03-20T12:00:00.000Z",
"priority": "medium",
"wordCount": 1200,
"readingTimeMinutes": 5,
"createdAt": "2026-03-19T10:00:00.000Z",
"updatedAt": "2026-03-20T12:00:00.000Z",
"metadata": {
"articleType": "guide",
"description": "A comprehensive guide to AI search optimization"
}
}
}Signature Verification
If you configure a signing secret, every webhook request includes an X-Webhook-Signature header containing an HMAC-SHA256 hex digest of the request body signed with your secret.
// Node.js example
import { createHmac } from "crypto";
function verifyWebhook(body: string, signature: string, secret: string): boolean {
const expected = createHmac("sha256", secret)
.update(body)
.digest("hex");
return signature === expected;
}
// In your webhook handler
app.post("/webhooks/chatfeatured", (req, res) => {
const signature = req.headers["x-webhook-signature"];
const body = JSON.stringify(req.body);
if (!verifyWebhook(body, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).send("Invalid signature");
}
const { event, data } = req.body;
switch (event) {
case "article.review":
console.log(`Article "${data.title}" is ready for review`);
break;
case "article.published":
console.log(`Article "${data.title}" has been published`);
break;
}
res.status(200).send("OK");
});Tip: Webhooks have a 10-second timeout. If your endpoint doesn't respond in time, the delivery is considered failed. Make sure your handler responds quickly — process the payload asynchronously if needed.