---
title: "Get a blog post"
method: GET
path: "/v1/blog/{slug}"
tags: ["Content"]
---

# Get a blog post

`GET /v1/blog/{slug}`

## Request

- Base URL: `https://api.gunspec.io`
- URL: `https://api.gunspec.io/v1/blog/{slug}`
- Auth: one of:
  - none
  - API key in header `X-API-Key`
  - HTTP bearer

Returns a single published blog post, including its full body.

No API key required.

## Path parameters

- `slug` string, required

## Response `200`

Get a blog post

- object
  - `success` boolean, required: Always true on a successful response. Every error carries `false` and an `error` object instead.
  - `data` object, required: The response payload.
    - `post` BlogPost: A published post. Both endpoints serve the stored row; `body` is markdown.
      - `id` string, required: Opaque post id. A string, not a number: posts are keyed like every other authored record here.
      - `slug` string, required: URL-safe slug, and what `/v1/blog/{slug}` addresses.
      - `title` string, required: Post headline.
      - `summary` string, nullable: One-line description, for a card or a feed. Null where the author wrote none.
      - `body` string, nullable: The post itself, as markdown.
      - `heroImage` string, nullable: Path of the hero image on the assets CDN, or null. Prefix it with the assets host to fetch.
      - `heroAlt` string, nullable: What the hero image shows, as alt text. Null where the post has no hero or none was written.
      - `category` string, nullable: Editorial category, e.g. `guides`. Null where the post has none.
      - `status` string, required: Always `published` on these endpoints: a draft is not served publicly.
      - `postedAt` string, nullable: When the post was published, which is what the list orders by. Null on a post never given a date.
      - `createdAt` string, required: When the post was first written, `YYYY-MM-DD HH:MM:SS` in UTC. Not the publication date: `postedAt` is.
      - `updatedAt` string, required: When the post was last edited, `YYYY-MM-DD HH:MM:SS` in UTC.
      - `author` object, nullable: Who wrote the post: the display name on the account that created it, never its address. Null when that account has no display name, and the post is then attributed to the publisher.
        - `name` string, required: The author's display name, as set on their GunSpec account.
        - `handle` string, required: URL segment of the author's page on the blog, made from their display name.
        - `avatarStyle` string, required: Which avatar style the author chose on their account.
        - `avatarSeed` string, required: Seed the avatar is drawn from. Stable per author, and not their account id.

## Other responses

- `400`: Validation error
- `404`: Resource not found
- `429`: A limit was reached. `RATE_LIMITED` is the per-minute limit: wait `Retry-After` seconds (a minute) and retry. `DAILY_CAP_EXCEEDED` is the plan's daily limit, per key: nothing will be served until the counters return to zero at midnight UTC. `MONTHLY_CAP_EXCEEDED` is the plan's monthly allowance, for the whole account: nothing will be served until midnight UTC on the first of next month, or until the plan changes. For both, `Retry-After` is the seconds until then and `error.resetsAt` says when as an instant. Calls made after a refusal are refused too and do not spend the month, and a free key that keeps calling is paused, so stop at the first one and resume at the reset.
- `500`: Internal server error

---

[API](https://skmtc.dev/gunspec/apis/gunspec-io-api.md) · [All operations](https://skmtc.dev/gunspec/apis/gunspec-io-api/llms.txt) · [OpenAPI document](https://skmtc.dev/gunspec/apis/gunspec-io-api/revisions/f2e974d8b05c?raw)
