Quickstart
From nothing to a published page in six steps: a token, three variables, a health check, the first read, the first page, and a page in the docs section.
The whole chain runs through the API. The only step that may involve a browser is the very first one, and even that has a browserless path.
1. Get a token
API v2 authenticates with a personal OnPress token: op_ followed by 64 hex characters. There are two ways to get one.
In the profile. Open wp-admin/profile.php on any site of the network, section “API Token”, and issue a token. It is shown once.
Through API v1, without a browser. The v1 endpoint that issues tokens accepts an Application Password (profile, section “Application Passwords”; the login is the WordPress user name, not the email). GET shows whether a token exists, POST issues one:
# is there a token? prefix and dates only, never the token itself
curl -s -u "$LOGIN:$APP_PASSWORD" "$SITE/wp-json/onpress/v1/api-token"
# issue or re-issue: the token text is shown this once
curl -s -X POST -u "$LOGIN:$APP_PASSWORD" "$SITE/wp-json/onpress/v1/api-token"
{ "token": "op_9f3c1a7e…", "prefix": "op_9f3c1a7e", "created_at": "2026-09-12 20:27:45", "last_used_at": null }
POSTrotates: there is one token per user, and issuing a new one kills the previous token immediately — for everyone using it. Check withGET, issue withPOSTonly when you mean to rotate.
2. Set three variables
Every example in this documentation uses the same variables, so a command can be copied as it is and no key ends up in a shared snippet.
export SITE="https://example.onpress.pro" # the site you work on
export BASE="https://stagepress.bond/api/v2" # API v2
export OP_TOKEN="op_9f3c1a7e…" # your token from step 1
3. Check the service
curl -s "$BASE/health"
{"ok":true,"db":true}
GET /health is the only endpoint without a token; db is a real ping of the database. Everything else needs the token and a network site.
Always name the site. Without
blog_idordomainthe request goes to blog 1, the main site of the network. The staging environment shares its database with production, so a forgotten parameter is not an error in the response — it is a successful change on a live site. The site of this documentation isblog_id233.
4. The first read
The docs sidebar of this site — a safe call that shows the token, the site choice and the response shape at once:
curl -s -H "Authorization: Bearer $OP_TOKEN" "$BASE/docs/sidebar?blog_id=233&lang=en"
{
"success": true,
"blog_id": 233,
"home_url": "https://example.onpress.pro",
"template": "templates/docs.php",
"statuses": ["publish", "draft", "private", "pending", "future"],
"include_hidden": false,
"lang": { "requested": "en", "applied": "en", "filtered_out": 12 },
"total": 25,
"hidden_total": 0,
"tree": [
{
"id": 6183,
"title": "Documentation",
"slug": "docs",
"status": "publish",
"parent": 0,
"menu_order": 0,
"hidden": false,
"children": [
{ "id": 6186, "title": "Introduction", "slug": "vvedenie", "status": "publish", "parent": 6183, "menu_order": 0, "hidden": false, "children": [], "url": "/docs/vvedenie/", "link": "https://example.onpress.pro/docs/vvedenie/" },
{ "…": "…" }
]
}
]
}
A success is always "success": true plus the endpoint’s own fields. An error is "success": false with a machine code in error — see Errors.
5. The first page
A page is markdown with frontmatter; name is the only required field. The site goes in the JSON body next to the document:
curl -s -X POST -H "Authorization: Bearer $OP_TOKEN" -H 'Content-Type: application/json' \
"$BASE/pages/markdown" -d '{
"blog_id": 233,
"markdown": "---\nname: \"Test page\"\nslug: proba-pera\nstatus: draft\n---\n\nThe first paragraph.\n"
}'
{
"success": true,
"updated": false,
"id": 6229,
"status": "draft",
"parent": 0,
"url": "/proba-pera/",
"link": null,
"preview_url": "https://example.onpress.pro/?page_id=6229",
"visible": false,
"warnings": ["page is not published (status \"draft\"), the address does not serve it"]
}
The response is the state of the page after the write, not an echo of the request. updated says whether the page was created or updated; link is the public address or null while there is none, and then preview_url comes instead; visible says whether an anonymous visitor really gets the page, with every reason for false in warnings. Publishing the same document again updates the page: it is found by slug plus lang, or by id when the frontmatter has one.
6. Put a page into the docs section
A page appears in this section when its url is inside /docs/ and it is printed in the documentation frame. Getting into the tree on the left is a separate step: an item of that sidebar is a page with the meta _wp_page_template = templates/docs.php, v2 does not write that meta, and POST /docs/sidebar/items/{ref}/show puts the page in — see Docs sidebar.
---
name: "Dashboard"
slug: "dashbord"
url: "/docs/dashbord/"
lang: "en"
status: "publish"
frame: "obolochka-dokumentaciya"
excerpt: "A web app outside WordPress for the same work the API does."
---
The dashboard is a single-page app…
This is the response to exactly that document, published while this documentation was written:
{
"success": true,
"updated": false,
"id": 6350,
"status": "publish",
"lang": "en",
"parent": 6183,
"url": "/docs/dashbord/",
"link": "https://example.onpress.pro/docs/dashbord/",
"visible": true,
"translations": { "en": 6350 },
"frame": { "id": "af33214f168f8efd", "slug": "obolochka-dokumentaciya", "meta_key": "_onpress_frame" },
"lang_changed": { "changed": true, "from": null, "to": "en" },
"printed": {
"how": "on_request",
"url": "/docs/dashbord/",
"link": "https://example.onpress.pro/docs/dashbord/",
"frame": { "id": "af33214f168f8efd", "slug": "obolochka-dokumentaciya", "renders_on_request": true }
},
"warnings": [],
"preview_url": null
}
parent was resolved from the path, frame names the frame the page is now printed in, printed says how it reaches the visitor — here on_request, because the documentation shell prints the page’s own text — and lang_changed reports the language term the page received. A template in the frontmatter would have added the warning template_ignored and nothing else: v2 has no theme templates, the look is the frame. The order of items in the tree is set separately — see Docs sidebar.
Where to go next
How the token, the site choice and rights work — Authentication. Every frontmatter field and the page tree — Pages and markdown. The look of a page — Frames, its dynamic parts — Inserts and Data. Step-by-step tasks — Recipes. When something fails — Errors.