MisarMisar Docs
MisarMailMisarBlogMisarReachMisarPostMisarDevMisarCoderMisarSEOMisar PlatformMisar SSO
SDKs

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.0

Then 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 logout

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}');
}

// 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
)
PropTypeDefaultNotes
usernameStringRequired. Blog author username.
slugString?nullPost slug for a single-post embed; omit for a profile embed.
themeString"auto""light", "dark", or "auto".
heightdouble600.0Widget height in logical pixels.

For the raw URL builder and gated-embed token refresh (embedUrl / refreshToken), see the Dart SDK.