Flutter SDK
Call the MisarBlog developer API from Flutter with secure key storage, plus the post-embed widget.
misarblog_flutter (v1.0.0) ships a full client for the developer API (https://api.misar.io/blog/v1) with secure key storage, plus the MisarBlogEmbed widget. It builds on the misarblog_sdk Dart package, so the API surface is identical to the Dart client.
Installation
dependencies:
misarblog_flutter: ^1.0.0Then run flutter pub get.
API 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.
import 'package:misarblog_flutter/misarblog_flutter.dart';
// Direct API key
final blog = MisarBlogClient(apiKey: 'mbk_YOUR_KEY');Secure key storage
On mobile, store the key in the platform keychain (iOS Keychain / Android Keystore) via SecureKeyStore, then build the client from it:
// Persist once (e.g. after the user pastes their key)
await MisarBlogClient.saveApiKey('mbk_YOUR_KEY');
// Later — load the stored key and return a ready client
final blog = await MisarBlogClient.withSecureStorage();
// Or manage the key directly
const store = SecureKeyStore();
await store.saveApiKey('mbk_YOUR_KEY');
final key = await store.loadApiKey();
await store.deleteApiKey(); // on logoutArticles
// List your articles
final result = await blog.articles.list(status: 'published', limit: 20);
for (final a in result.articles) {
print('${a.title} ${a.url}');
}
// Publish
final created = await blog.articles.publish(
title: 'Getting Started with the MisarBlog API',
bodyMarkdown: '## Introduction\n\nThis guide covers…',
tags: ['flutter', '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.create(title: 'A Series', description: 'Optional');
await blog.ai.titles(action: 'seo', prompt: 'best AI writing tools 2026');
await blog.images.generate(prompt: 'A minimalist cover', size: '1792x1024');
await blog.articles.search(q: 'react', type: 'articles', sort: 'newest');
await blog.analytics.get(days: 30);
await blog.account.profile(); // GET /me
await blog.reactions.add(articleId: articleId, type: 'like');
blog.close();The full resource surface — articles, series, ai, images, analytics, account, reactions — matches the Dart SDK resources table.
Error handling
try {
await blog.articles.get('missing-slug');
} on MisarBlogException catch (err) {
print('${err.status} ${err.message}');
}MisarBlogNetworkException is thrown when the request never completes or retries are exhausted.
Embed widget
MisarBlogEmbed renders a MisarBlog post or profile embed inside a WebView — no API key required:
import 'package:misarblog_flutter/misarblog_flutter.dart';
MisarBlogEmbed(
username: 'johndoe',
slug: 'my-first-post', // optional — omit for a profile embed
theme: 'dark', // "light" | "dark" | "auto" (default "auto")
height: 600.0, // default 600.0
)| Prop | Type | Default | Notes |
|---|---|---|---|
username | String | — | Required. Blog author username. |
slug | String? | null | Post slug for a single-post embed; omit for a profile embed. |
theme | String | "auto" | "light", "dark", or "auto". |
height | double | 600.0 | Widget height in logical pixels. |
For the raw URL builder and gated-embed token refresh (embedUrl / refreshToken), see the Dart SDK.