--- title: "DevPlace REST: SEO Diagnostics, DeepSearch and AI Usage Analyzer" description: "Background-job endpoints for the three public developer tools: queueing a run, polling status, reading the report, and the progress websockets - all addressed by unguessable capability URLs." language: null framework: null category: api_design tags: - devplace - api - http-api - background-jobs - websocket - capability-url - seo - research - rest - polling keywords: - devplace POST /tools/seo/run job uid - devplace deepsearch api report endpoint - devplace ai usage analyzer api badge - devplace tool job status websocket url - capability url unguessable job uid last_updated: 2026-08-12 difficulty: intermediate version: "DevPlace (devplace.net), documented 2026-08" related: - conventions_and_errors.md - README.md - authentication.md search_priority: normal status: published --- # DevPlace REST: SEO Diagnostics, DeepSearch and AI Usage Analyzer Two public developer tools that run as background jobs. **SEO Diagnostics** audits a URL or sitemap with a headless browser and runs a broad battery of technical, on-page, structured-data, Core Web Vitals, accessibility and AI-readiness checks. **DeepSearch** is a multi-agent deep web researcher that crawls and indexes sources, then synthesises a cited report with confidence scoring and gap analysis, plus a grounded chat over the results. **AI Usage Analyzer** classifies a git repository or website as AI slop, sophisticated AI-assisted work or genuine human work, and publishes a persistent report with an embeddable authenticity badge. Every endpoint follows the shared [Conventions & Errors](conventions_and_errors.md). These are **capability URLs**: the job `uid` is an unguessable identifier, so anyone holding it can read the status and report. ## `POST /tools/seo/run` - Queue an SEO audit Start a background SEO audit of a URL or sitemap. Returns the job uid plus status and websocket URLs. *Minimal role:* Public **Parameters** | Name | In | Type | Required | Description | |------|----|------|----------|-------------| | `url` | form | string | yes | Page URL or sitemap.xml URL to audit. | | `mode` | form | enum | no | 'url' (single page) or 'sitemap' (crawl). Allowed: url, sitemap. | | `max_pages` | form | integer | no | Max pages to crawl in sitemap mode (1-50). | **Sample response** ```json { "uid": "SEO_JOB_UID", "status_url": "/tools/seo/SEO_JOB_UID", "ws_url": "/tools/seo/SEO_JOB_UID/ws" } ``` ## `GET /tools/seo/{uid}` - SEO audit status Poll an SEO audit. Once done, score, grade and report_url are populated. *Minimal role:* Public **Parameters** | Name | In | Type | Required | Description | |------|----|------|----------|-------------| | `uid` | path | string | yes | SEO job uid returned when the audit was queued. | **Sample response** ```json { "uid": "SEO_JOB_UID", "kind": "seo", "status": "done", "target": "https://example.com", "mode": "url", "ws_url": "/tools/seo/SEO_JOB_UID/ws", "report_url": "/tools/seo/SEO_JOB_UID/report", "score": 82, "grade": "B", "page_count": 1, "error": null, "created_at": "2026-06-14T10:00:00+00:00", "completed_at": "2026-06-14T10:00:18+00:00" } ``` ## `GET /tools/seo/{uid}/report` - SEO audit report Full categorised report: overall score, per-category subscores, and every check with its recommendation. Negotiates HTML or JSON. *Minimal role:* Public **Parameters** | Name | In | Type | Required | Description | |------|----|------|----------|-------------| | `uid` | path | string | yes | SEO job uid of a finished audit. | **Sample response** ```json { "uid": "SEO_JOB_UID", "status": "done", "target": "https://example.com", "score": 82, "grade": "B", "page_count": 1, "counts": { "pass": 40, "warn": 8, "fail": 3, "info": 5, "skip": 0 }, "categories": { "crawlability": { "score": 90, "pass": 9, "warn": 1, "fail": 0 } }, "pages": [ { "url": "https://example.com", "status": 200, "score": 82, "grade": "B" } ], "checks": [ { "id": "meta.title_present", "category": "meta", "title": "Title tag", "status": "pass", "severity": "high", "value": "Example Domain", "recommendation": "", "url": "https://example.com" } ], "site": { "robots": { "status": 200 }, "sitemap": { "status": 200, "url_count": 12 } }, "generated_at": "2026-06-14T10:00:18+00:00" } ``` ## `GET /tools/seo/{uid}/screenshot/{index}` - SEO audit page screenshot Stream the rendered screenshot (image/png) captured for the audited page at the given zero-based index. *Minimal role:* Public **Parameters** | Name | In | Type | Required | Description | |------|----|------|----------|-------------| | `uid` | path | string | yes | SEO job uid of a finished audit. | | `index` | path | integer | yes | Zero-based index of the audited page. | ## `GET /tools/seo-meta/{target_type}/{target_uid}` - Generated SEO metadata for a content item Read the clean, AI-generated SEO title, description and keywords for a published post, project, gist, news article or issue. Returns a plain-content default with status 'pending' until the AI value is ready. *Minimal role:* Public **Parameters** | Name | In | Type | Required | Description | |------|----|------|----------|-------------| | `target_type` | path | enum | yes | Content type. Allowed: post, project, gist, news, issue. | | `target_uid` | path | string | yes | The content uid (or issue number). | **Sample response** ```json { "uid": "SEO_META_UID", "target_type": "post", "target_uid": "CONTENT_UID", "seo_title": "Building a fast SQLite social network", "seo_description": "How DevPlace keeps SQLite synchronous and still serves a developer social network fast, with WAL, mmap and batch query helpers.", "seo_keywords": "sqlite, fastapi, social network, performance, wal", "status": "ready", "source": "ai", "generated_at": "2026-06-14T10:00:18+00:00" } ``` ## `POST /tools/deepsearch/run` - Queue a DeepSearch research job Start a multi-agent deep web research job. Returns the job uid plus status and websocket URLs. Connect ws_url for live progress frames. *Minimal role:* Public **Parameters** | Name | In | Type | Required | Description | |------|----|------|----------|-------------| | `query` | form | string | yes | The research question to investigate. | | `depth` | form | integer | no | Research depth (1-4). | | `max_pages` | form | integer | no | Maximum sources to crawl (1-30). | **Sample response** ```json { "uid": "DEEPSEARCH_JOB_UID", "status_url": "/tools/deepsearch/DEEPSEARCH_JOB_UID", "ws_url": "/tools/deepsearch/DEEPSEARCH_JOB_UID/ws", "progress_frames_note": "The ws_url stream emits newline-delimited JSON frames; the set is append-only and the first frame carries version:1. Each frame has a type: phase (phase, index, total, label), stage, substep (planning angles), queries, candidates, rsearch, progress (done, total, url), page_loaded (source, render, elapsed_ms, done, total), page_cached, page_skipped (reason), page_duplicate, embed_batch (batch, total_batches, backend, done, total), embed_done (backend, chunk_count), agent (agent, status start|done, elapsed_ms, tokens_in, tokens_out), report_ready, done (session_url), failed (message)." } ``` ## `GET /tools/deepsearch/{uid}` - DeepSearch status Poll a DeepSearch job. Once done, score, confidence and session_url are populated. *Minimal role:* Public **Parameters** | Name | In | Type | Required | Description | |------|----|------|----------|-------------| | `uid` | path | string | yes | DeepSearch job uid returned when the run was queued. | **Sample response** ```json { "uid": "DEEPSEARCH_JOB_UID", "kind": "deepsearch", "status": "done", "query": "history of the transistor", "depth": 2, "max_pages": 12, "ws_url": "/tools/deepsearch/DEEPSEARCH_JOB_UID/ws", "chat_ws_url": "/tools/deepsearch/DEEPSEARCH_JOB_UID/chat", "session_url": "/tools/deepsearch/DEEPSEARCH_JOB_UID/session", "score": 78, "confidence": 0.72, "source_diversity": 0.64, "page_count": 11, "chunk_count": 240, "error": null, "created_at": "2026-06-14T10:00:00+00:00", "completed_at": "2026-06-14T10:01:40+00:00" } ``` ## `GET /tools/deepsearch/{uid}/session` - DeepSearch report Full cited research report: summary, findings, sources and metrics. Negotiates HTML or JSON. *Minimal role:* Public **Parameters** | Name | In | Type | Required | Description | |------|----|------|----------|-------------| | `uid` | path | string | yes | DeepSearch job uid of a finished run. | **Sample response** ```json { "uid": "DEEPSEARCH_JOB_UID", "status": "done", "query": "history of the transistor", "score": 78, "confidence": 0.72, "source_diversity": 0.64, "page_count": 11, "chunk_count": 240, "summary": "The transistor was invented at Bell Labs in 1947...", "findings": [ { "title": "Invention", "detail": "...", "confidence": 0.8, "citations": [ 1 ] } ], "sources": [ { "url": "https://example.com", "title": "Example", "source": "httpx" } ], "chat_ws_url": "/tools/deepsearch/DEEPSEARCH_JOB_UID/chat", "export_md_url": "/tools/deepsearch/DEEPSEARCH_JOB_UID/export.md", "export_json_url": "/tools/deepsearch/DEEPSEARCH_JOB_UID/export.json", "export_pdf_url": "/tools/deepsearch/DEEPSEARCH_JOB_UID/export.pdf" } ``` ## `POST /tools/isslop/run` - Queue a AI usage analysis Start a background authenticity analysis of a git repository or website. Returns the job uid plus status, events and report URLs. *Minimal role:* Public **Parameters** | Name | In | Type | Required | Description | |------|----|------|----------|-------------| | `url` | form | string | yes | Repository (http/git/ssh) or website URL to classify. | **Sample response** ```json { "uid": "ISSLOP_UID", "status_url": "/tools/isslop/ISSLOP_UID", "events_url": "/tools/isslop/ISSLOP_UID/events", "report_url": "/tools/isslop/ISSLOP_UID/report", "topic": "public.isslop.ISSLOP_UID" } ``` ## `GET /tools/isslop/list` - My AI usage analyses List the caller's analyses, newest first. Member history is account-bound; guest history is session-bound and claimed by the account on first signed-in call. *Minimal role:* Public **Parameters** | Name | In | Type | Required | Description | |------|----|------|----------|-------------| | `limit` | query | integer | no | Maximum analyses to return (1-200). | **Sample response** ```json { "analyses": [ { "uid": "ISSLOP_UID", "status": "completed", "source_url": "https://github.com/owner/repository", "source_kind": "git", "grade": "B", "human_percent": 71.4, "ai_percent": 28.6, "category": "human-clean", "report_url": "/tools/isslop/ISSLOP_UID/report", "badge_url": "/tools/isslop/ISSLOP_UID/badge.svg" } ] } ``` ## `GET /tools/isslop/{uid}` - AI usage analysis status Poll an analysis. Once completed, grade, category and the human/AI split are populated. *Minimal role:* Public **Parameters** | Name | In | Type | Required | Description | |------|----|------|----------|-------------| | `uid` | path | string | yes | Analysis uid returned when the run was queued. | **Sample response** ```json { "uid": "ISSLOP_UID", "status": "completed", "source_url": "https://github.com/owner/repository", "source_kind": "git", "grade": "B", "slop_score": 31.2, "origin_score": 28.0, "quality_deficit_score": 22.5, "human_percent": 71.4, "ai_percent": 28.6, "category": "human-clean", "confidence": "medium", "files_total": 120, "files_analyzed": 96, "report_url": "/tools/isslop/ISSLOP_UID/report", "badge_url": "/tools/isslop/ISSLOP_UID/badge.svg", "events_url": "/tools/isslop/ISSLOP_UID/events", "topic": "public.isslop.ISSLOP_UID" } ``` ## `GET /tools/isslop/{uid}/events` - AI usage analysis event trail The persisted, ordered event trail of an analysis. Use ?after=SEQ to poll incrementally; live frames also stream on the pub/sub topic. *Minimal role:* Public **Parameters** | Name | In | Type | Required | Description | |------|----|------|----------|-------------| | `uid` | path | string | yes | Analysis uid. | | `after` | query | integer | no | Return only events with a sequence number greater than this. | | `limit` | query | integer | no | Maximum events to return (1-5000). | **Sample response** ```json { "uid": "ISSLOP_UID", "status": "running", "events": [ { "seq": 1, "kind": "stage", "message": "Resolving source type", "data": { "stage": "resolve" }, "created_at": "2026-06-14T10:00:00+00:00" } ] } ``` ## `GET /tools/isslop/{uid}/report` - AI usage analysis report Full report: verdict, markdown body, per-file results, image review and badge embeds. Negotiates HTML or JSON. *Minimal role:* Public **Parameters** | Name | In | Type | Required | Description | |------|----|------|----------|-------------| | `uid` | path | string | yes | Analysis uid of a finished run. | **Sample response** ```json { "uid": "ISSLOP_UID", "status": "completed", "source_url": "https://github.com/owner/repository", "grade": "B", "human_percent": 71.4, "ai_percent": 28.6, "category": "human-clean", "markdown": "# Verdict...", "generator_model": "molodetz", "badge": { "badge_url": "https://devplace.example/tools/isslop/ISSLOP_UID/badge.svg", "report_url": "https://devplace.example/tools/isslop/ISSLOP_UID/report", "markdown": "[![authenticity human score](...)](...)", "html": "" }, "files": [ { "path": "src/main.py", "language": "python", "lines": 120, "origin_score": 35.0, "quality_deficit_score": 18.0, "category": "human-clean", "signals": [] } ], "images": [ { "path": "assets/hero.png", "ai_probability": 84.0, "grade": "F", "verdict": "ai-generated", "image_kind": "illustration", "tells": [ "waxy skin" ], "description": "...", "thumb_url": "/tools/isslop/ISSLOP_UID/media/0f3a9c2d1b4e5a67.webp" } ] } ``` ## `GET /tools/isslop/{uid}/report.md` - Download report markdown Download the full report as a markdown file. *Minimal role:* Public **Parameters** | Name | In | Type | Required | Description | |------|----|------|----------|-------------| | `uid` | path | string | yes | Analysis uid of a finished run. | ## `GET /tools/isslop/{uid}/source` - Annotated source of a flagged file The persisted source of a signal-bearing file with its signals, rendered with line numbers and highlighted findings (HTML) or as JSON. Linked from the report's file table, signal chips and prose. *Minimal role:* Public **Parameters** | Name | In | Type | Required | Description | |------|----|------|----------|-------------| | `uid` | path | string | yes | Analysis uid. | | `path` | query | string | yes | Workspace-relative file path from the report. | | `line` | query | integer | no | Line to focus and highlight. | **Sample response** ```json { "uid": "ISSLOP_UID", "path": "src/libs/Env.ts", "language": "typescript", "category": "human-clean", "origin_score": 24.0, "quality_deficit_score": 34.9, "source": "import { createEnv } from '@t3-oss/env-nextjs';...", "truncated": false, "signals": [ { "code": "PUBLIC_ENV_SECRET", "title": "Secret exposed via public env variable", "severity": "strong", "line": 12 } ] } ``` ## `GET /tools/isslop/{uid}/media/{name}` - Reviewed image thumbnail Aspect-preserving WebP thumbnail of a reviewed image, persisted as evidence. The name comes from the report's images[].thumb_url. *Minimal role:* Public **Parameters** | Name | In | Type | Required | Description | |------|----|------|----------|-------------| | `uid` | path | string | yes | Analysis uid. | | `name` | path | string | yes | Thumbnail file name from the report. | ## `GET /tools/isslop/{uid}/badge.svg` - Authenticity badge Embeddable SVG badge showing the human score and authenticity grade, linking to the report. *Minimal role:* Public **Parameters** | Name | In | Type | Required | Description | |------|----|------|----------|-------------| | `uid` | path | string | yes | Analysis uid. |