Skip to content

Review API

Manage post review and approval workflows.

Overview

The Review API provides endpoints for approving and rejecting posts. FenLiu supports both manual review via the web interface and programmatic review via this API.

Review Workflow

  1. Fetch: posts are collected from streams
  2. Classify: AI text and image checks run (see AI Classification)
  3. Review: human or API decision (approve/reject)
  4. Export: approved posts moved to the Curated Queue

Authentication

All Review API endpoints require API key authentication via X-API-Key header:

curl -H "X-API-Key: your-api-key" \
  http://localhost:8000/api/v1/posts/42

See Authentication Guide for details.

Endpoints

PATCH /api/v1/posts/{id}

Update post review status (approve or reject).

Request

curl -X PATCH \
  -H "X-API-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "approved": true
  }' \
  http://localhost:8000/api/v1/posts/42

Request Body

{
  "approved": true
}
Field Type Required Description
approved boolean No Approval decision (true=approve, false=reject)

Response (200 OK)

{
  "id": 42,
  "post_id": "https://example.com/users/alice/statuses/123",
  "approved": true,
  "reviewed_at": "2026-03-03T12:00:00Z",
  "queue_status": "pending"
}

Error Responses

{ "detail": "Post not found" }  // 404

Review Decisions

Approve a Post

curl -X PATCH \
  -H "X-API-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "approved": true
  }' \
  http://localhost:8000/api/v1/posts/42

Reject a Post

curl -X PATCH \
  -H "X-API-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "approved": false
  }' \
  http://localhost:8000/api/v1/posts/42

Examples

Python

import httpx

api_key = "your-api-key"
base_url = "http://localhost:8000/api/v1"
headers = {"X-API-Key": api_key}

# Approve a post
async with httpx.AsyncClient() as client:
    response = await client.patch(
        f"{base_url}/posts/42",
        json={"approved": True},
        headers=headers,
    )
    result = response.json()
    print(f"Post {result['id']} approved")

# Get unreviewed posts
async with httpx.AsyncClient() as client:
    response = await client.get(
        f"{base_url}/posts?reviewed=false&limit=50",
        headers=headers,
    )
    unreviewed = response.json()["items"]
    print(f"Found {len(unreviewed)} posts to review")

cURL

export API_KEY="your-api-key"
export BASE_URL="http://localhost:8000/api/v1"

# Approve a post
curl -X PATCH "$BASE_URL/posts/42" \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"approved": true}'

# Get unreviewed posts
curl "$BASE_URL/posts?reviewed=false&limit=50" \
  -H "X-API-Key: $API_KEY"

Query Filters

Use the Posts API with filters to find posts for review:

# Unreviewed posts
curl "http://localhost:8000/api/v1/posts?reviewed=false" \
  -H "X-API-Key: your-api-key"

# Recent posts from a specific stream
curl "http://localhost:8000/api/v1/posts?stream_id=1&reviewed=false" \
  -H "X-API-Key: your-api-key"

# Approved posts (for quality control)
curl "http://localhost:8000/api/v1/posts?approved=true" \
  -H "X-API-Key: your-api-key"

Best Practices

  1. Read the Content: the AI badge is a guide, not definitive
  2. Check the Author: look at account history/patterns
  3. Verify Links: suspicious URLs are often spam
  4. Be Consistent: apply the same standards across reviews