Skip to main content
Base URL: http://localhost:8002 (local worker — the only supported deployment today). Status: Alpha. Surface area is broad but not contractually stable across releases. Last updated: 2026-05-23.

Jump to a group

Authentication

OAuth 2.1 Client Credentials grant. poindexter setup provisions the initial CLI client.

Tasks

Create, list, approve, and reject content tasks. The lifecycle is pending → in_progress → awaiting_approval.

Posts

Public post list + search, plus authenticated update / soft-delete.

Settings

Read and update app_settings rows over the REST surface.

Overview

Reference for the REST API exposed by the Poindexter worker. All routes are under /api/* — there is no URL-based versioning.
Stability warning. The API is not yet considered stable. Route shapes change between releases, especially around task metadata. Pin to a specific commit until the first tagged release.

API Principles

  • RESTful: Standard HTTP methods and status codes
  • JSON: All requests/responses in JSON format
  • Authentication: Bearer token in Authorization header
  • Pagination: Limit/offset for list endpoints

Authentication

OAuth 2.1 Client Credentials

All protected endpoints require an OAuth-issued JWT in the Authorization header:
poindexter setup provisions an initial CLI OAuth client on first run. Mint a fresh JWT for ad-hoc curl tests with:
Or POST against the token endpoint directly:
To register additional clients (brain daemon, MCP servers, scripts, OpenClaw, Grafana), run the matching poindexter auth migrate-* helper. The legacy static-Bearer fallback was removed in Glad-Labs/poindexter#249.

Development Bypass

When development_mode is true in app_settings, the literal token dev-token is accepted as a Bearer credential:
Never enable development_mode in production. As of the 2026-04-25 rotation, development_mode=false by default — the bypass is dormant unless an operator explicitly flips the flag.

Public Endpoints (no auth required)

  • GET /api/health — system health
  • GET /api/posts — published post list
  • GET /api/posts/{slug} — single post by slug
  • GET /api/categories — category list
  • GET /api/posts/search?q=... — post search

Core Endpoints

System Health

GET /api/health

Response (200 OK):
(services/task_executor.py was deleted 2026-05-16 in the Prefect Stage 4 cutover; dispatch is now Prefect-native and there is no task_executor component in the health payload.)

Tasks

GET /api/tasks

List tasks (requires auth). Supports ?status=pending&limit=20&offset=0.

POST /api/tasks

Create a content task.
The task enters the pipeline automatically: pending → in_progress → awaiting_approval (or rejected if QA fails).

POST /api/tasks/{task_id}/approve

Approve a task for publishing. Publishes immediately unless publish_at is set.

POST /api/tasks/{task_id}/reject

Reject a task with feedback.

Posts

GET /api/posts

List published posts. Public (no auth).

GET /api/posts/{slug}

Get a single post by slug. Public.

GET /api/posts/search?q={query}

Search posts by title/content. Public.

Settings

GET /api/settings

List all app_settings (requires auth).

PUT /api/settings/{key}

Update a setting.

Other Endpoints

GroupMethod + PathAuthPurpose
CategoriesGET /api/categoriespublicList all content categories with post counts
CategoriesGET /api/categories/{slug}publicSingle category metadata + posts
PostsGET /api/postspublicPaginated post list (status, category, limit, offset query)
PostsGET /api/posts/{slug}publicSingle published post by slug
PostsGET /api/posts/search?q=...publicFull-text + pgvector similarity search
PostsGET /api/posts/preview/{preview_token}tokenPreview a pre-publish post using a signed one-shot token
PostsPATCH /api/posts/{post_id}bearerUpdate post metadata (title, tags, SEO fields)
PostsDELETE /api/posts/{post_id}bearerSoft delete (archive) a post
TagsGET /api/tagspublicList all tags with post counts
MemoryGET /api/memory/search?q=...bearerSemantic search via pgvector (top-k cosine similarity)
MemoryGET /api/memory/statsbearerEmbedding counts by source_table / writer
PipelineGET /api/pipeline/eventsbearerLive event stream (recent task transitions, with pagination)
PipelineGET /api/pipeline/events/task/{task_id}bearerEvent history for a single task
AnalyticsGET /api/analytics/viewsbearerPage view rollups (day, post_id, geo if configured)
ExportPOST /api/export/rebuildbearerTrigger static JSON + RSS rebuild to R2 / configured storage
MediaGET /images/generated/{filename}publicServe a generated image-gen / Pexels image
MediaGET /episodespublicList all podcast episodes
MediaGET /episodes/{post_id}.mp3publicStream a podcast audio episode
MediaGET /episodes/{post_id}.mp4publicStream a podcast video episode
MediaPOST /generate/{post_id}bearerRegenerate audio/video for a specific post
SubscribersGET /subscribers/countpublicTotal opted-in newsletter subscribers
SubscribersPOST /subscribepublicDouble opt-in newsletter signup (captcha recommended)
SubscribersPOST /unsubscribepublicOne-click unsubscribe by token
FeedGET /feed.xmlpublicRSS 2.0 feed of published posts
WebhooksPOST /alertmanagersignedPrometheus Alertmanager webhook receiver (routes to Discord)
FrontendPOST /revalidate-cachebearerTrigger Next.js ISR cache revalidation after publish
FrontendGET /preview/{preview_token}tokenServer-rendered preview HTML for vision-gate QA
Everything prefixed /api is the REST surface. Media routes (/episodes/*, /images/generated/*) and the RSS feed sit at the server root without the /api prefix to match classic web expectations.

Webhook security

POST /alertmanager verifies the Alertmanager webhook signature (HMAC-SHA256, shared secret in app_settings.alertmanager_webhook_secret). Invalid signatures are rejected with 401. Preview tokens (/api/posts/preview/{token}, /preview/{token}) are single-purpose signed tokens issued by the worker at post creation. They expire after 24 hours and can only be used to read — never to modify state.

Error Responses

Common status codes: 400 validation, 401 missing/bad token, 404 not found, 500 server error.