# Analysis: Scarleta API reference

Page: https://www.scarleta.ai/docs/reference/analysis
Base URL: https://api.scarleta.ai. Authentication: `Authorization: Bearer $SCARLETA_API_KEY`.
Operations: 4.

## POST /v1/analyze

Operation id: `submit_analysis`

**Submit an analysis**

Starts a full analysis of one audio file and returns `202` at once with a `job_id`. Poll `GET /v1/analyze/{job_id}` until `status` is final; the analysis itself normally takes seconds to a minute.

`audio_url` must be a public `http` or `https` URL, or the URL of a file in your own library. Files longer than 60 minutes are refused with 400 `audio_too_long`. Unreadable or unsupported files are refused with 400 `unsupported_format` or `audio_processing_failed`; a file that cannot be downloaded from the URL is refused with 404 `audio_not_found`. Your balance is checked before the job starts; if it cannot cover the file the call returns 402 `insufficient_balance` and nothing is charged. Supply `features` to name the measurements you care about; leave it out to get the standard set.

Access: API key required; free and paid accounts. Cost: uses tokens. Charged when the analysis finishes: tokens per second of audio, at the rate for a full analysis. The submit response reports the amount in `expected_tokens`. A file longer than the maximum, or a balance too low to cover the file, is refused before anything starts..

### Request body

| Field | Type | Description |
| --- | --- | --- |
| `audio_url` | string | Where to fetch the audio, at most 4096 characters. Must be public `http` or `https`, or a file in your own library. Allowed: 1 to 4096 characters. |
| `features` | array<string> | Dotted feature ids to request, for example `spectral.centroid`. Ids that are not recognised are ignored and the standard set is used. |

### Response fields (inside `data`)

| Field | Type | Description |
| --- | --- | --- |
| `job_id` | string | Identifier to poll, cancel and read logs with. |
| `status` | "IN_QUEUE" \| "IN_PROGRESS" \| "COMPLETED" \| "FAILED" \| "CANCELLED" \| "TIMEOUT" | `IN_QUEUE` when accepted. |
| `message` | string |   |
| `tenant_id` | string \| null | Your account identifier. Absent for free accounts. |
| `audio_url` | string | The file being analyzed, with any credentials stripped from the URL. |
| `workflow` | "direct-api" |   |
| `created_at` | string | ISO 8601 timestamp. |
| `response_time_ms` | integer | How long accepting the job took, in milliseconds. Allowed: -9007199254740991 to 9007199254740991. |
| `expected_duration` | number | Length of the audio in seconds. |
| `expected_tokens` | integer | Tokens this analysis will cost when it finishes. Allowed: -9007199254740991 to 9007199254740991. |
| `cache_hit` | boolean | True when the file had been read before and was reused. |

### Responses

202: Accepted. The job is queued. Carries an `X-Job-ID` header with the same `job_id`,.

```json
{
  "data": {
    "job_id": "analysis_8f3c2a41-6d57-4b1e-9a02-5c7e1d0b9a44",
    "status": "IN_QUEUE",
    "message": "Analysis job submitted. Use GET /v1/analyze/{job_id} to retrieve results.",
    "tenant_id": "8c1d0b52-3f6a-4e0d-9d7b-2a41c5e90f13",
    "audio_url": "https://example.com/track-1.wav",
    "workflow": "direct-api",
    "created_at": "2026-10-21T03:41:37.272Z",
    "response_time_ms": 610,
    "expected_duration": 5.2,
    "expected_tokens": 26,
    "cache_hit": false
  },
  "meta": {
    "request_id": "req_0b7a3c2e-6f1d-4d9a-8e55-3a4b5c6d7e8f"
  }
}
```

400: Invalid JSON, a missing `audio_url`, an unacceptable URL, or a file that cannot be read as audio (`error.details.supported_formats` lists the accepted formats).

```json
{
  "error": {
    "code": "missing_audio_url",
    "message": "audio_url is required in request body",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#missing_audio_url"
  }
}
```

401: Missing, malformed, unknown or revoked API key.

```json
{
  "error": {
    "code": "invalid_key",
    "message": "Invalid or revoked API key",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#invalid_key"
  }
}
```

402: The balance cannot cover this file. `error.details.required_tokens` says how much is needed.

