Everything you need to integrate BlogSaas into your application.
All API requests require an API key passed via the X-API-Key header. Create API keys from the dashboard.
curl -H "X-API-Key: YOUR_API_KEY" \ https://api-blogsaas.figoodle.com/api/v1/posts
https://api-blogsaas.figoodle.comFetch and display blog posts on your site.
/api/v1/postsReturns a paginated list of published blog posts. Pinned posts appear first, then ordered by publish date (newest first).
Query Parameters
| Param | Type | Default | Description |
|---|---|---|---|
| page | integer | 1 | Page number |
| pageSize | integer | 9 | Posts per page |
| category | string | — | Filter by category name |
Example Request
curl -H "X-API-Key: YOUR_API_KEY" \ "https://api-blogsaas.figoodle.com/api/v1/posts?page=1&pageSize=9&category=Tech"
Response
{
"items": [
{
"id": "uuid",
"title": "Post Title",
"slug": "post-title",
"excerpt": "Short summary...",
"cover_image_url": "https://api-host/uploads/image.webp",
"category": "Tech",
"author_name": "John",
"is_pinned": false,
"published_at": "2026-03-14T00:00:00Z",
"cta_url": "https://...",
"cta_text": "Try It Free",
"tags": ["tag1", "tag2"]
}
],
"total_count": 42,
"page": 1,
"page_size": 9
}/api/v1/posts/:slugReturns a single published blog post by its slug, including full markdown content. Each request increments the view count.
URL Parameters
| Param | Type | Description |
|---|---|---|
| slug | string | The post's URL slug (from list endpoint) |
Example Request
curl -H "X-API-Key: YOUR_API_KEY" \ "https://api-blogsaas.figoodle.com/api/v1/posts/my-blog-post-slug"
Response
{
"id": "uuid",
"title": "Post Title",
"slug": "post-title",
"content": "Full markdown content...",
"excerpt": "Short summary...",
"cover_image_url": "https://api-host/uploads/image.webp",
"meta_title": "SEO Title",
"meta_description": "SEO description...",
"keywords": "seo, keywords",
"category": "Tech",
"author_name": "John",
"is_pinned": false,
"cta_url": "https://...",
"cta_text": "Try It Free",
"published_at": "2026-03-14T00:00:00Z",
"view_count": 123,
"tags": ["tag1", "tag2"],
"image_urls": ["https://api-host/uploads/img1.webp"]
}Use page and pageSize query parameters. The response includes total_count so you can calculate total pages:
const totalPages = Math.ceil(data.total_count / data.page_size);
| Field | Type | Description |
|---|---|---|
| id | string (uuid) | Unique post identifier |
| title | string | Post title |
| slug | string | URL-safe slug |
| content | string | Full markdown content (single post only) |
| excerpt | string? | Short summary (max 500 chars) |
| cover_image_url | string? | Cover image URL |
| meta_title | string? | SEO title (single post only) |
| meta_description | string? | SEO description (single post only) |
| keywords | string? | Comma-separated SEO keywords (single post only) |
| category | string? | Post category |
| author_name | string? | Author display name |
| is_pinned | boolean | Whether post is pinned to top |
| cta_url | string? | Call-to-action link URL |
| cta_text | string? | Call-to-action button text |
| published_at | string (ISO 8601) | Publish date |
| view_count | integer | Total views (single post only) |
| tags | string[] | Array of tag strings |
| image_urls | string[] | Embedded image URLs (single post only) |
Blog content is returned as Markdown. To render it properly on your site, you need a markdown library and typography CSS.
1. Install Dependencies
# React / Next.js / Vite npm install marked # For Tailwind CSS typography (proper spacing, fonts, lists) npm install @tailwindcss/typography
2. Configure Tailwind
// Tailwind v4 (globals.css)
@import "tailwindcss";
@plugin "@tailwindcss/typography";
// Tailwind v3 (tailwind.config.js)
import typography from '@tailwindcss/typography'
export default {
plugins: [typography],
}3. Render Content
import { marked } from 'marked';
marked.setOptions({ breaks: true, gfm: true });
// In your component:
<div
className="prose prose-lg max-w-none"
dangerouslySetInnerHTML={{
__html: marked.parse(post.content)
}}
/>That's it! The prose class from Tailwind Typography handles all heading sizes, list spacing, paragraph margins, image styling, link colors, and code blocks automatically.
Manage your subscriber list programmatically.
/api/v1/subscribersAdd a subscriber. If the email already exists and was unsubscribed, it reactivates them.
Request Body
{
"email": "user@example.com",
"name": "Jane Doe",
"source": "api",
"tags": "customers,trial"
}Example
curl -X POST -H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","name":"Jane"}' \
https://api-blogsaas.figoodle.com/api/v1/subscribers/api/v1/subscribers/batchImport up to 1000 subscribers at once. Returns counts of created, updated, and skipped. Existing subscribers are updated (name, metadata, tags). Unsubscribed users are skipped.
Request Body
{
"subscribers": [
{ "email": "a@example.com", "name": "Alice", "tags": "Active-user" },
{ "email": "b@example.com", "name": "Bob", "tags": "Active-user,Premium" }
]
}Response
{ "created": 2, "updated": 0, "skipped": 0, "errors": [] }Groups & Tags
The tags field is a comma-separated string of group names (e.g. "Active-user,Premium"). Groups are auto-created if they don't exist yet — no need to create groups manually before importing. Tags set on a subscriber replace any previously assigned tags (not merged). When sending newsletters, you can target subscribers by group name.
/api/v1/subscribersList subscribers with optional filtering by status, tag, or search term.
Query Parameters
| Param | Description |
|---|---|
| status | Filter: active, unsubscribed, deleted |
| tag | Filter by tag name |
| search | Search by email or name |
| page, pageSize | Pagination (default 1, 50) |
/api/v1/subscribers/:id|DELETE/api/v1/subscribers/:idUpdate a subscriber's name, metadata, or tags. DELETE soft-deletes the subscriber.
PUT Body
{ "name": "Updated Name", "tags": "paid,enterprise" }/api/v1/newslettersCreate a newsletter draft. Use content_json for block-based content.
Request Body
{
"subject": "March Product Update",
"preview_text": "New features this month",
"content_json": "[{\"type\":\"text\",\"content\":\"Hello!\"}]",
"target_tags": "customers",
"show_logo": true,
"show_footer": true
}/api/v1/newslettersList newsletters. Filter by status (draft, scheduled, queued, sending, sent, failed).
/api/v1/newsletters/:id/sendQueue a draft newsletter for immediate sending. Requires Resend API key configured in site settings.
Example
curl -X POST -H "X-API-Key: YOUR_API_KEY" \ https://api-blogsaas.figoodle.com/api/v1/newsletters/NEWSLETTER_ID/send
Response
{ "message": "Newsletter queued for sending" }/api/v1/newsletters/:id/scheduleSchedule a draft newsletter for a future date.
Request Body
{ "scheduled_at": "2026-04-01T09:00:00Z" }/api/v1/newsletters/:id/reportGet send report: total recipients, sent count, failed count, and rendered HTML.
Response
{
"id": "uuid",
"subject": "March Product Update",
"status": "sent",
"total_recipients": 142,
"sent_count": 140,
"failed_count": 2,
"sent_at": "2026-03-15T10:00:00Z"
}Drop-in blog widget for any website.
Drop this snippet into any HTML page to embed your blog with zero setup. The widget handles pagination, theming, and post rendering automatically.
<div id="blog"></div>
<script src="https://api-blogsaas.figoodle.com/embed.js"></script>
<script>
BlogSaas.init({
apiKey: 'YOUR_API_KEY',
container: '#blog',
theme: 'auto', // 'light' | 'dark' | 'auto'
layout: 'grid', // 'grid' | 'list'
postsPerPage: 9,
});
</script>| Status | Meaning |
|---|---|
| 401 | Missing or invalid API key |
| 404 | Resource not found |
| 409 | Conflict (e.g. editing a sent newsletter) |
| 500 | Server error |
{ "error": "API key required" }