Blogs API
Manage your blog posts programmatically with the CrossPostr Blogs API
Blogs API
The Blogs API allows you to programmatically manage your blog posts on CrossPostr. You can list, create, update, and delete blog posts through this API.
Base Endpoint
GET /api/v1/blogs
Authentication
All Blogs API endpoints require authentication. See the Authentication guide for details.
Required permission: read:blogs
List Blogs
Retrieve a paginated list of your blog posts that have API access enabled.
Request
GET /api/v1/blogs
Query Parameters
| Parameter | Type | Default | Description |
| --------- | ------- | ------- | ---------------------------------- |
| page
| integer | 1 | Page number for pagination |
| limit
| integer | 10 | Number of blogs per page (max: 50) |
Headers
x-api-key: your_api_key_here
Content-Type: application/json
Example Request
curl -H "x-api-key: cp_your_api_key_here" \ "https://crosspostr.ai/api/v1/blogs?page=1&limit=10"
Example Response
{ "success": true, "data": { "blogs": [ { "id": "blog_123", "title": "Getting Started with Next.js", "blogSlug": "getting-started-nextjs", "description": "A comprehensive guide to building modern web applications with Next.js", "isPublic": true, "allowApiAccess": true, "seoTitle": "Next.js Tutorial - Complete Guide", "seoDescription": "Learn Next.js from scratch with this comprehensive tutorial", "createdAt": "2025-07-01T10:00:00Z", "updatedAt": "2025-07-08T15:30:00Z" }, { "id": "blog_124", "title": "React Hooks Best Practices", "blogSlug": "react-hooks-best-practices", "description": "Essential patterns and best practices for using React Hooks effectively", "isPublic": true, "allowApiAccess": true, "seoTitle": "React Hooks Best Practices Guide", "seoDescription": "Master React Hooks with these proven patterns and best practices", "createdAt": "2025-06-28T14:20:00Z", "updatedAt": "2025-07-05T09:15:00Z" } ], "pagination": { "page": 1, "limit": 10, "total": 25, "totalPages": 3, "hasNext": true, "hasPrev": false } } }
Blog Object
Fields
| Field | Type | Description |
| ---------------- | ------- | ------------------------------------------- |
| id
| string | Unique identifier for the blog post |
| title
| string | The blog post title |
| blogSlug
| string | URL-friendly slug for the blog post |
| description
| string | Brief description of the blog post |
| isPublic
| boolean | Whether the blog post is publicly visible |
| allowApiAccess
| boolean | Whether API access is enabled for this blog |
| seoTitle
| string | SEO-optimized title |
| seoDescription
| string | SEO-optimized description |
| createdAt
| string | ISO 8601 timestamp of creation |
| updatedAt
| string | ISO 8601 timestamp of last update |
API Access Control
Only blogs with allowApiAccess: true
are returned by the API. To enable API access for a blog:
- Go to your blog settings in the dashboard
- Enable "Allow API Access"
- Save your changes
Filtering and Search
By Public Status
Get only public blogs:
curl -H "x-api-key: cp_your_api_key_here" \ "https://crosspostr.ai/api/v1/blogs?public=true"
By Date Range
Get blogs created within a date range:
curl -H "x-api-key: cp_your_api_key_here" \ "https://crosspostr.ai/api/v1/blogs?from=2025-07-01&to=2025-07-31"
Error Responses
Unauthorized (401)
{ "success": false, "error": { "code": "UNAUTHORIZED", "message": "API key required" } }
Forbidden (403)
{ "success": false, "error": { "code": "INSUFFICIENT_PERMISSIONS", "message": "Your API key does not have read:blogs permission" } }
Rate Limit Exceeded (429)
{ "success": false, "error": { "code": "RATE_LIMIT_EXCEEDED", "message": "Too many requests. Please try again later." } }
Code Examples
JavaScript/Node.js
async function getBlogs(apiKey, page = 1, limit = 10) { try { const response = await fetch( `https://crosspostr.ai/api/v1/blogs?page=${page}&limit=${limit}`, { headers: { 'x-api-key': apiKey, 'Content-Type': 'application/json', }, } ); if (!response.ok) { const error = await response.json(); throw new Error(`API Error: ${error.error.message}`); } const data = await response.json(); return data.data.blogs; } catch (error) { console.error('Error fetching blogs:', error); throw error; } } // Usage const apiKey = process.env.CROSSPOSTR_API_KEY; const blogs = await getBlogs(apiKey, 1, 20); console.log(`Found ${blogs.length} blogs`);
Python
import requests import os def get_blogs(api_key, page=1, limit=10): url = f"https://crosspostr.ai/api/v1/blogs" headers = { 'x-api-key': api_key, 'Content-Type': 'application/json' } params = { 'page': page, 'limit': limit } try: response = requests.get(url, headers=headers, params=params) response.raise_for_status() data = response.json() return data['data']['blogs'] except requests.exceptions.RequestException as e: print(f"Error fetching blogs: {e}") raise # Usage api_key = os.getenv('CROSSPOSTR_API_KEY') blogs = get_blogs(api_key, page=1, limit=20) print(f"Found {len(blogs)} blogs")
PHP
<?php function getBlogs($apiKey, $page = 1, $limit = 10) { $url = "https://crosspostr.ai/api/v1/blogs?" . http_build_query([ 'page' => $page, 'limit' => $limit ]); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'x-api-key: ' . $apiKey, 'Content-Type: application/json' ]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); if ($httpCode !== 200) { throw new Exception("API Error: " . $response); } $data = json_decode($response, true); curl_close($ch); return $data['data']['blogs']; } // Usage $apiKey = $_ENV['CROSSPOSTR_API_KEY']; $blogs = getBlogs($apiKey, 1, 20); echo "Found " . count($blogs) . " blogs\n"; ?>
Go
package main import ( "encoding/json" "fmt" "io" "net/http" "os" ) type BlogsResponse struct { Success bool `json:"success"` Data struct { Blogs []Blog `json:"blogs"` Pagination struct { Page int `json:"page"` Limit int `json:"limit"` Total int `json:"total"` TotalPages int `json:"totalPages"` HasNext bool `json:"hasNext"` HasPrev bool `json:"hasPrev"` } `json:"pagination"` } `json:"data"` } type Blog struct { ID string `json:"id"` Title string `json:"title"` BlogSlug string `json:"blogSlug"` Description string `json:"description"` IsPublic bool `json:"isPublic"` AllowApiAccess bool `json:"allowApiAccess"` SEOTitle string `json:"seoTitle"` SEODescription string `json:"seoDescription"` CreatedAt string `json:"createdAt"` UpdatedAt string `json:"updatedAt"` } func getBlogs(apiKey string, page, limit int) ([]Blog, error) { url := fmt.Sprintf("https://crosspostr.ai/api/v1/blogs?page=%d&limit=%d", page, limit) req, err := http.NewRequest("GET", url, nil) if err != nil { return nil, err } req.Header.Set("x-api-key", apiKey) req.Header.Set("Content-Type", "application/json") client := &http.Client{} resp, err := client.Do(req) if err != nil { return nil, err } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return nil, err } var response BlogsResponse err = json.Unmarshal(body, &response) if err != nil { return nil, err } return response.Data.Blogs, nil } func main() { apiKey := os.Getenv("CROSSPOSTR_API_KEY") blogs, err := getBlogs(apiKey, 1, 20) if err != nil { fmt.Printf("Error: %v\n", err) return } fmt.Printf("Found %d blogs\n", len(blogs)) }
Best Practices
1. Pagination
Always use pagination for large datasets:
async function getAllBlogs(apiKey) { const allBlogs = []; let page = 1; let hasMore = true; while (hasMore) { const response = await fetch( `https://crosspostr.ai/api/v1/blogs?page=${page}&limit=50`, { headers: { 'x-api-key': apiKey }, } ); const data = await response.json(); allBlogs.push(...data.data.blogs); hasMore = data.data.pagination.hasNext; page++; } return allBlogs; }
2. Error Handling
Always handle potential errors:
try { const blogs = await getBlogs(apiKey); // Process blogs } catch (error) { if (error.message.includes('RATE_LIMIT_EXCEEDED')) { // Wait and retry await new Promise(resolve => setTimeout(resolve, 60000)); // Retry request } else { console.error('Unexpected error:', error); } }
3. Caching
Cache blog data to reduce API calls:
const cache = new Map(); const CACHE_TTL = 5 * 60 * 1000; // 5 minutes async function getCachedBlogs(apiKey) { const cacheKey = 'blogs'; const cached = cache.get(cacheKey); if (cached && Date.now() - cached.timestamp < CACHE_TTL) { return cached.data; } const blogs = await getBlogs(apiKey); cache.set(cacheKey, { data: blogs, timestamp: Date.now(), }); return blogs; }
Rate Limiting
The Blogs API is subject to rate limiting:
- Free: 100 requests/hour
- Pro: 1,000 requests/hour
- Enterprise: 10,000 requests/hour
Rate limit information is included in response headers:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 995
X-RateLimit-Reset: 1625097600