---
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.
