Ruby SDK
Publish articles, manage series, and run AI tools with the MisarBlog Ruby SDK, plus post-embed helpers.
The Ruby SDK ships a full client for the developer API (https://api.misar.io/blog/v1) plus the iframe embed helpers, in the misarblog gem (v1.0.0). It uses only the standard library.
Installation
gem install misarblogOr add to your Gemfile:
gem 'misarblog'API Client
MisarBlog.new authenticates with an mbk_ key (or an OAuth 2.1 access token) and defaults to https://api.misar.io/blog/v1 (the gateway strips /api). Resource methods return typed model objects. Retryable statuses (429, 500, 502, 503, 504) are retried with exponential back-off.
require 'misarblog'
blog = MisarBlog.new(api_key: 'mbk_YOUR_KEY')
# Override the base URL if needed
staging = MisarBlog.new(api_key: 'mbk_YOUR_KEY', base_url: 'https://api.misar.io/blog/v1')Articles
# List your articles
result = blog.articles.list(status: 'published', limit: 20)
result.articles.each { |a| puts "#{a.title} #{a.url}" }
# Get one by slug (or UUID)
article = blog.articles.get('my-first-article')
# Publish
created = blog.articles.publish(
title: 'Getting Started with the MisarBlog API',
body_markdown: "## Introduction\n\nThis guide covers…",
tags: %w[ruby api],
cover_image_url: 'https://example.com/cover.jpg',
visibility: 'public'
)
# Save a draft, then update / publish it
draft = blog.articles.create_draft(title: 'Work in progress', body_markdown: '## Soon…')
blog.articles.update(draft.slug, publish: true)Other resources
blog.series.list
blog.series.create(title: 'A Series', description: 'Optional')
blog.ai.titles(action: 'seo', prompt: 'best AI writing tools 2026')
blog.ai.complete(prompt: 'Tighten this intro: …', system: 'You are an editor.', max_tokens: 300)
blog.images.generate(prompt: 'A minimalist cover', size: '1792x1024')
blog.articles.search(q: 'react', type: 'articles', sort: 'newest')
blog.articles.recommendations(article_id: article_id, limit: 5)
blog.analytics.get(days: 30)
blog.account.profile # GET /me
blog.account.plan
blog.account.trial_status
blog.reactions.get(article_id: article_id)
blog.reactions.add(article_id: article_id, type: 'like') # "like" | "clap" | "bookmark"
blog.reactions.remove(article_id: article_id, type: 'like')Resources
| Resource | Methods |
|---|---|
blog.articles | list · get · publish · update · create_draft · search · recommendations |
blog.series | list · create · add_article |
blog.ai | titles · complete |
blog.images | generate · upload |
blog.analytics | get |
blog.account | profile (GET /me) · plan · trial_status · start_trial · upsell_funnel |
blog.reactions | get · add · remove |
Error handling
begin
blog.articles.get('missing-slug')
rescue MisarBlog::ApiError => err
warn "#{err.status}: #{err.message}" # err.body carries the parsed response
endMisarBlog::NetworkError (an ApiError with status == 0) is raised when the request never completes or retries are exhausted.
Embed helpers
The no-key iframe helpers are module functions:
require 'misarblog'
# Profile embed
url = MisarBlog.embed_url(username: 'johndoe')
# Single-post embed with a theme
post_url = MisarBlog.embed_url(username: 'johndoe', slug: 'my-first-post', theme: 'dark')
# For gated (paywalled) embeds, refresh the session token
result = MisarBlog.refresh_token(token: 'current-session-token')
puts result[:token], result[:expiresAt]MisarBlog.embed_url(username:, slug: nil, theme: "auto") returns a public embed-viewer URL. MisarBlog.refresh_token(token:, base_url: "https://misar.blog") returns the parsed token payload (symbol keys), or raises on a non-200 response.