Sdks
Go SDK
Install and use the official MisarBlog Go SDK to publish and manage blog content programmatically.
Installation
go get github.com/misarai/misarblog-goAuthentication
package main
import (
"context"
"os"
misarblog "github.com/misarai/misarblog-go"
)
func main() {
client := misarblog.NewClient(os.Getenv("MISARBLOG_API_KEY"))
ctx := context.Background()
_ = ctx
}
Generate an API key at misar.blog/dashboard/api-keys. See the Authentication guide for key scopes.
Profile
me, err := client.Me.Get(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Println(me.Username)
fmt.Println(me.DisplayName)
fmt.Println(me.FollowerCount)
Articles
List articles
result, err := client.Articles.List(ctx, &misarblog.ListArticlesOptions{
Limit: 20,
Offset: 0,
})
if err != nil {
log.Fatal(err)
}
for _, article := range result.Data {
fmt.Printf("%s — %s\n", article.Title, article.Slug)
}
Get a single article
article, err := client.Articles.Get(ctx, "my-first-article") // slug
if err != nil {
log.Fatal(err)
}
fmt.Println(article.Title)
fmt.Println(article.ContentHTML)
Publish an article
article, err := client.Articles.Publish(ctx, &misarblog.PublishArticleOptions{
Title: "Getting Started with MisarBlog API",
Content: "## Introduction\n\nThis guide covers...",
Excerpt: "A practical intro to building with the MisarBlog Go SDK.",
Tags: []string{"go", "api", "tutorial"},
})
if err != nil {
log.Fatal(err)
}
fmt.Println("Published:", article.Slug)
Delete an article
if err := client.Articles.Delete(ctx, "my-first-article"); err != nil {
log.Fatal(err)
}
Drafts
draft, err := client.Drafts.Save(ctx, &misarblog.SaveDraftOptions{
Title: "Work in Progress",
Content: "## Introduction\n\nComing soon...",
Tags: []string{"draft", "wip"},
})
if err != nil {
log.Fatal(err)
}
fmt.Println("Draft saved:", draft.ID)
Series
// List all series
seriesList, err := client.Series.List(ctx)
if err != nil {
log.Fatal(err)
}
for _, s := range seriesList {
fmt.Println(s.Title)
}
// Create a new series
newSeries, err := client.Series.Create(ctx, &misarblog.CreateSeriesOptions{
Title: "Go for Bloggers",
Description: "A 5-part series on building blog tools with Go.",
})
if err != nil {
log.Fatal(err)
}
// Add an article to the series
err = client.Series.AddArticle(ctx, newSeries.Slug, "getting-started-with-misarblog-api")
if err != nil {
log.Fatal(err)
}
AI Tools
// Generate title suggestions
titles, err := client.AI.SuggestTitles(ctx, "productivity hacks for developers")
if err != nil {
log.Fatal(err)
}
for _, title := range titles {
fmt.Println(title)
}
// AI research — returns Markdown with citations
research, err := client.AI.Research(ctx, "Next.js App Router caching strategies")
if err != nil {
log.Fatal(err)
}
fmt.Println(research.Content) // Markdown string
Analytics
stats, err := client.Analytics.Get(ctx, nil)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Total views: %d\n", stats.TotalViews)
fmt.Printf("Subscribers: %d\n", stats.SubscriberCount)
fmt.Printf("Revenue (USD cents): %d\n", stats.RevenueCents)
API Keys
// List API keys
keys, err := client.Keys.List(ctx)
if err != nil {
log.Fatal(err)
}
for _, k := range keys.Keys {
fmt.Println(k.Name, k.LastUsedAt)
}
// Create a new key
newKey, err := client.Keys.Create(ctx, &misarblog.CreateKeyOptions{
Name: "CI/CD Key",
Scopes: []string{"articles:write"},
})
if err != nil {
log.Fatal(err)
}
fmt.Println("New key:", newKey.Key) // shown once
// Revoke a key
if err := client.Keys.Revoke(ctx, "key-uuid"); err != nil {
log.Fatal(err)
}
Webhook Integration
Build a webhook receiver to handle MisarBlog article events. See the Webhooks reference for the full payload schema.
package main
import (
"encoding/json"
"fmt"
"net/http"
)
type WebhookPayload struct {
Event string `json:"event"`
Article struct {
ID string `json:"id"`
Slug string `json:"slug"`
Title string `json:"title"`
} `json:"article"`
Author struct {
Username string `json:"username"`
DisplayName *string `json:"display_name"`
} `json:"author"`
}
func webhookHandler(w http.ResponseWriter, r *http.Request) {
event := r.Header.Get("X-Webhook-Event")
var payload WebhookPayload
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
http.Error(w, "bad request", http.StatusBadRequest)
return
}
switch event {
case "article.published":
fmt.Println("New article:", payload.Article.Title)
case "article.updated":
fmt.Println("Updated:", payload.Article.Slug)
case "article.deleted":
fmt.Println("Deleted:", payload.Article.ID)
}
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]bool{"ok": true})
}
Error Handling
import "errors"
article, err := client.Articles.Get(ctx, "non-existent-slug")
if err != nil {
var apiErr *misarblog.APIError
if errors.As(err, &apiErr) {
switch apiErr.StatusCode {
case 401:
fmt.Println("Invalid or expired API key")
case 404:
fmt.Println("Article not found")
case 429:
fmt.Printf("Rate limited. Retry after %ds\n", apiErr.RetryAfter)
default:
fmt.Printf("API error %d: %s\n", apiErr.StatusCode, apiErr.Message)
}
} else {
fmt.Println("Network error:", err)
}
}