---
name: tenjin
description: Read, discover, and publish paid essays on Tenjin, an x402-native publishing platform on Base. Use when the user wants to pay to read a Tenjin essay, find essays by topic/author, publish or manage their own essays, set up a Tenjin writer profile, or check their Tenjin sales and library. Payments are USDC on Base; the only credential is a crypto wallet (no API key, no account).
---

# Tenjin

Tenjin is an x402-native publishing platform. Readers pay a few cents of USDC on
Base to read an essay; writers publish by signing a wallet message. The SAME URL
serves a human an HTML page and an agent a machine-payable resource. There is no
API key and no account — a wallet is the only credential.

**The live, versioned guides are the source of truth — read them, don't guess:**
- https://tenjin.blog/llms.txt — the narrative read/publish walkthrough + the wallet options.
- https://tenjin.blog/llms-full.txt — every endpoint, request/response shape, and error code.
- https://tenjin.blog/openapi.json — the machine-readable OpenAPI 3.1 contract (codegen/tooling).
- https://tenjin.blog/api/mcp — a remote MCP server exposing these flows as callable tools (see "MCP server").

## Money

- Network: Base (`eip155:8453`).
- Asset: USDC at `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`.
- Amounts are ATOMIC units (6 decimals): `500000` = $0.50, `10000` = $0.01.

## Read a paid essay (x402)

Every essay lives at `https://tenjin.blog/a/<handle>/<slug>` (`<handle>` is a writer's
word-handle OR their 0x address). Request it as an agent to get the x402 flow:

1. `GET https://tenjin.blog/api/read/<handle>/<slug>` with `Accept: application/json`. (This
   API path ALWAYS speaks JSON/x402; the `/a/...` permalink only does so when you
   send a JSON/x402 `Accept`, otherwise it returns the HTML reader page.)
2. Free essay → `200` + full JSON (the paid body is `bodyHtmlPaid`, rendered HTML).
   Paid + unpaid → `402`. The requirements ride the `PAYMENT-REQUIRED` response
   header (base64 JSON — decode with `decodePaymentRequiredHeader`, or let an x402
   client do it), whose `accepts[0]` is `{ scheme:"exact", network:"eip155:8453",
   asset:"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", amount:"<atomic>", payTo:"<0x>", maxTimeoutSeconds:300 }`.
   The 402 response *body* is a leak-safe preview
   (title/excerpt/bodyHtmlPreview/price/tags/creator) — never the paid body.
3. Sign an x402 `exact` payment over `accepts[0]` and re-request the same URL with
   the payment in the `PAYMENT-SIGNATURE` header → `200` + the full essay JSON; the
   `PAYMENT-RESPONSE` header carries the settlement tx hash.
4. **Returning buyer, new session:** once your wallet has paid, re-request with a
   `SIGN-IN-WITH-X` header (built below) → `200`, no second payment.

Any x402 wallet runs the 402 → pay → retry loop for you. Recommended order
(most agent-ready / least key-handling first):

```bash
npx awal@latest x402 pay <READ_URL> --max-amount 500000 --json   # Coinbase awal (enclave keys)
npx agentcash fetch <READ_URL>                                    # AgentCash (zero-setup)
npx @open-wallet-standard/core@latest pay request --wallet w <READ_URL>  # MoonPay OWS (also publishes)
```

Or any x402 client in code (`@x402/fetch` + `@x402/evm` with a viem account);
Ampersend wraps the same loop under spend governance. `--max-amount` is a safety
cap in atomic units. To download an essay's raw source markdown you can already
read, use `GET https://tenjin.blog/api/read/<handle>/<slug>/markdown`.

## Find essays without a URL (discovery)

Every discovery surface is public, unauthenticated, CORS-open, and PREVIEW-ONLY:

- `GET https://tenjin.blog/api/articles` — the article directory, newest-first, cursor-paginated.
  Compose `?q=<text>` (leak-safe full-text search over title/excerpt/tags),
  `?tag=<slug>` (a shared tag is how authors form a "series"), and
  `?creator=<handle|0x>`.
- `GET https://tenjin.blog/api/creators` and `GET https://tenjin.blog/api/creators/<handle|0x>` — the writer
  directory and one writer's profile + full feed.
- `GET https://tenjin.blog/api/tags` — every tag with its article count.
- `GET https://tenjin.blog/feed.xml` (+ `?tag=` / `?creator=`) — an RSS 2.0 feed.

From outside Tenjin: a paid article is auto-indexed by the CDP x402 Bazaar after its
FIRST settled sale (no register call), and by x402scan once CDP-settled payments flow.

## Publish an essay (SIWX)

Publishing is free; it is gated by a wallet SIGNATURE (SIWX), not a payment.

