TDQStool definition quality scoresign in →

tdqs / api

Hosted API

The same scorer the playground and the CLI use, over HTTP, with a key from your account. Lint is synchronous. Scoring creates a report that the model fills in within seconds; poll it or open its page.

Basics

Base URL https://tdqs.dev/api/v1. Requests and responses are JSON. Every request carries Authorization: Bearer tdqs_… with a key from your account; signing in is with GitHub, and keys are free. A missing or rejected key answers 401; an exhausted allowance answers 429; every error body is { "error": { "code", "message" } }.

The tool definitions are what an MCP client sees from tools/list: send that result verbatim, or a bare array of tools, optionally with a serverName.

POST /lint

The deterministic stages only. Returns immediately; spends one call.

curl https://tdqs.dev/api/v1/lint \
  -H 'Authorization: Bearer tdqs_...' \
  -H 'Content-Type: application/json' \
  -d '{ "serverName": "github-mcp", "tools": [ { "name": "list_issues", "description": "...", "inputSchema": { ... } } ] }'
200
{
  "lint": {
    "specVersion": "1.2",
    "generatedAt": "2026-09-01T12:00:00.000Z",
    "server": { "name": "github-mcp", "toolCount": 1 },
    "tools": [ { "name": "list_issues", "contextSignals": { ... }, "flags": [], "findings": [ ... ] } ],
    "shadowCandidates": [],
    "findings": [ { "tool": "list_issues", "rule": "missing-annotations", "severity": "warning", "message": "..." } ]
  }
}

POST /reports

Lints synchronously, stores the definitions, and queues the model stages. The response is the report's identity; the score arrives on it. Spends one call.

curl https://tdqs.dev/api/v1/reports \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer tdqs_...' \
  -d @tools.json
202
{
  "uid": "k3n9x2p0qa",
  "status": "queued",
  "url": "https://tdqs.dev/reports/k3n9x2p0qa",
  "apiUrl": "https://tdqs.dev/api/v1/reports/k3n9x2p0qa"
}

GET /reports/:uid

The report as it stands. score is null until status is completed; a failed report carries a failureMessage. Poll every couple of seconds; the CLI's hosted mode does exactly this. Reading spends nothing.

200
{
  "uid": "k3n9x2p0qa",
  "status": "completed",
  "requestedAt": "2026-09-01T12:00:00.000Z",
  "completedAt": "2026-09-01T12:00:09.000Z",
  "specVersion": "1.2",
  "model": "deepseek/deepseek-v4-flash-0731",
  "serverName": "github-mcp",
  "toolCount": 10,
  "lint": { ... },
  "score": {
    "specVersion": "1.2",
    "model": "deepseek/deepseek-v4-flash-0731",
    "server": { "name": "github-mcp", "toolCount": 10 },
    "tools": [ { "name": "list_issues", "tdqs": 4.3, "tier": "A", "scores": { ... }, "justifications": { ... }, "flags": [], "smells": [] } ],
    "serverScore": { "overallScore": 4.1, "overallTier": "A", "coherenceScore": 4.8, "descriptionQualityScore": 3.8, ... }
  },
  "failureMessage": null,
  "url": "https://tdqs.dev/reports/k3n9x2p0qa"
}

The shapes of lint and score are the package's published JSON Schemas, and every field name matches the specification's output format.

Limits

per request
Up to 200 tools; a definition set larger than 1 MB is refused.
per account
30 calls per day, shared across the account's keys, resetting at 00:00 UTC. POST /lint and POST /reports spend one each; GET /reports/:uid is free. Every counted response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (the next reset, as unix seconds); the account overview shows the same balance.
model
The operator's choice, named on every report; scores are only comparable within one rubric+model pair.