Publications API
Two surfaces: public reads (no auth) that any consumer renders from, and authoring (bearer token, scoped to your account) for managing your own publications and their categories. See the Publications concept for the model.
Base URL
Production: https://api.esy.com. All paths below are under /v1/publications.
Public reads — no auth
The headless contract. {slug} is the publication slug; only publications marked public and documents with status published are returned.
{
"items": [
{
"slug": "the-economics-of-desalination",
"title": "The economics of desalination",
"description": "Cost drivers, energy intensity, and where the curve bends.",
"category": "policy",
"categoryLabel": "Policy",
"categories": [{ "slug": "policy", "label": "Policy" }],
"kind": "article",
"publishedAt": "2026-06-20T14:02:11.004Z",
"tags": ["water", "energy"],
"relatedSlugs": []
}
],
"total": 1
}Authoring — bearer token
Authenticated requests are scoped to your account: you only see and manage publications you own. Manage tokens from app.esy.com.
Create a publication
{
"name": "My Field Notes",
"slug": "my-field-notes",
"acceptedKinds": ["article"],
"siteUrl": "https://example.com",
"sectionPath": "/notes",
"revalidateUrl": "https://example.com/api/revalidate"
}revalidateSecret is returned only on create and secret/rotate. Esy stores it encrypted and never returns it again — copy it into your consumer’s environment immediately. Later responses only carry hasRevalidateSecret.
{
"id": "b4c5d6e7-f8a9-4b0c-8d1e-2f3a4b5c6d7e",
"name": "My Field Notes",
"slug": "my-field-notes",
"acceptedKinds": ["article"],
"siteUrl": "https://example.com",
"sectionPath": "/notes",
"revalidateUrl": "https://example.com/api/revalidate",
"isPublic": false,
"hasRevalidateSecret": true,
"revalidateSecret": "kP3x…shown-once…9aQ",
"lastDeliveryStatus": "",
"createdAt": "2026-06-26T07:40:00.000Z"
}Categories
A publication’s own taxonomy. Authoring endpoints are owner-scoped.
Delivery health
Every webhook attempt records its outcome on the publication so you can see whether your consumer is receiving pings.
| Field | Meaning |
|---|---|
lastDeliveryStatus | “ok” or “failed”. |
lastDeliveryAt | Timestamp of the last attempt. |
lastDeliveryDetail | HTTP status or error string for the last attempt. |
All endpoints are versioned under /v1. Breaking changes land on a new path and are tracked in the changelog.