> ## Documentation Index
> Fetch the complete documentation index at: https://docs.relayintelligence.org/llms.txt
> Use this file to discover all available pages before exploring further.

# HTTP

> The training API's routes, and the inference and training-session wire protocols, for clients in other languages.

The Python package wraps these. Use them directly from another language.

## Authentication

Every request to the training API carries your API key:

```
Authorization: Bearer $RELAY_API_KEY
```

Errors come back as `{"error": "<message>"}` with status 400 (a bad request), 401 (no key, or an invalid one), 404 (not found, or not yours) or 503.

## Fine-tuning jobs

| Route | Body | Returns |
| - | - | - |
| `POST /v1/fine-tunes` | `SFTConfig`'s fields as JSON | a job |
| `GET /v1/fine-tunes` | | `{"data": [jobs]}`, newest first |
| `GET /v1/fine-tunes/{id}` | | a job |
| `POST /v1/fine-tunes/{id}/cancel` | | a job |
| `GET /v1/fine-tunes/{id}/events` | | `{"data": [records]}` |

```bash theme={null}
curl -X POST "$RELAY_BASE_URL/v1/fine-tunes" \
  -H "Authorization: Bearer $RELAY_API_KEY" -H "Content-Type: application/json" \
  -d '{"model": "pi05", "dataset_name": "lerobot/pusht_image", "batch_size": 32, "targets": ["all"]}'
```

A job is JSON: `id`, `status`, `created_at`, `model`, `dataset_name`, `batch_size`, `learning_rate`, `steps`, `finetune`, `lora_rank`, `lora_alpha`, `targets`, `cameras`, `name`, `step`, `loss`, `error`, `output_dir`. See [Fine-tuning](https://docs.relayintelligence.org/fine-tuning.md) for the fields and their limits.

## Training sessions

| Route | Body | Returns |
| - | - | - |
| `POST /v1/training_sessions` | `base_model`, `finetune` (`"lora"` or `"full"`), `rank`, `alpha`, `targets`, `action_horizon` | a session |
| `GET /v1/training_sessions` | | `{"data": [sessions]}` |
| `GET /v1/training_sessions/{id}` | | a session |
| `POST /v1/training_sessions/{id}/close` | | a session |

A session is JSON: `id`, `status` (`starting`, `ready`, `closed` or `error`), `created_at`, its request's fields, `url`, `token` and `error`. Poll it until it's `ready`, then open a websocket to its `url` with `Authorization: Bearer <token>`.

### The session's websocket

Messages are [msgpack](https://msgpack.org), with numpy arrays as maps with binary keys: `{"__ndarray__": true, "data": <bytes>, "dtype": "<f4", "shape": [...]}` (OpenPI's encoding).

1. The server sends `{"info": {"model", "action_horizon", "action_dim", "trainable_params"}}`.
2. You send requests: `{"id": <int>, "op": <op>, ...arguments}`.
3. It answers each, in order: `{"id", "result"}` or `{"id", "error"}`. You may send the next before the last is answered.

| `op` | Arguments | `result` |
| - | - | - |
| `forward_backward` | `data`, `codec`, `loss_fn` | `{"loss", "loss_per_datum"}` |
| `forward` | `data`, `codec`, `keep` | `velocity`, `target`, `x_t`, `noise`, `time` |
| `backward` | `velocity_grad`, after a `forward` with `keep: true` | `{}` |
| `optim_step` | `learning_rate`, `beta1`, `beta2`, `eps`, `weight_decay`, `grad_clip_norm` | `{"grad_norm", "skipped"}` |
| `sample` | `data`, `codec`, `num_steps`, `weights` (a saved name, or null) | actions `(B, action_horizon, action_dim)` |
| `save_state`, `load_state` | `name` | the name, or `{}` |
| `save_weights` | `name` | the weights' path |

`data` is a list of `{"observation": {"image": {camera: <encoded frame>}, "state", "prompt"}, "actions", "weight"}`, the frames encoded with `codec` (a [Codec](https://docs.relayintelligence.org/reference/python.md#codec) name: `"LOSSLESS"` for ZPNG, or `"CODEC_JPEG_Q90"` and the like for JPEG).

## Inference

A policy server speaks OpenPI's websocket protocol:

1. Connect to its `wss://` URL. It sends its metadata, msgpack-encoded.
2. Send an observation: msgpack, then compressed with zstd (level 1) using Relay's dictionary, [`observation.zdict`](https://github.com/RelayIntelligenceAI/Relay/blob/main/sdk/python/src/relay/inference/observation.zdict). It holds OpenPI's keys plus `image_codec`, the codec its frames are encoded with.
3. It replies with `{"actions", "policy_timing", "server_timing"}`, or, if the request failed, a text frame with its traceback, and then closes the connection.

`GET /healthz` on the same host answers `OK` once the server is up.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.