C# SDK
Publish articles, manage series, and run AI tools with the MisarBlog C# SDK, plus post-embed helpers.
The C# SDK ships a full async client for the developer API (https://api.misar.io/blog/v1) plus the iframe embed helpers, in the Misar.Blog NuGet package (v1.0.0).
Installation
dotnet add package Misar.BlogAPI 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). Every method is async and returns a JsonElement. Retryable statuses (429, 500, 502, 503, 504) are retried with exponential back-off. The client is IDisposable.
using MisarBlog;
using var blog = new MisarBlogClient("mbk_YOUR_KEY");
// Override the base URL if needed
using var staging = new MisarBlogClient(
"mbk_YOUR_KEY",
baseUrl: "https://api.misar.io/blog/v1");Articles
// List your articles
JsonElement result = await blog.Articles_ListAsync(status: "published", limit: 20);
foreach (var a in result.GetProperty("articles").EnumerateArray())
Console.WriteLine($"{a.GetProperty("title")} {a.GetProperty("url")}");
// Get one by slug (or UUID)
JsonElement article = await blog.Articles_GetAsync("my-first-article");
// Publish
JsonElement created = await blog.Articles_PublishAsync(new
{
title = "Getting Started with the MisarBlog API",
body_markdown = "## Introduction\n\nThis guide covers…",
tags = new[] { "csharp", "api" },
cover_image_url = "https://example.com/cover.jpg",
visibility = "public",
});
// Save a draft, then update / publish it
JsonElement draft = await blog.Articles_CreateDraftAsync(new
{
title = "Work in progress", body_markdown = "## Soon…",
});
await blog.Articles_UpdateAsync(draft.GetProperty("slug").GetString()!, new { publish = true });Other resources
await blog.Series_ListAsync();
await blog.Series_CreateAsync("A Series", description: "Optional");
await blog.Ai_TitlesAsync(action: "seo", prompt: "best AI writing tools 2026");
await blog.Ai_CompleteAsync("Tighten this intro: …", system: "You are an editor.", maxTokens: 300);
await blog.Images_GenerateAsync("A minimalist cover", size: "1792x1024");
await blog.SearchAsync(q: "react", type: "articles", sort: "newest");
await blog.Recommendations_GetAsync(articleId, limit: 5);
await blog.Analytics_GetAsync(days: 30);
await blog.Profile_GetAsync(); // GET /me
await blog.Plan_GetAsync();
await blog.Trial_StatusAsync();
await blog.Reactions_GetAsync(articleId);
await blog.Reactions_AddAsync(articleId, "like"); // "like" | "clap" | "bookmark"
await blog.Reactions_RemoveAsync(articleId, "like");Methods
| Group | Methods |
|---|---|
| Articles | Articles_ListAsync · Articles_GetAsync · Articles_PublishAsync · Articles_UpdateAsync · Articles_CreateDraftAsync |
| Series | Series_ListAsync · Series_CreateAsync · Series_AddArticleAsync |
| AI | Ai_TitlesAsync · Ai_CompleteAsync |
| Images | Images_GenerateAsync · Images_UploadAsync |
| Search / Recommendations | SearchAsync · Recommendations_GetAsync |
| Analytics | Analytics_GetAsync |
| Account | Profile_GetAsync (GET /me) · Plan_GetAsync · Trial_StatusAsync · Trial_StartAsync |
| Reactions | Reactions_GetAsync · Reactions_AddAsync · Reactions_RemoveAsync |
| Upsell | Upsell_FunnelAsync — platform-admin only |
Error handling
try
{
await blog.Articles_GetAsync("missing-slug");
}
catch (MisarBlogException ex)
{
Console.Error.WriteLine($"{ex.Status}: {ex.Message}"); // + RequiredScope / GrantedScopes on 403
}MisarBlogNetworkException (a MisarBlogException with Status == 0) is thrown when the request never completes or retries are exhausted.
Embed helpers
The no-key iframe helpers are static:
using MisarBlog;
// Profile embed
var url = Embed.Url("johndoe");
// Single-post embed with a theme
var postUrl = Embed.Url("johndoe", slug: "my-first-post", theme: "dark");
// For gated (paywalled) embeds, refresh the session token
TokenResult result = await Auth.RefreshToken("current-session-token");
Console.WriteLine($"{result.Token} {result.ExpiresAt}");static string Embed.Url(string username, string? slug = null, string theme = "auto") returns a public embed-viewer URL. static Task<TokenResult> Auth.RefreshToken(string token, string baseUrl = "https://misar.blog", HttpClient? client = null) returns a TokenResult(Token, ExpiresAt); it throws on a non-success status.