Dart SDK
Publish articles, manage series, and run AI tools with the MisarBlog Dart SDK, plus post-embed helpers.
The Dart SDK ships a full client for the developer API (https://api.misar.io/blog/v1) plus the iframe embed helpers, in the misarblog_sdk package (v1.0.0). For Flutter apps, the misarblog_flutter package adds secure key storage and an embed widget on top of this client.
Installation
Add to pubspec.yaml, then run dart pub get:
dependencies:
misarblog_sdk: ^1.0.0API Client
MisarBlogClient 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. Call close() when you are done.
import 'package:misarblog_sdk/misarblog.dart';
final blog = MisarBlogClient(apiKey: 'mbk_YOUR_KEY');
// Override the base URL if needed
final staging = MisarBlogClient(
apiKey: 'mbk_YOUR_KEY',
baseUrl: 'https://api.misar.io/blog/v1',
);Articles
// List your articles
final result = await blog.articles.list(status: 'published', limit: 20);
for (final a in result.articles) {
print('${a.title} ${a.url}');
}
// Get one by slug (or UUID)
final article = await blog.articles.get('my-first-article');
// Publish
final created = await blog.articles.publish(
title: 'Getting Started with the MisarBlog API',
bodyMarkdown: '## Introduction\n\nThis guide covers…',
tags: ['dart', 'api'],
coverImageUrl: 'https://example.com/cover.jpg',
visibility: 'public',
);
// Save a draft, then update / publish it
final draft = await blog.articles.createDraft(title: 'Work in progress', bodyMarkdown: '## Soon…');
await blog.articles.update(draft.slug, publish: true);Other resources
await blog.series.list();
await blog.series.create(title: 'A Series', description: 'Optional');
await blog.ai.titles(action: 'seo', prompt: 'best AI writing tools 2026');
await blog.ai.complete(prompt: 'Tighten this intro: …', system: 'You are an editor.', maxTokens: 300);
await blog.images.generate(prompt: 'A minimalist cover', size: '1792x1024');
await blog.articles.search(q: 'react', type: 'articles', sort: 'newest');
await blog.articles.recommendations(articleId: articleId, limit: 5);
await blog.analytics.get(days: 30);
await blog.account.profile(); // GET /me
await blog.account.plan();
await blog.account.trialStatus();
await blog.reactions.get(articleId);
await blog.reactions.add(articleId: articleId, type: 'like'); // "like" | "clap" | "bookmark"
await blog.reactions.remove(articleId: articleId, type: 'like');
blog.close();Resources
| Resource | Methods |
|---|---|
blog.articles | list · get · publish · update · createDraft · search · recommendations |
blog.series | list · create · addArticle |
blog.ai | titles · complete |
blog.images | generate · upload |
blog.analytics | get |
blog.account | profile (GET /me) · plan · trialStatus · startTrial · upsellFunnel |
blog.reactions | get · add · remove |
Error handling
try {
await blog.articles.get('missing-slug');
} on MisarBlogError catch (err) {
print('${err.status} ${err.message}'); // err.body carries the parsed response
}MisarBlogNetworkError is thrown when the request never completes or retries are exhausted.
Embed helpers
The no-key iframe helpers are top-level functions:
import 'package:misarblog_sdk/misarblog.dart';
// Profile embed
final url = embedUrl('johndoe');
// Single-post embed with a theme
final postUrl = embedUrl('johndoe', slug: 'my-first-post', theme: 'dark');
// For gated (paywalled) embeds, refresh the session token
final result = await refreshToken('current-session-token');
print('${result.token} ${result.expiresAt}');embedUrl(String username, {String? slug, String theme = "auto"}) -> String returns a public embed-viewer URL. Future<TokenResult> refreshToken(String token, {String baseUrl = "https://misar.blog"}) returns a TokenResult(token, expiresAt), or throws on a non-200 response.
For an in-app embed widget, see the Flutter SDK.