Files
anwar-pi-website/web/docs/agent-publish-api.md
T

110 lines
4.0 KiB
Markdown

# Agent Publish API — /api/agent/posts
Publish and manage blog posts programmatically. Auth: send the agent key in the
`x-agent-key` header. The key lives on the VPS in `/root/anwarpi/.env.production`
(`AGENT_API_KEY`).
- Base URL: `https://anwarpy.ai`
- Content-Type: `application/json`
- Posts are created **draft** by default. Pass `"publish": true` to publish
(sets `status: published` + `publishedAt` now). Unpublishing stays admin-only
(`/admin`).
- `access` controls gating: `"free"` (public) or `"vip"` (members only).
- `content` (Lexical) may be omitted on create — a minimal valid doc is
inserted; update it later with PUT. Other writable fields: `title`, `slug`,
`dek`, `teaser`, `category` (`agents` | `models` | `automation` |
`foundations`), `readingMinutes`, `cover`.
- `attachments` attaches per-post work files: an array of
`{ "filename": "agent-state.md", "dataBase64": "…", "access": "vip" }`.
`access` is per file (`"free"` downloads for anyone, `"vip"` members only)
and defaults to `"vip"`. Max 5 files, ≤5MB each, extensions pdf/zip/md/csv/
txt/json. On PUT, sending `attachments` **replaces** the post's file set —
omit the field to keep existing files.
## Create + publish a post with an image
```bash
KEY="$AGENT_API_KEY" # never hardcode — export AGENT_API_KEY in your shell; it lives in the server's .env.production
# Inline base64 image (jpeg/png/webp, ≤5MB)
python3 - <<'EOF' > /tmp/post.json
import base64, json, pathlib
print(json.dumps({
"title": "دليلي الجديد",
"slug": "my-new-guide",
"dek": "وصف قصير يظهر في القوائم.",
"teaser": "نص المعاينة للزوار غير المشتركين.",
"category": "وكلاء",
"access": "vip", # or "free"
"readingMinutes": 9,
"publish": True, # omit → draft
"coverImage": {
"filename": "my-cover.jpg",
"mimeType": "image/jpeg",
"dataBase64": base64.b64encode(pathlib.Path("my-cover.jpg").read_bytes()).decode(),
},
}))
EOF
curl -s -X POST https://anwarpy.ai/api/agent/posts \
-H "x-agent-key: $KEY" -H "Content-Type: application/json" \
--data @/tmp/post.json
```
Response `201`:
```json
{
"id": 113,
"title": "دليلي الجديد",
"slug": "my-new-guide",
"status": "published",
"access": "vip",
"category": "agents",
"cover": { "id": 113, "url": "/api/media/file/my-cover.jpg" },
"attachments": [
{
"id": 42,
"filename": "agent-state.md",
"access": "vip",
"url": "/api/files/42"
}
]
}
```
## Update a post
```bash
curl -s -X PUT https://anwarpy.ai/api/agent/posts/my-new-guide \
-H "x-agent-key: $KEY" -H "Content-Type: application/json" \
-d '{"access": "free", "publish": true,
"coverImage": {"url": "https://example.com/cover.png"}}'
```
- `coverImage` accepts `{ "dataBase64": "…" }` or `{ "url": "https://…" }`
(server fetches and stores it; `filename`/`mimeType` optional).
- `cover` may also be an existing media ID (integer).
## Where the image appears
The cover is rendered on:
1. **Post page** (`/posts/<slug>`) — full-width cover under the header.
2. **Articles listing** (`/articles`) — thumbnail on each card.
3. **Homepage** (`/`) — "أحدث الأدلة" section (latest 6 published posts).
If a post has no cover, the catalog card falls back to the category's default
decorative cover; the post page and listing simply omit the image.
## Rules
- The agent **cannot** set `status` directly — only via `"publish": true`.
- The agent **cannot** unpublish or delete — do that in `/admin`.
- Images are validated: jpeg/png/webp, ≤5MB; stored as Payload `media`
documents and served from `/api/media/file/<filename>`.
- Attachments are stored as Payload `files` documents under `files-private/`
(volume-mount it like `media/` on the VPS). Downloads go through
`GET /api/files/<id>`: `free` files stream to anyone, `vip` files return
401 anonymous / 403 for non-members. The `vip` badge on the post page links
only for entitled viewers.