---
title: "Your first published article"
description: "Create a key, create an article, publish it, read it back."
canonical: "https://writavo.com/docs/quickstart"
last-updated: "2026-08-19"
---

# Your first published article

Five requests: check your key, create a draft, publish it, read it back, then read it the way a browser would.

## Get a key

Keys are created in the dashboard, not through the API.

1. **Open Settings, then API keys** You need the `api_keys.manage` permission. Owners and admins have it by default.
2. **Create a secret key** Choose **Secret** with the scopes `articles:read`, `articles:write` and `meta:read`. A key can never do more than the person who created it.
3. **Copy it now** It is shown once. Only a hash is stored, so a lost key can be rotated but not recovered.
4. **Create a publishable key too** Choose **Publishable** with `articles:read`. Step 5 uses it. This kind is safe in a browser.

> Never put a secret key in a browser bundle, a mobile app or a repository. If one leaks, revoke it on the same screen; it stops working on the next request.

## Set your shell up

Export these once and every request below can be pasted as it is.

shell:

```
export WRITAVO_SECRET_KEY="wv_sk_your_secret_key"
export WRITAVO_PUBLISHABLE_KEY="wv_pub_your_publishable_key"
export WRITAVO_BASE="https://api.writavo.com/v1"
```

The snippets show the key inline. Substitute your real key, or replace it with `$WRITAVO_SECRET_KEY`.

## The five requests

**1. Check your key works** (returns 200)

```bash

curl https://api.writavo.com/v1/ping \
  -H "Authorization: Bearer wv_sk_EXAMPLE0000000000000000000000000000"

```

The cheapest authenticated call there is. It tells you the kind of key you presented and the scopes it carries.

**2. Create a draft** (returns 201)

```bash

curl -X POST https://api.writavo.com/v1/articles \
  -H "Authorization: Bearer wv_sk_EXAMPLE0000000000000000000000000000" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: b6f4b0e2-0000-4000-8000-0000000000aa" \
  -d '{
  "title": "How to choose a headless CMS",
  "slug": "how-to-choose-a-headless-cms",
  "excerpt": "A practical framework for picking a headless CMS without regretting it.",
  "content": "## Start with your delivery model\n\nThe first question is not which CMS. It is where the HTML is rendered."
}'

```

This always creates a draft. There is no request field that can make it public.

**3. Publish it** (returns 200)

```bash

curl -X POST https://api.writavo.com/v1/articles/3f1b0c7a-0000-4000-8000-000000000001/publish \
  -H "Authorization: Bearer wv_sk_EXAMPLE0000000000000000000000000000"

```

Publishing is free. It makes no external call, so it spends no credits and is unaffected by your spend cap.

**4. Read it back** (returns 200)

```bash

curl https://api.writavo.com/v1/articles/3f1b0c7a-0000-4000-8000-000000000001?fields=id,status,title,slug,published_at \
  -H "Authorization: Bearer wv_sk_EXAMPLE0000000000000000000000000000"

```

A sparse fieldset. `fields` is an allow list, so there is no way to ask for everything.

**5. Read it with a publishable key** (returns 200)

```bash

curl https://api.writavo.com/v1/articles?limit=5&fields=id,title,slug,published_at \
  -H "Authorization: Bearer wv_pub_EXAMPLE000000000000000000000000000"

```

A publishable key is safe in a browser. It sees only published articles, and it cannot write.

## What just happened

- **Your key chose the Site.** Nothing you send can point it at another one.
- **Nothing went public by accident.** `POST /articles` made a draft; only the publish call put it on the web.
- **Publishing cost nothing.** Only `POST /pipeline/runs` spends credits.
- **The publishable key saw only published content.** The secret key would also see drafts.

## Next

- [Authentication and keys](/docs/authentication): scopes, rotation and revocation.
- [The content lifecycle](/docs/content-lifecycle): scheduling and statuses.
- [Webhooks](/docs/webhooks): get told when content changes.
- [The API reference](/docs/api): every operation.
