Sdks
Python SDK
Install and use the official MisarBlog Python SDK to publish and manage blog content programmatically.
Installation
pip install misar-blogAuthentication
import os
from misar_blog import MisarBlogClient
client = MisarBlogClient(api_key=os.environ["MISARBLOG_API_KEY"])Generate an API key at misar.blog/dashboard/api-keys. See the Authentication guide for key scopes.
Profile
# Get your profile
me = client.me.get()
print(me.username)
print(me.display_name)
print(me.follower_count)Articles
List articles
result = client.articles.list(limit=20, offset=0)
for article in result.data:
print(article.title, article.slug)Get a single article
article = client.articles.get("my-first-article") # slug
print(article.title)
print(article.content_html)
print(article.tags)Publish an article
article = client.articles.publish(
title="Getting Started with MisarBlog API",
content="## Introduction\n\nThis guide covers...",
excerpt="A practical intro to building with the MisarBlog Python SDK.",
tags=["python", "api", "tutorial"],
featured_image_url="https://example.com/cover.jpg",
)
print("Published:", article.slug)Delete an article
client.articles.delete("my-first-article") # slugDrafts
# Save a new draft
draft = client.drafts.save(
title="Work in Progress",
content="## Introduction\n\nComing soon...",
tags=["draft", "wip"],
)
print("Draft saved:", draft.id)Series
# List all series
series_list = client.series.list()
# Create a series
new_series = client.series.create(
title="Python for Bloggers",
description="A 5-part series on building blog tools with Python.",
)
# Add an article to a series
client.series.add_article(
series_slug=new_series.slug,
article_slug="getting-started-with-misarblog-api",
)AI Tools
# Generate title suggestions from a topic
titles = client.ai.suggest_titles(topic="productivity hacks for developers")
for title in titles:
print(title)
# AI research — returns structured Markdown with citations
research = client.ai.research(topic="Next.js App Router caching strategies")
print(research.content) # Markdown stringImages
# Upload a cover image from a local file
with open("cover.jpg", "rb") as f:
result = client.images.upload(f, content_type="image/jpeg")
print("Cover URL:", result.url)
# Generate an AI cover image
result = client.images.generate(
prompt="Abstract geometric pattern in green and white",
style="digital-art",
aspect_ratio="16:9",
)
print("Generated URL:", result.url)Analytics
stats = client.analytics.get()
print(f"Total views: {stats.total_views}")
print(f"Subscribers: {stats.subscriber_count}")
print(f"Revenue (USD cents): {stats.revenue_cents}")API Keys
# List your API keys
keys = client.keys.list()
for key in keys.keys:
print(key.name, key.last_used_at)
# Create a new key
new_key = client.keys.create(name="CI/CD Key", scopes=["articles:write"])
print("New key:", new_key.key) # shown once
# Revoke a key
client.keys.revoke(key_id="key-uuid")Webhook Integration
The Python SDK can also help you build webhook receiver endpoints. See the Webhooks reference for the full payload schema.
from fastapi import FastAPI, Request
app = FastAPI()
@app.post("/webhook")
async def receive_webhook(request: Request):
event = request.headers.get("x-webhook-event")
payload = await request.json()
if event == "article.published":
print("New article:", payload["article"]["title"])
elif event == "article.updated":
print("Updated:", payload["article"]["slug"])
elif event == "article.deleted":
print("Deleted:", payload["article"]["id"])
return {"ok": True}Error Handling
from misar_blog.exceptions import MisarBlogAPIError, MisarBlogNetworkError
try:
article = client.articles.get("non-existent-slug")
except MisarBlogAPIError as e:
if e.status_code == 401:
print("Invalid or expired API key")
elif e.status_code == 404:
print("Article not found")
elif e.status_code == 429:
print(f"Rate limited. Retry after {e.retry_after}s")
else:
print(f"API error {e.status_code}: {e.message}")
except MisarBlogNetworkError as e:
print(f"Network error: {e}")Configuration
client = MisarBlogClient(
api_key="mbk_your_api_key",
base_url="https://api.misar.io/blog", # default
timeout=30, # seconds, default 30
)