> For the complete documentation index, see [llms.txt](https://form-1.gitbook.io/form-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://form-1.gitbook.io/form-docs/reference/errors.md).

# Error Handling

Errors are returned as JSON with an `error` field describing what went wrong. This page lists every error response the API can currently return, grouped by status code.

## 400 Bad Request

Request was well-formed but invalid in some way. The message tells you exactly what to fix.

| Endpoint                      | Message                                                                                                          |
| ----------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `POST /v1/downloads`          | `'url' is required`                                                                                              |
| `POST /v1/downloads`          | `'source' is required`                                                                                           |
| `POST /v1/downloads`          | `'url' does not look like a valid {source} track URL`                                                            |
| `POST /v1/downloads`          | `source '{source}' is not supported yet`                                                                         |
| `POST /v1/downloads`          | `Bandcamp album/playlist URLs are not yet supported — submit an individual track URL (path containing /track/).` |
| `POST /v1/downloads`          | `No Spotify credentials registered for this API key. Register yours first via PUT /v1/spotify-credentials.`      |
| `PUT /v1/spotify-credentials` | `'client_id' and 'client_secret' are both required`                                                              |
| `PUT /v1/spotify-credentials` | `Spotify rejected these credentials: <reason>`                                                                   |

These are all client-side fixes — correct the request and retry.

## 401 Unauthorized

Applies to every endpoint except `GET /health`.

| Situation                                             | Message                      |
| ----------------------------------------------------- | ---------------------------- |
| `X-API-Key` header missing                            | `Missing X-API-Key header`   |
| Key doesn't match any active key, or has been revoked | `Invalid or revoked API key` |

If you're getting this unexpectedly, double-check the header name (`X-API-Key`, not `Authorization`) and ask the operator whether your key is still active.

## 404 Not Found

| Endpoint                     | Situation                                            | Message         |
| ---------------------------- | ---------------------------------------------------- | --------------- |
| `GET /v1/downloads/{job_id}` | Job doesn't exist, or belongs to a different API key | `Job not found` |

Jobs are scoped to the API key that created them — you cannot look up another key's job even with a valid `job_id`.

## 429 Too Many Requests

Returned when you exceed the rate limit for your API key (see [Getting Started](/form-docs/readme.md#rate-limiting)). The response includes a `Retry-After` header indicating how long to wait before your next request will be accepted. Back off and retry after that interval rather than retrying immediately.

## 501 Not Implemented

| Endpoint                            | Message                                       |
| ----------------------------------- | --------------------------------------------- |
| `GET /v1/downloads/{job_id}/events` | `SSE progress events are not implemented yet` |

This is a reserved-for-later endpoint, not an error in your request. Use `GET /v1/downloads/{job_id}` to poll for status instead.

## 503 Service Unavailable

| Endpoint      | Situation                            |
| ------------- | ------------------------------------ |
| `GET /health` | Postgres and/or Redis is unreachable |

Indicates an operator-side infrastructure problem, not something wrong with your request. See [Health Check](/form-docs/api-reference/health.md) for the response shape.

## Errors that don't come back as a clean status

If a job fails *after* being accepted — for example, the source track was removed, or processing hit an unrecoverable error — you won't see it as an HTTP error at all. `POST /v1/downloads` already returned `202` and a `job_id`. Instead, poll `GET /v1/downloads/{job_id}` and check for `"status": "failed"`, with details in the `error` field if one was recorded. See [Downloads](/form-docs/api-reference/downloads.md).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://form-1.gitbook.io/form-docs/reference/errors.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