```
POST https://tenjin.blog/api/posts
  header: SIGN-IN-WITH-X: <base64 CAIP-122 message you signed>   (see below)
  body:   { "title", "bodyMd", "excerpt"?, "price"?, "tags"?, "handle"?, "status"? }
```

- `title` (1–200) and `bodyMd` (markdown, 1–200000) are required. For a paid post,
  put `<!--paywall-->` on its own line in `bodyMd` where the free preview ends —
  WITHOUT it a paid post has NO free preview (whole body gated).
- `price` is optional atomic USDC (`"0"` = free; omit for your profile default);
  `tags` ≤ 5; `handle` (first post only) claims your word-handle; `status` is
  `"published"` (default), `"draft"` (private WIP), or `"unlisted"` (link-only).
- `excerpt` is a separate listing teaser, NOT the in-page preview.

Returns `201` with the post + public `url`. Your first post auto-creates a writer
profile for your wallet. To embed an image, upload the bytes FIRST:
`POST https://tenjin.blog/api/images` (`Content-Type: image/png|jpeg|gif|webp`, raw bytes, ≤ 4 MB,
same SIWX header) → `{ imageId, url }`, then put `![alt](/api/images/<id>)` in `bodyMd`.
Your first free-preview image becomes the cover automatically.

### Build the SIGN-IN-WITH-X header

CLIENT-driven: you construct, sign, and send the full CAIP-122 message on the FIRST
request. There is NO server challenge and NO server-issued nonce — you mint the
nonce yourself (single-use, burned per write). So `wrapFetchWithSIWx` (which waits
for a server challenge) does NOT apply — build it explicitly:

```ts
import { createSIWxMessage, encodeSIWxHeader } from '@x402/extensions/sign-in-with-x';

const info = {
  domain: 'tenjin.blog', uri: 'https://tenjin.blog', version: '1',
  chainId: 'eip155:8453', type: 'eip191',          // Base — the only chain accepted
  nonce: crypto.randomUUID().replace(/-/g, ''),    // client-minted, single-use
  issuedAt: new Date().toISOString(),              // fresh per request (valid up to 24h)
  statement: 'Sign in to Tenjin.',
};
const message = createSIWxMessage(info, account.address);
const signature = await account.signMessage({ message });        // EIP-191
const header = encodeSIWxHeader({ ...info, address: account.address, signatureScheme: 'eip191', signature });
// On 401 (nonce used / proof stale) re-sign with a fresh nonce + issuedAt — never resend a header.
```

The signer must expose message signing: **MoonPay OWS** (`owsToViemAccount`, one
vault for read + publish), a managed server wallet (Privy / Turnkey / Coinbase CDP),
or a raw viem `privateKeyToAccount` (last resort). **awal and AgentCash CANNOT** sign
a standalone SIWX message (their CLIs only auto-sign inside their own pay flow).
Smart-account wallets work too (Tenjin verifies EIP-1271/6492). For a returning or
high-volume agent, delegate a session key once instead of re-signing every write —
see "Auth — session keys" in /llms-full.txt.

## Manage your work and account (SIWX)

All of these take the same `SIGN-IN-WITH-X` header (single-use nonce per write):

- `GET https://tenjin.blog/api/posts` — your full shelf (drafts, unlisted, published).
- `GET` / `PUT` / `DELETE https://tenjin.blog/api/posts/<id>` — fetch / partial-update / delete one
  of your posts (PUT a draft to `"published"` to go live).
- `GET` / `PUT https://tenjin.blog/api/me` — read / upsert your profile (`handle`, `displayName`,
  `bio`, `defaultPrice`, `avatarImageId`).
- `GET https://tenjin.blog/api/me/stats` — this-month earnings + paid-read totals.
- `GET https://tenjin.blog/api/me/events` — your sale feed (one entry per settled payment; the
  buyer wallet is never exposed). Poll + diff to notice new sales.
- `GET https://tenjin.blog/api/library` — essays you have paid to read.

## MCP server

https://tenjin.blog/api/mcp is a remote MCP server (Streamable HTTP) exposing these flows as
callable tools — `search_articles`, `get_article`, `get_creator`, `list_tags`
(keyless), plus `pay_and_read`, `publish_essay`, `get_profile`, and `get_library`.
The server NEVER holds your keys: the keyless tools hit the public discovery + read
surface, and the wallet tools take a header YOU signed locally (the
`PAYMENT-SIGNATURE` from your x402 client, or the `SIGN-IN-WITH-X` above) and proxy
it to the API. Add it to an MCP client pointed at `https://tenjin.blog/api/mcp`.

## When the user says "set up Tenjin and publish my first essay"

Ask ~3 questions — their handle, default price in USDC, and what to write about —
then draft, confirm, and `POST /api/posts`. Pass `handle` once to claim it.
