Misar Docs
MisarMailMisar.BlogMisarReachMisarPostMisar.DevMisar PlatformMisar IdentityMisar Posts API
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-go

Authentication

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