api
api
blogs
content

Blogs API

Manage your blog posts programmatically with the CrossPostr Blogs API

6 min read
Updated 7/9/2025

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:

  1. Go to your blog settings in the dashboard
  2. Enable "Allow API Access"
  3. 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

Was this page helpful?