# Get the public catalog and list prices

> GET /v1/catalog: Get the public catalog and list prices. Noptcha API reference.

Source: https://noptcha.com/docs/api-reference/get-catalog/

GET https://api.noptcha.com/v1/catalog

Native API (v1). [Guide](https://noptcha.com/docs/native-api.md). Operation ID `getCatalog`.

The public task types with their list prices, for price tables and integrations that have no key yet. No authentication: the `Authorization` header is ignored (a valid, invalid or missing key gets the same response, and is not checked or counted against the IP). The items have the same shape as `GET /v1/types`, but list every public type at the list price, whatever an organization's actual prices or a key's allowed types; use `GET /v1/types` for the prices that apply to you.

`placeholder` is `true` when the prices are not real prices (test deployments only); do not show them as prices then.

Cacheable: `Cache-Control: public, max-age=300`, a strong `ETag`; send it back in `If-None-Match` to get `304 Not Modified`. `HEAD` works as well.

Cross-origin reads are allowed from any origin: every response on this path, errors included, has `Access-Control-Allow-Origin: *` and exposes `ETag`, `Retry-After` and `Noptcha-Request-Id`. There is no CORS preflight (`OPTIONS` is not served), so from a browser send a simple request: a plain `fetch(url)`, or only CORS-safelisted headers such as `Accept`; a request with `Authorization` or another custom header is blocked by the browser. The SDKs' `get_catalog` / `getCatalog` send only `Accept` (no key, and the TypeScript SDK no `User-Agent`).

Rate limit per client IP: 60 per minute, bursts of 30; for IPv6 per /64, and also 600 per minute, bursts of 300, per /48 (starting values). Over that `429 rate_limited` with `Retry-After`.

## Request

Authentication: the key in the `clientKey` body field ([Keys](https://noptcha.com/docs/authentication.md)).

| Parameter | In | Description |
| --- | --- | --- |
| `If-None-Match`  optional  | header |  An `ETag` from an earlier response (or a list of them, or `*`); `304` when it still matches.  string · e.g. "5d41402abc4b2a76b9719d911017c592"  |

## Responses

### 200

The catalog.

Headers: `Access-Control-Allow-Origin`, `Cache-Control`, `ETag`, `Noptcha-Request-Id`.

Content: `application/json`

| Field | Type | Description |
| --- | --- | --- |
| `currency`  required  | `const "USD"` |  |
| `data`  required  | `array of TypeInfo` |  Every public task type with a list price, ordered by `type`.  |
| `data.[item]`  optional  | `object` |  |
| `data.[item].family`  required  | `string` |  Captcha family (concurrency is limited per family), e.g. `recaptcha`, `hcaptcha`, `cloudflare`, `arkose`, `image`.  |
| `data.[item].name`  required  | `string` |  |
| `data.[item].status`  required  | `string` |  `active` or `beta`.  |
| `data.[item].timeout_seconds`  required  | `integer` |  Deadline after which an unsolved task fails with `timeout`.  |
| `data.[item].type`  required  | `string` |  |
| `data.[item].variants`  required  | `array of object` |  |
| `data.[item].variants.[item]`  optional  | `object` |  |
| `data.[item].variants.[item].price`  required  | [`Money`](https://noptcha.com/docs/api-reference/schemas.md#Money) |  |
| `data.[item].variants.[item].variant`  required  | `string` |  `proxyless` or `proxy` (the task has `params.proxy`).  |
| `placeholder`  required  | `boolean` |  `true` when the prices are placeholders, not real prices (test deployments only).  |
| `price_version`  required  | `integer` |  Version of the price list the prices come from.  |

### 304

Not modified (`If-None-Match` matched the current `ETag`); no body.

Headers: `Access-Control-Allow-Origin`, `Cache-Control`, `ETag`, `Noptcha-Request-Id`.

### 403

`forbidden` (problem details): the request reached the API without passing through our edge network. Infrastructure, not part of the compatibility protocol.

Headers: `Noptcha-Request-Id`.

Content: `application/problem+json`

| Field | Type | Description |
| --- | --- | --- |
| `code`  required  | `string` |  Machine-readable error code (see the table).  |
| `detail`  optional  | `string` |  Human-readable explanation of this occurrence.  |
| `request_id`  required  | `string` |  Same as the `Noptcha-Request-Id` header.  |
| `status`  required  | `integer` |  The HTTP status code.  |
| `title`  required  | `string` |  |
| `type`  required  | `string` |  format: uri  |

### 413

`request_too_large`: the body exceeds the limit (1 MB for image types, 64 KB otherwise). Any request with a body over 1 MB gets this, GET requests included.

Headers: `Noptcha-Request-Id`, `RateLimit` (optional), `RateLimit-Policy` (optional).

Content: `application/problem+json`

| Field | Type | Description |
| --- | --- | --- |
| `code`  required  | `string` |  Machine-readable error code (see the table).  |
| `detail`  optional  | `string` |  Human-readable explanation of this occurrence.  |
| `request_id`  required  | `string` |  Same as the `Noptcha-Request-Id` header.  |
| `status`  required  | `integer` |  The HTTP status code.  |
| `title`  required  | `string` |  |
| `type`  required  | `string` |  format: uri  |

### 429

`rate_limited`: too many tasks created per second by this key, the same task polled too often, the sandbox's per-organization rate, usage queried too often, the catalog fetched too often from this IP, or this IP sent too many invalid keys. `concurrency_limited`: the organization has too many tasks in flight for this captcha family (or, with a test key, too many sandbox tasks still processing). Wait `Retry-After` seconds.

Headers: `Noptcha-Request-Id`, `RateLimit` (optional), `RateLimit-Policy` (optional), `Retry-After`.

Content: `application/problem+json`

| Field | Type | Description |
| --- | --- | --- |
| `code`  required  | `string` |  Machine-readable error code (see the table).  |
| `detail`  optional  | `string` |  Human-readable explanation of this occurrence.  |
| `request_id`  required  | `string` |  Same as the `Noptcha-Request-Id` header.  |
| `status`  required  | `integer` |  The HTTP status code.  |
| `title`  required  | `string` |  |
| `type`  required  | `string` |  format: uri  |

### 500

`internal`: an error on our side.

Headers: `Noptcha-Request-Id`, `RateLimit` (optional), `RateLimit-Policy` (optional).

Content: `application/problem+json`

| Field | Type | Description |
| --- | --- | --- |
| `code`  required  | `string` |  Machine-readable error code (see the table).  |
| `detail`  optional  | `string` |  Human-readable explanation of this occurrence.  |
| `request_id`  required  | `string` |  Same as the `Noptcha-Request-Id` header.  |
| `status`  required  | `integer` |  The HTTP status code.  |
| `title`  required  | `string` |  |
| `type`  required  | `string` |  format: uri  |

### 503

`service_unavailable`: no capacity right now (all solvers busy or failing, the gateway is overloaded, a dependency is unavailable). For `POST /v1/tasks` nothing was created or charged. Wait `Retry-After`.

Headers: `Noptcha-Request-Id`, `RateLimit` (optional), `RateLimit-Policy` (optional), `Retry-After`.

Content: `application/problem+json`

| Field | Type | Description |
| --- | --- | --- |
| `code`  required  | `string` |  Machine-readable error code (see the table).  |
| `detail`  optional  | `string` |  Human-readable explanation of this occurrence.  |
| `request_id`  required  | `string` |  Same as the `Noptcha-Request-Id` header.  |
| `status`  required  | `integer` |  The HTTP status code.  |
| `title`  required  | `string` |  |
| `type`  required  | `string` |  format: uri  |

Header descriptions and every schema: [Schemas](https://noptcha.com/docs/api-reference/schemas.md). Machine-readable: [openapi.json](https://noptcha.com/openapi.json), [openapi.yaml](https://noptcha.com/openapi.yaml).