```json
{
  "error": {
    "code": "insufficient_balance",
    "message": "This audio requires 26 tokens (5.2s duration), but you have insufficient balance.",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#insufficient_balance"
  }
}
```

403: `audio_url` points at a library file owned by another account.

```json
{
  "error": {
    "code": "media_not_owned",
    "message": "That file belongs to a different account.",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#media_not_owned"
  }
}
```

404: The file at `audio_url` could not be downloaded.

```json
{
  "error": {
    "code": "audio_not_found",
    "message": "Unable to download audio file from the provided URL. Please ensure the URL is correct and the file is accessible.",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#audio_not_found"
  }
}
```

429: Over the account request budget for the hour. Wait for the `Retry-After` header, then retry.

```json
{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#rate_limit_exceeded"
  }
}
```

500: The analysis could not be started. Nothing was charged; retry.

```json
{
  "error": {
    "code": "analysis_service_error",
    "message": "Audio analysis service returned an error. Please try again.",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#analysis_service_error"
  }
}
```

503: The job could not be recorded. Nothing was charged; retry.

```json
{
  "error": {
    "code": "persistence_failed",
    "message": "Unable to create job tracking record. Please retry.",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#persistence_failed"
  }
}
```

### Error codes

[`analysis_failed`](https://www.scarleta.ai/docs/errors#analysis_failed), [`analysis_service_error`](https://www.scarleta.ai/docs/errors#analysis_service_error), [`audio_not_found`](https://www.scarleta.ai/docs/errors#audio_not_found), [`audio_processing_failed`](https://www.scarleta.ai/docs/errors#audio_processing_failed), [`audio_too_long`](https://www.scarleta.ai/docs/errors#audio_too_long), [`auth_unavailable`](https://www.scarleta.ai/docs/errors#auth_unavailable), [`configuration_error`](https://www.scarleta.ai/docs/errors#configuration_error), [`insufficient_balance`](https://www.scarleta.ai/docs/errors#insufficient_balance), [`invalid_audio_duration`](https://www.scarleta.ai/docs/errors#invalid_audio_duration), [`invalid_audio_url`](https://www.scarleta.ai/docs/errors#invalid_audio_url), [`invalid_auth_format`](https://www.scarleta.ai/docs/errors#invalid_auth_format), [`invalid_json`](https://www.scarleta.ai/docs/errors#invalid_json), [`invalid_key`](https://www.scarleta.ai/docs/errors#invalid_key), [`invalid_key_format`](https://www.scarleta.ai/docs/errors#invalid_key_format), [`media_not_owned`](https://www.scarleta.ai/docs/errors#media_not_owned), [`missing_api_key`](https://www.scarleta.ai/docs/errors#missing_api_key), [`missing_audio_url`](https://www.scarleta.ai/docs/errors#missing_audio_url), [`missing_auth`](https://www.scarleta.ai/docs/errors#missing_auth), [`persistence_failed`](https://www.scarleta.ai/docs/errors#persistence_failed), [`rate_limit_exceeded`](https://www.scarleta.ai/docs/errors#rate_limit_exceeded), [`rate_limit_unavailable`](https://www.scarleta.ai/docs/errors#rate_limit_unavailable), [`service_unavailable`](https://www.scarleta.ai/docs/errors#service_unavailable), [`unauthorized`](https://www.scarleta.ai/docs/errors#unauthorized), [`unsupported_format`](https://www.scarleta.ai/docs/errors#unsupported_format)

### Example

```bash
curl -X POST "https://api.scarleta.ai/v1/analyze" \
  -H "Authorization: Bearer $SCARLETA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "audio_url": "https://example.com/track-1.wav"
  }'
```

## GET /v1/analyze/{job_id}

Operation id: `get_analysis`

**Get an analysis**

Returns the state of one analysis job and, once `status` is `COMPLETED`, its `results`. Poll this route every few seconds until `status` is `FAILED`, `CANCELLED` or `TIMEOUT`, or `COMPLETED` with `results` present. You can only read your own jobs; any other job id returns 404 `job_not_found`. For a few seconds after `status` first reads `COMPLETED`, `results` can still be null: keep polling until it is an object. `results` is a JSON object whose keys depend on the analysis and can grow over time: read the keys you need and ignore the rest.

Access: API key required; free and paid accounts. Cost: no token cost.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `job_id` | path | string | yes | The `job_id` returned when the analysis was submitted, for example `analysis_8f3c2a41-6d57-4b1e-9a02-5c7e1d0b9a44`. Allowed: at least 1 character. |

### Response fields (inside `data`)

| Field | Type | Description |
| --- | --- | --- |
| `job_id` | string |   |
| `status` | "IN_QUEUE" \| "IN_PROGRESS" \| "COMPLETED" \| "FAILED" \| "CANCELLED" \| "TIMEOUT" |   |
| `workflow` | string | How the job was started; `direct-api` for jobs created by `POST /v1/analyze`. |
| `audio_url` | string | The analyzed file. A library file comes back as a short-lived signed link. |
| `features` | array<string> | The feature ids you asked for; empty when you took the standard set. |
| `results` | object \| null | The measurements, or null until the job completes. |
| `error` | any | Why the job failed, or null. |
| `created_at` | string | ISO 8601 timestamp. |
| `completed_at` | string \| null | ISO 8601 timestamp, or null while the job runs. |

### Responses

200: The job exists. `results` is null until `status` is `COMPLETED`.

```json
{
  "data": {
    "job_id": "analysis_8f3c2a41-6d57-4b1e-9a02-5c7e1d0b9a44",
    "status": "COMPLETED",
    "workflow": "direct-api",
    "audio_url": "https://example.com/track-1.wav",
    "features": [],
    "results": {
      "success": true,
      "summary": {
        "duration_seconds": 5,
        "dominant_key": "A",
        "rms_energy": 0.856
      }
    },
    "error": null,
    "created_at": "2026-10-21T03:41:37.272Z",
    "completed_at": "2026-10-21T03:41:56.630Z"
  },
  "meta": {
    "request_id": "req_0b7a3c2e-6f1d-4d9a-8e55-3a4b5c6d7e8f"
  }
}
```

400: `job_id` has characters outside letters, digits and `_ . : -`, or is too long.

```json
{
  "error": {
    "code": "invalid_job_id",
    "message": "job_id must match ^[A-Za-z0-9_.:-]{1,128}$",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#invalid_job_id"
  }
}
```

401: Missing, malformed, unknown or revoked API key.

```json
{
  "error": {
    "code": "invalid_key",
    "message": "Invalid or revoked API key",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#invalid_key"
  }
}
```

404: No job with this id exists for your account.

```json
{
  "error": {
    "code": "job_not_found",
    "message": "Job analysis_8f3c2a41-6d57-4b1e-9a02-5c7e1d0b9a44 not found or access denied",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#job_not_found"
  }
}
```

429: Over the account request budget for the hour. Wait for the `Retry-After` header, then retry.

```json
{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#rate_limit_exceeded"
  }
}
```

500: The job could not be read. Retry.

```json
{
  "error": {
    "code": "retrieval_failed",
    "message": "Failed to retrieve analysis results",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#retrieval_failed"
  }
}
```

503: Temporary platform condition; retry shortly.

```json
{
  "error": {
    "code": "auth_unavailable",
    "message": "Authentication service temporarily unavailable",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#auth_unavailable"
  }
}
```

### Error codes

[`auth_unavailable`](https://www.scarleta.ai/docs/errors#auth_unavailable), [`invalid_auth_format`](https://www.scarleta.ai/docs/errors#invalid_auth_format), [`invalid_job_id`](https://www.scarleta.ai/docs/errors#invalid_job_id), [`invalid_key`](https://www.scarleta.ai/docs/errors#invalid_key), [`invalid_key_format`](https://www.scarleta.ai/docs/errors#invalid_key_format), [`job_not_found`](https://www.scarleta.ai/docs/errors#job_not_found), [`missing_api_key`](https://www.scarleta.ai/docs/errors#missing_api_key), [`missing_auth`](https://www.scarleta.ai/docs/errors#missing_auth), [`missing_job_id`](https://www.scarleta.ai/docs/errors#missing_job_id), [`rate_limit_exceeded`](https://www.scarleta.ai/docs/errors#rate_limit_exceeded), [`rate_limit_unavailable`](https://www.scarleta.ai/docs/errors#rate_limit_unavailable), [`retrieval_failed`](https://www.scarleta.ai/docs/errors#retrieval_failed), [`unauthorized`](https://www.scarleta.ai/docs/errors#unauthorized)

### Example

```bash
JOB_ID="YOUR_JOB_ID"
curl "https://api.scarleta.ai/v1/analyze/$JOB_ID" \
  -H "Authorization: Bearer $SCARLETA_API_KEY"
```

## POST /v1/analyze/{job_id}/cancel

Operation id: `cancel_analysis`

**Cancel an analysis**

Stops an analysis that has not finished and marks it `CANCELLED`. The call is idempotent: a job that is already final is left alone and its current `status` is returned, so a second cancel is not an error. A job cancelled before it finishes is not charged.

Access: API key required; free and paid accounts. Cost: no token cost.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `job_id` | path | string | yes | The `job_id` returned when the analysis was submitted, for example `analysis_8f3c2a41-6d57-4b1e-9a02-5c7e1d0b9a44`. Allowed: at least 1 character. |

### Response fields (inside `data`)

| Field | Type | Description |
| --- | --- | --- |
| `job_id` | string |   |
| `status` | "IN_QUEUE" \| "IN_PROGRESS" \| "COMPLETED" \| "FAILED" \| "CANCELLED" \| "TIMEOUT" | `CANCELLED` when this call stopped the job; otherwise the final state the job was already in. |

### Responses

200: Success

```json
{
  "data": {
    "job_id": "analysis_8f3c2a41-6d57-4b1e-9a02-5c7e1d0b9a44",
    "status": "CANCELLED"
  },
  "meta": {
    "request_id": "req_0b7a3c2e-6f1d-4d9a-8e55-3a4b5c6d7e8f"
  }
}
```

400: `job_id` has characters outside letters, digits and `_ . : -`, or is too long.

```json
{
  "error": {
    "code": "invalid_job_id",
    "message": "job_id must match ^[A-Za-z0-9_.:-]{1,128}$",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#invalid_job_id"
  }
}
```

401: Missing, malformed, unknown or revoked API key.

```json
{
  "error": {
    "code": "invalid_key",
    "message": "Invalid or revoked API key",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#invalid_key"
  }
}
```

404: No job with this id exists for your account.

```json
{
  "error": {
    "code": "job_not_found",
    "message": "Job 'analysis_8f3c2a41-6d57-4b1e-9a02-5c7e1d0b9a44' not found",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#job_not_found"
  }
}
```

429: Over the account request budget for the hour. Wait for the `Retry-After` header, then retry.

```json
{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#rate_limit_exceeded"
  }
}
```

503: Temporary platform condition; retry shortly.

```json
{
  "error": {
    "code": "auth_unavailable",
    "message": "Authentication service temporarily unavailable",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#auth_unavailable"
  }
}
```

### Error codes

[`auth_unavailable`](https://www.scarleta.ai/docs/errors#auth_unavailable), [`invalid_auth_format`](https://www.scarleta.ai/docs/errors#invalid_auth_format), [`invalid_job_id`](https://www.scarleta.ai/docs/errors#invalid_job_id), [`invalid_key`](https://www.scarleta.ai/docs/errors#invalid_key), [`invalid_key_format`](https://www.scarleta.ai/docs/errors#invalid_key_format), [`job_not_found`](https://www.scarleta.ai/docs/errors#job_not_found), [`missing_api_key`](https://www.scarleta.ai/docs/errors#missing_api_key), [`missing_auth`](https://www.scarleta.ai/docs/errors#missing_auth), [`missing_job_id`](https://www.scarleta.ai/docs/errors#missing_job_id), [`rate_limit_exceeded`](https://www.scarleta.ai/docs/errors#rate_limit_exceeded), [`rate_limit_unavailable`](https://www.scarleta.ai/docs/errors#rate_limit_unavailable), [`unauthorized`](https://www.scarleta.ai/docs/errors#unauthorized)

### Example

```bash
JOB_ID="YOUR_JOB_ID"
curl -X POST "https://api.scarleta.ai/v1/analyze/$JOB_ID/cancel" \
  -H "Authorization: Bearer $SCARLETA_API_KEY"
```

## GET /v1/analyze/{job_id}/logs

Operation id: `get_analysis_logs`

**Get the logs of an analysis**

Returns the execution log entries recorded for one of your jobs, oldest first, at most 200 entries. A job that has not started a step, or an analysis submitted with `POST /v1/analyze`, can have no entries: `logs` is then an empty array. Use the logs to diagnose a failed job.

Access: API key required; free and paid accounts. Cost: no token cost.

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `job_id` | path | string | yes | The `job_id` returned when the analysis was submitted, for example `analysis_8f3c2a41-6d57-4b1e-9a02-5c7e1d0b9a44`. Allowed: at least 1 character. |

### Response fields (inside `data`)

| Field | Type | Description |
| --- | --- | --- |
| `job_id` | string |   |
| `status` | "IN_QUEUE" \| "IN_PROGRESS" \| "COMPLETED" \| "FAILED" \| "CANCELLED" \| "TIMEOUT" |   |
| `log_count` | integer | Entries in `logs`. Allowed: -9007199254740991 to 9007199254740991. |
| `logs` | array<object> |   |
| `logs[].job_id` | string |   |
| `logs[].tool_name` | string \| null | Name of the step that produced the entry. |
| `logs[].worker_id` | string \| null | Opaque identifier of the machine that ran the step. |
| `logs[].success` | boolean \| null | Whether the step succeeded. |
| `logs[].total_time_ms` | number \| null | How long the step took, in milliseconds. |
| `logs[].error_message` | string \| null | Why the step failed, when it did. |
| `logs[].stdout_tail` | string \| null | The last lines the step printed. |
| `logs[].created_at` | string \| number \| null | When the entry was recorded. |

### Responses

200: Success

```json
{
  "data": {
    "job_id": "analysis_8f3c2a41-6d57-4b1e-9a02-5c7e1d0b9a44",
    "status": "COMPLETED",
    "log_count": 0,
    "logs": []
  },
  "meta": {
    "request_id": "req_0b7a3c2e-6f1d-4d9a-8e55-3a4b5c6d7e8f"
  }
}
```

400: `job_id` has characters outside letters, digits and `_ . : -`, or is too long.

```json
{
  "error": {
    "code": "invalid_job_id",
    "message": "job_id must match ^[A-Za-z0-9_.:-]{1,128}$",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#invalid_job_id"
  }
}
```

401: Missing, malformed, unknown or revoked API key.

```json
{
  "error": {
    "code": "invalid_key",
    "message": "Invalid or revoked API key",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#invalid_key"
  }
}
```

404: No job with this id exists for your account.

```json
{
  "error": {
    "code": "job_not_found",
    "message": "Job 'analysis_8f3c2a41-6d57-4b1e-9a02-5c7e1d0b9a44' not found",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#job_not_found"
  }
}
```

429: Over the account request budget for the hour. Wait for the `Retry-After` header, then retry.

```json
{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#rate_limit_exceeded"
  }
}
```

503: Temporary platform condition; retry shortly.

```json
{
  "error": {
    "code": "auth_unavailable",
    "message": "Authentication service temporarily unavailable",
    "request_id": "req_5b1c0f3e-2d41-4a8e-9a57-0c1b2d3e4f50",
    "docs_url": "https://www.scarleta.ai/docs/errors#auth_unavailable"
  }
}
```

### Error codes

[`auth_unavailable`](https://www.scarleta.ai/docs/errors#auth_unavailable), [`invalid_auth_format`](https://www.scarleta.ai/docs/errors#invalid_auth_format), [`invalid_job_id`](https://www.scarleta.ai/docs/errors#invalid_job_id), [`invalid_key`](https://www.scarleta.ai/docs/errors#invalid_key), [`invalid_key_format`](https://www.scarleta.ai/docs/errors#invalid_key_format), [`job_not_found`](https://www.scarleta.ai/docs/errors#job_not_found), [`missing_api_key`](https://www.scarleta.ai/docs/errors#missing_api_key), [`missing_auth`](https://www.scarleta.ai/docs/errors#missing_auth), [`missing_job_id`](https://www.scarleta.ai/docs/errors#missing_job_id), [`rate_limit_exceeded`](https://www.scarleta.ai/docs/errors#rate_limit_exceeded), [`rate_limit_unavailable`](https://www.scarleta.ai/docs/errors#rate_limit_unavailable), [`unauthorized`](https://www.scarleta.ai/docs/errors#unauthorized)

### Example

```bash
JOB_ID="YOUR_JOB_ID"
curl "https://api.scarleta.ai/v1/analyze/$JOB_ID/logs" \
  -H "Authorization: Bearer $SCARLETA_API_KEY"
```
