Misar.BlogApi Reference
GraphQL API
Query and mutate MisarBlog content using the GraphQL API — articles, profiles, series, and analytics.
Overview
MisarBlog exposes a GraphQL API at api.misar.io/blog/graphql for flexible content queries. GraphQL lets you fetch only the fields you need and combine multiple queries in a single request.
Both GET (for queries) and POST (for queries and mutations) are supported. Use POST with a JSON body for production clients.
Authentication
All requests require a valid API key in the Authorization header:
Authorization: Bearer mbk_your_api_key
Generate keys at misar.blog/dashboard/api-keys.
Endpoint
POST api.misar.io/blog/graphql
Content-Type: application/json
Authorization: Bearer mbk_your_api_key
Schema
Types
type Article {
id: ID!
slug: String!
title: String!
excerpt: String
contentHtml: String
status: String! # "draft" | "published"
visibility: String! # "public" | "subscribers" | "paid" | "private"
tags: [String!]
publishedAt: String
updatedAt: String
viewCount: Int
canonicalUrl: String
featuredImageUrl: String
author: Profile
series: Series
}
type Profile {
id: ID!
username: String!
displayName: String
bio: String
avatarUrl: String
articleCount: Int
subscriberCount: Int
profileUrl: String
}
type Series {
id: ID!
slug: String!
title: String!
description: String
articleCount: Int
}
type Analytics {
totalViews: Int!
uniqueVisitors: Int!
subscriberCount: Int!
totalRevenueCents: Int!
period: String!
}
type ArticleConnection {
nodes: [Article!]!
totalCount: Int!
hasNextPage: Boolean!
}
Queries
me — Get your profile
query {
me {
id
username
displayName
bio
avatarUrl
articleCount
subscriberCount
profileUrl
}
}
article — Get a single article
query {
article(slug: "my-first-post") {
id
title
excerpt
contentHtml
status
visibility
tags
publishedAt
viewCount
canonicalUrl
}
}
articles — List articles
query {
articles(limit: 20, offset: 0, status: "published", tag: "productivity") {
totalCount
hasNextPage
nodes {
id
slug
title
excerpt
tags
publishedAt
viewCount
}
}
}
| Argument | Type | Default | Description |
|---|---|---|---|
limit | Int | 20 | Results per page (max 100) |
offset | Int | 0 | Pagination offset |
status | String | — | Filter by "draft" or "published" |
tag | String | — | Filter by tag slug |
series — List series
query {
series {
id
slug
title
description
articleCount
}
}
Pass slug to get a specific series:
query {
series(slug: "my-series") {
id
title
articleCount
}
}
analytics — Get analytics
query {
analytics(days: 30) {
totalViews
subscriberCount
totalRevenueCents
period
}
}
| Argument | Type | Default | Description |
|---|---|---|---|
days | Int | 30 | Lookback window in days |
Mutations
createDraft — Create a new draft
mutation {
createDraft(
title: "My New Article"
content: "<p>Hello world</p>"
tags: ["writing", "productivity"]
) {
id
slug
title
status
}
}
updateArticle — Update an article
mutation {
updateArticle(
slug: "my-new-article"
title: "My Updated Title"
excerpt: "A better summary"
tags: ["writing", "tips"]
) {
id
slug
title
updatedAt
}
}
publishDraft — Publish a draft
mutation {
publishDraft(slug: "my-new-article") {
id
slug
status
publishedAt
}
}
deleteArticle — Delete an article
mutation {
deleteArticle(slug: "my-new-article")
}
Returns true on success, false on failure.
TypeScript client example
async function queryGraphQL<T>(query: string, variables?: Record<string, unknown>): Promise<T> {
const res = await fetch("https://api.misar.io/blog/graphql", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer mbk_your_api_key",
},
body: JSON.stringify({ query, variables }),
});
const { data, errors } = await res.json();
if (errors?.length) throw new Error(errors[0].message);
return data;
}
// Usage
const { articles } = await queryGraphQL<{ articles: { nodes: { title: string }[] } }>(`
query ListArticles($limit: Int) {
articles(limit: $limit, status: "published") {
nodes { title slug }
totalCount
}
}
`, { limit: 10 });Errors
GraphQL errors are returned in the errors array alongside data:
{
"errors": [
{
"message": "Unauthorized",
"locations": [{ "line": 2, "column": 3 }],
"path": ["me"]
}
],
"data": { "me": null }
}| Message | Cause |
|---|---|
Unauthorized | Missing or invalid API key |
insert error / update error | Database constraint violation |