---
title: One Move developer portal
description: Quickstart, self-serve OAuth clients, sandbox and rate limits.
canonical: https://getonemove.app/developers
last-updated: 2026-11-05
---

# One Move developer portal

Build against the same public report engine the website uses.

## Quickstart

1. Read the [API reference](https://getonemove.app/docs/api).
2. Call the sandbox: `curl https://api.getonemove.app/v1/sandbox/reports/chesscom/example`.
3. Call a real public report: `curl "https://api.getonemove.app/v1/free-reports/chesscom/hikaru?time_class=blitz"`.
4. If you need attributable limits, register a client with `POST https://api.getonemove.app/v1/clients` and exchange it at `https://api.getonemove.app/oauth2/token`.
5. For agent hosts, connect the [MCP server](https://getonemove.app/docs/mcp) instead of writing HTTP glue.

## API keys

`POST https://api.getonemove.app/v1/clients` is self-serve and anonymous. It returns:

```json
{
  "client_id": "om_...",
  "client_secret": "...",
  "scopes": ["reports:read", "reports:write", "docs:read"],
  "token_endpoint": "https://api.getonemove.app/oauth2/token"
}
```

The secret is shown once. Exchange it with the `client_credentials` grant. Public report reads work without any key.

## Sandbox

`GET https://api.getonemove.app/v1/sandbox/reports/{site}/{username}` returns a fixed synthetic report and never touches a real account. The sandbox accepts `chesscom` or `lichess` and any username. Use it for schema tests and retry logic.

## Rate limits

Default: 120 requests per minute per IP. Responses carry `RateLimit-Limit`, `RateLimit-Remaining`, `RateLimit-Reset` and `RateLimit-Policy`; 429s carry `Retry-After`. Report creation has its own per-IP budget documented in the API reference.

## Support

- Support form: https://getonemove.app/support
- Issues: https://github.com/chrissuperduper/workstreams/issues
- Source and agent rules: https://github.com/chrissuperduper/one-move-agent


---

---
title: One Move REST API
description: Versioned REST API reference with OAuth, pagination, async jobs and idempotency.
canonical: https://getonemove.app/docs/api
last-updated: 2026-11-05
---

# One Move REST API

Base URL: `https://api.getonemove.app`
Versioned base URL: `https://api.getonemove.app/v1`
OpenAPI: `https://api.getonemove.app/openapi.json`

## Authentication

The public read surface is anonymous: `GET /v1/constraints`, `GET /v1/free-reports/{site}/{username}` and `GET /v1/jobs/{id}` need no credentials. For higher, attributable limits, mint a client and use OAuth 2.0 client credentials:

```bash
curl -sS -X POST https://api.getonemove.app/v1/clients \
  -H 'Content-Type: application/json' \
  -d '{"client_name":"my-agent"}'
# { "client_id": "...", "client_secret": "...", "scopes": ["reports:read", "docs:read"] }

curl -sS -X POST https://api.getonemove.app/oauth2/token \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'grant_type=client_credentials&client_id=...&client_secret=...'
```

Then send `Authorization: Bearer <access_token>`. Discovery documents: [protected-resource metadata](https://api.getonemove.app/.well-known/oauth-protected-resource) and [authorization-server metadata](https://api.getonemove.app/.well-known/oauth-authorization-server). The full walkthrough is [auth.md](https://getonemove.app/auth.md).

## Scopes

| Scope | Grants |
| --- | --- |
| `reports:read` | Read public Free reports, jobs, constraints and documentation. |
| `reports:write` | Queue a Free report or submit a batch. |
| `docs:read` | Read documentation through the docs MCP server. |

## Endpoints

### `GET /v1/constraints`

List the Constraint catalog with Targets by Band. Cursor pagination:

| Query | Type | Meaning |
| --- | --- | --- |
| `limit` | integer, 1–50, default 20 | Page size. |
| `cursor` | string | Opaque cursor from `next_cursor`. |
| `subject` | `chess` or `poker` | Filter by subject. |

Response: `{ "data": [...], "next_cursor": "...", "has_more": true }`. When `has_more` is false, `next_cursor` is `null`.

### `GET /v1/constraints/{slug}`

One Constraint, its metric definition, direction and chess medians by Band.

### `GET /v1/free-reports/{site}/{username}`

`site` is `chesscom` or `lichess`. `username` is a public chess username. Optional `time_class=rapid|blitz`. Anonymous.

- `200` report
- `202` queued or running; body has `job_id`, `status`, `status_url`, `minutes`
- `404` not enough games, or unknown user
- `429` over the per-IP budget; `Retry-After` is set

### `GET /v1/jobs/{job_id}`

The async-job pattern: `queued`, `running`, `done` or `failed`, plus `status_url` and, when done, `result_url`.

### `POST /v1/batch`

Run up to 10 read operations in one request. Each operation has `id`, `tool` and `arguments`. Supported tools: `constraints.get`, `constraints.list`, `report.get`. Send an `Idempotency-Key` header to make retries safe. Response: `{ "results": [{ "id": "...", "ok": true, "result": ... }] }`.

### `GET /v1/sandbox/reports/{site}/{username}`

A stable, synthetic report for testing. It never reads a real account, never queues work and never calls Claude. Use it before touching a real username.

### `POST /v1/clients`

Self-serve OAuth client registration. Returns a client id, a secret shown once, and the scopes `reports:read`, `reports:write`, `docs:read`. Rate limited.

### `POST /v1/reports`

Queue a report from JSON: `{ "site": "chesscom", "username": "...", "time_class": "rapid" }`. Returns `202` with a job. Supports `Idempotency-Key`.

### `POST /v1/batch`

See above.

### `POST /ask`

NLWeb v0.55 natural-language search over the docs and Constraint catalog. Body: `{ "query": { "text": "..." }, "prefer": { "streaming": false } }`. Set `prefer.streaming` to `true` (or `Accept: text/event-stream`) for the NLWeb SSE events `start`, `result`, `complete`.

## Idempotency

All `POST`, `PUT` and `PATCH` requests accept an `Idempotency-Key` header. A replay with the same key and body returns the first response, status included, for 24 hours. A replay with a different body returns `409`.

## Pagination

List endpoints are cursor-based and return `data`, `next_cursor` and `has_more`. Treat the cursor as opaque. Do not construct cursors.

## Async jobs

Long work returns `202 Accepted` with a job id, `status_url` and a rough `minutes` estimate. Poll `/v1/jobs/{job_id}`; on success it returns `result_url`, the canonical report URL.

## Errors

Errors are JSON: `{ "detail": "..." }` or, for the agent API, `{ "error": { "code": "...", "message": "..." } }`. Status codes follow HTTP: `400` invalid input, `401` auth required, `404` not found, `409` idempotency conflict, `422` validation, `429` rate limited, `500` server error.

## Deprecation policy

The current stable version is `v1`. A deprecated endpoint keeps working for at least 90 days and returns `Deprecation: @<unix>` and `Sunset: <HTTP-date>`. The changelog is at https://api.getonemove.app/v1/deprecation.
