# REST API & TypeScript SDK

Pull your published blog content into any app - a headless frontend, a WordPress or Shopify integration, a static-site build, or your own server. Read access to articles, categories, tags, authors, search and site metadata, over a simple JSON API and a typed TypeScript SDK.

- **API-key auth** - one key per workspace, sent as a Bearer token.
- **JSON REST** - predictable envelopes, pagination and errors.
- **Typed SDK** - `@verbinge/sdk`, zero-dependency, works in Node & edge.

## Authentication

Every request needs a workspace API key. Create one in **Settings → API keys** (you'll see the secret once - copy it somewhere safe). Send it in the `Authorization` header:

```bash
curl https://verbinge.com/api/v1/articles?limit=10 \
  -H "Authorization: Bearer nvy_your_key_here"
```

Keys are secrets - use them from a server, never from browser code. To render your blog without a key, use the one-line embed instead.

## Base URL

```
https://verbinge.com/api/v1
```

## Endpoints

All endpoints return published content scoped to your workspace.

| Method | Path | Description |
|--------|------|-------------|
| GET | /articles | List published articles. Query: page, limit, category (slug), tag (slug). |
| GET | /articles/{slug} | A single published article - full HTML/Markdown, SEO and author. |
| GET | /categories | Categories defined in your workspace. |
| GET | /tags | Tags defined in your workspace. |
| GET | /authors | Authors with at least one published article. |
| GET | /authors/{id} | A single author profile (byline + bio + links). |
| GET | /search?q= | Full-text search across published articles. |
| GET | /site | Blog metadata: title, description, canonical URL, logo. |
| GET | /openapi.json | Machine-readable OpenAPI 3.1 spec (no auth) for client codegen. |

## Response shape

Successful responses wrap the payload in `data`; list endpoints add `pagination`.

```json
{
  "data": [{ "id": "…", "title": "…", "slug": "…", "url": "https://acme.verbinge.com/…", "publishedAt": "2026-07-01T09:00:00.000Z" }],
  "pagination": { "page": 1, "limit": 10, "total": 24, "totalPages": 3, "hasMore": true }
}
```

## TypeScript SDK

`@verbinge/sdk` is a thin, fully-typed wrapper over the REST API. No dependencies; runs anywhere `fetch` exists.

```bash
npm i @verbinge/sdk
```

```ts
import { VerbingeClient } from '@verbinge/sdk';

// Server-side only - never expose your key in a browser bundle.
const verbinge = new VerbingeClient({ apiKey: process.env.VERBINGE_API_KEY! });

const { data, pagination } = await verbinge.articles.list({ limit: 10 });
const post = await verbinge.articles.get('onboarding-retention');
const { data: hits } = await verbinge.search({ q: 'retention' });
const site = await verbinge.site.get();
```

## Errors

Non-2xx responses use a consistent shape; the SDK throws a typed `VerbingeError` carrying `status` and `code`.

```json
{ "error": { "code": "invalid_key", "message": "Unknown or revoked API key." } }
```

Common codes: `missing_key` / `invalid_key` (401), `not_found` (404), `missing_query` (400).