# Runners

6 operations on the Logion v1 API.

- [Enroll a runner node.](#enroll-a-runner-node) — `POST /v1/runners/enroll`
- [Renew a held lease.](#renew-a-held-lease) — `POST /v1/runners/heartbeat`
- [Upload one artifact blob for the leased job.](#upload-one-artifact-blob-for-the-leased-job) — `POST /v1/runners/jobs/{job_id}/artifacts/{name}`
- [Submit a signed execution receipt.](#submit-a-signed-execution-receipt) — `POST /v1/runners/jobs/{job_id}/receipt`
- [Claim one queued execution job.](#claim-one-queued-execution-job) — `POST /v1/runners/lease`
- [Rotate a runner's API key and signing keypair.](#rotate-a-runner-s-api-key-and-signing-keypair) — `POST /v1/runners/rotate-key`

## Enroll a runner node.

```http
POST /v1/runners/enroll
```

Operation id: `enroll_runner`

Takes an [`Authorization`](/docs/api/overview#authentication) header.

**Request body**

Body `EnrollRunnerRequest`:

| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| `capabilities` | string[] | no |  |
| `name` | string | yes | min length 1; max length 255 |

**Responses**

| Status | Meaning | Schema |
| --- | --- | --- |
| `201` | Successful Response | `EnrollRunnerResponse` |
| `401` | Authentication required | `ErrorResponse` |
| `403` | Enrollment is disabled or access is forbidden | `ErrorResponse` |
| `422` | Invalid enrollment request | `ErrorResponse` |

Returns `EnrollRunnerResponse`:

| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| `key_fingerprint` | string | yes |  |
| `runner_id` | string | yes |  |
| `runner_key` | string | yes |  |
| `signing_key_fingerprint` | string | yes |  |
| `signing_key_pem` | string | yes |  |

## Renew a held lease.

```http
POST /v1/runners/heartbeat
```

Operation id: `runner_heartbeat`

Takes an [`Authorization`](/docs/api/overview#authentication) header.

**Request body**

Body `RunnerHeartbeatRequest`:

| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| `attempt` | integer | yes |  |
| `job_id` | string | yes |  |

**Responses**

| Status | Meaning | Schema |
| --- | --- | --- |
| `200` | Successful Response | `RunnerHeartbeatResponse` |
| `401` | Runner authentication required | `ErrorResponse` |
| `403` | Runner access forbidden | `ErrorResponse` |
| `404` | Execution job or lease not found | `ErrorResponse` |
| `409` | Runner lease was lost | `ErrorResponse` |
| `422` | Invalid heartbeat request | `ErrorResponse` |

Returns `RunnerHeartbeatResponse`:

| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| `cancel_requested` | boolean | yes |  |
| `lease_expires_at` | string(date-time) | yes |  |
| `ok` | boolean | yes |  |

## Upload one artifact blob for the leased job.

```http
POST /v1/runners/jobs/{job_id}/artifacts/{name}
```

Operation id: `upload_execution_artifact`

Takes an [`Authorization`](/docs/api/overview#authentication) header.

**Parameters**

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `job_id` | path | string | yes |
| `name` | path | string | yes |

**Responses**

| Status | Meaning | Schema |
| --- | --- | --- |
| `200` | Successful Response | `UploadExecutionArtifactResponse` |
| `401` | Runner authentication required | `ErrorResponse` |
| `403` | Runner access forbidden | `ErrorResponse` |
| `404` | Execution job or lease not found | `ErrorResponse` |
| `409` | Runner lease was lost | `ErrorResponse` |
| `413` | Artifact exceeds the size limit | `ErrorResponse` |
| `415` | Expected an octet-stream request | `ErrorResponse` |
| `422` | Invalid artifact request | `ErrorResponse` |

Returns `UploadExecutionArtifactResponse`:

| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| `sha256` | string | yes |  |
| `size_bytes` | integer | yes |  |
| `stored` | boolean | yes |  |

## Submit a signed execution receipt.

```http
POST /v1/runners/jobs/{job_id}/receipt
```

Operation id: `submit_execution_receipt`

Takes an [`Authorization`](/docs/api/overview#authentication) header.

**Parameters**

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `job_id` | path | string | yes |

**Request body**

Body `SubmitExecutionReceiptRequest`:

| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| `client_receipt` | object | yes |  |
| `signature` | string | yes |  |
| `signature_algorithm` | string | yes |  |

**Responses**

| Status | Meaning | Schema |
| --- | --- | --- |
| `200` | Successful Response | `SubmitExecutionReceiptResponse` |
| `401` | Runner authentication required | `ErrorResponse` |
| `403` | Runner access forbidden | `ErrorResponse` |
| `404` | Execution job or lease not found | `ErrorResponse` |
| `409` | Receipt conflicts with coordinator state | `ErrorResponse` |
| `422` | Invalid receipt request | `ErrorResponse` |

Returns `SubmitExecutionReceiptResponse`:

| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| `accepted_as_late_evidence` | boolean | yes |  |
| `coordinator_accepted` | boolean | yes |  |
| `receipt_digest` | string | yes |  |
| `receipt_id` | string | yes |  |
| `terminal_status` | string | yes |  |

## Claim one queued execution job.

```http
POST /v1/runners/lease
```

Operation id: `lease_execution_job`

Takes an [`Authorization`](/docs/api/overview#authentication) header.

**Request body**

Body `LeaseExecutionJobRequest`:

| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| `capabilities` | string[] | no |  |

**Responses**

| Status | Meaning | Schema |
| --- | --- | --- |
| `200` | Successful Response | `LeaseExecutionJobResponse` |
| `401` | Runner authentication required | `ErrorResponse` |
| `403` | Runner access forbidden | `ErrorResponse` |
| `422` | Invalid lease request | `ErrorResponse` |

Returns `LeaseExecutionJobResponse`:

| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| `data` | object, optional | yes |  |

## Rotate a runner's API key and signing keypair.

```http
POST /v1/runners/rotate-key
```

Operation id: `rotate_runner_key`

Takes an [`Authorization`](/docs/api/overview#authentication) header.

**Responses**

| Status | Meaning | Schema |
| --- | --- | --- |
| `200` | Successful Response | `RotateRunnerKeyResponse` |
| `401` | Runner authentication required | `ErrorResponse` |
| `403` | Runner access forbidden | `ErrorResponse` |
| `422` | Invalid rotation request | `ErrorResponse` |

Returns `RotateRunnerKeyResponse`:

| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| `key_fingerprint` | string | yes |  |
| `runner_id` | string | yes |  |
| `runner_key` | string | yes |  |
| `signing_key_fingerprint` | string | yes |  |
| `signing_key_pem` | string | yes |  |
