MisarMisar Docs
MisarMailMisarBlogMisarReachMisarPostMisarDevMisarCoderMisarSEOMisar PlatformMisar SSO
SDKs

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 misarblog

Or 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

ResourceMethods
blog.articleslist · get · publish · update · create_draft · search · recommendations
blog.serieslist · create · add_article
blog.aititles · complete
blog.imagesgenerate · upload
blog.analyticsget
blog.accountprofile (GET /me) · plan · trial_status · start_trial · upsell_funnel
blog.reactionsget · 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
end

MisarBlog::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.