Specious Coda-Bishop · Technical Writing
Reference documentation for The Cat API's images search endpoint. Covers authentication, query parameters, response schema, error handling, and pagination behaviour — written to production documentation standards.
This document is a technical writing sample produced for a JetBrains application. The Cat API is a real, publicly available REST API. All parameters, response fields, error codes, and behaviour documented here reflect the actual API — this is not a fictional example.
The goal was to demonstrate API documentation to a production standard: precise parameter tables, accurate authenticated vs. unauthenticated distinctions, copy-pasteable examples, and error states written for resolution rather than enumeration.
The Cat API is a free, publicly available REST API for cat images and breed data. It's a genuinely useful tool for prototyping, testing, or building anything that needs placeholder imagery — and it happens to be cats, which is rarely a problem.
This document covers one endpoint: GET /v1/images/search. It's the one you'll use most. Send a request, get cat images back. By default it returns one random image — no setup, no key, nothing to configure. Once you add an API key, you unlock filtering by breed or category, pagination, and batch retrieval up to 25 results per request.
Common use cases
| What you want to do | How to do it |
|---|---|
| Show a random cat image on a page | Call the endpoint with no parameters — one random image, no key required |
| Show only a specific breed | Use breed_ids with an API key |
| Build a browsable gallery with pages | Use order=ASC, limit, and page to step through results in order |
| Show breed facts alongside the photo | Use has_breeds=1 — the response will include a full breed data object |
| Only return still photos, no GIFs | Use mime_types=jpg,png |
Embed an image directly in an <img> tag | Set format=src — the API returns the raw image file instead of JSON |
An API key is a unique string that identifies your account to the API. Think of it as a membership card — free to get, and it unlocks significantly more of the API than you can access without one.
You pass your API key in the request header as x-api-key. If you don't include it, the API still works — you just get one random image per call with no filtering. That's fine for a quick test. It's not enough to build anything real.
How to send the key
| Header name | Value |
|---|---|
x-api-key | Your API key, copied from the thecatapi.com dashboard |
What the key unlocks
| Without a key | With a key | |
|---|---|---|
| Images per request | 1 | Up to 25 |
| Filter by breed or category | No — parameters are silently ignored | Yes |
| Pagination | No | Yes |
| Monthly request allowance | No limit, but no tracking either | 10,000 (free) / 100,000 (premium) |
The header name must be lowercase: x-api-key. Some HTTP clients normalise header casing automatically, but not all of them. If your key appears valid but you're getting a 401, check that the header name isn't being sent as X-Api-Key or X-API-Key.
GET is an HTTP method that means "give me data." You're not creating anything, not updating anything — you're just asking for cat images and the API is handing them back. All the options you want (how many images, which breed, what format) are added to the URL as query parameters after a ?, or passed as headers. There's no request body.
The URL above is the full path to the endpoint. Everything after the ? in your request is a query parameter — covered in the next section.
A query parameter is a key-value pair appended to a URL to customise a request. The first one starts with ?; any additional ones are separated by &. For example: ?limit=10&order=ASC&breed_ids=beng passes three parameters at once. Order doesn't matter.
These are the knobs you can turn to shape what the API gives back. None of them are required. Leave them all out and you get one random cat image — totally valid. Add them to get more specific.
limit
Controls how many images come back in a single response. The default is 1. The maximum is 25. If you want more than one image, you need an API key.
When to use it: Any time you need more than a single cat — loading a grid, pre-fetching a batch, or building something that needs variety on the same page load.
| Parameter | Type | Default | Max | Requires key? |
|---|---|---|---|---|
limit | integer | 1 | 25 | Only for values above 1 |
order
Controls whether results come back in a stable, predictable sequence or in a random shuffle each time.
| Parameter | Type | Default | Accepted values |
|---|---|---|---|
order | string | RANDOM | RANDOM, ASC, DESC |
page
When you're using order=ASC or order=DESC, you can step through the full result set in chunks using page. It's zero-indexed, so the first page is page=0, the second is page=1, and so on.
When to use it: Pagination. If you're fetching 10 images at a time and want the next 10, increment the page number. See Section 09 for a worked example.
Note: This parameter does nothing when order=RANDOM. The API ignores it silently.
| Parameter | Type | Default | Note |
|---|---|---|---|
page | integer | 0 | Zero-indexed. Ignored when order=RANDOM. |
breed_ids
Pass one or more breed IDs to get back images of only those breeds. IDs are short strings like beng for Bengal or abys for Abyssinian. Separate multiple IDs with a comma.
When to use it: When your app is about a specific breed, or when a user has selected a breed from a list and you're fetching images to match. To get the full list of valid breed IDs, call GET /v1/breeds.
Requires an API key. Without one, this parameter is silently ignored and you'll get a random image with no filtering applied.
| Parameter | Type | Default | Example |
|---|---|---|---|
breed_ids | string | — | breed_ids=beng,abys |
category_ids
Similar to breed_ids, but for categories. Categories are broader groupings — things like "hats" or "boxes" — rather than breed-specific. Pass one or more category IDs as a comma-separated list. Call GET /v1/categories for the full list.
Requires an API key.
| Parameter | Type | Default | Example |
|---|---|---|---|
category_ids | string | — | category_ids=1,5 |
has_breeds
By default, the API returns whatever images it finds — not all of them have breed data attached. Set has_breeds=1 to filter out any image that doesn't come with a breeds object in the response.
When to use it: Whenever you want to display breed information alongside the image — name, description, temperament, origin. Without this filter, the breeds array may come back empty even when you're not filtering by a specific breed.
| Parameter | Type | Default | Accepted values |
|---|---|---|---|
has_breeds | integer | 0 | 0 (off) or 1 (on) |
mime_types
The Cat API serves JPGs, PNGs, and GIFs. By default you'll get a mix of all three. Pass one or more types to restrict what comes back.
When to use it: If your UI can't handle GIFs, or you specifically want animated images, or you're compressing images downstream and need a consistent format.
| Parameter | Type | Default | Accepted values |
|---|---|---|---|
mime_types | string | All types | jpg, png, gif (comma-separated) |
size
The API stores images in multiple size variants. This parameter tells it which one to give you. med is a good default for most display contexts. Use thumb for compact grids or lists, and full when you need the original resolution.
| Parameter | Type | Default | Options (smallest → largest) |
|---|---|---|---|
size | string | med | thumb, small, med, full |
format
By default the API responds with JSON — a structured data object containing the image URL, dimensions, and any breed or category info. Setting format=src changes the response entirely: instead of JSON, you get back the raw image file itself.
When to use it: When you want to point an <img> tag directly at the API endpoint without any JavaScript. The endpoint URL becomes the image source. All other parameters still apply, so you can still filter by breed, type, or size.
| Parameter | Type | Default | Accepted values |
|---|---|---|---|
format | string | json | json, src |
breed_ids and category_ids require a valid API key. Without one, these parameters are silently ignored — you won't get an error, just unfiltered results. If your filtering appears to have no effect, check that your x-api-key header is present and correct.
The examples below use curl, a command-line tool for making HTTP requests. It comes pre-installed on macOS and Linux, and is available on Windows via WSL or Git Bash. You can paste these directly into a terminal — just replace YOUR_API_KEY with your actual key.
Authenticated request — 5 Bengal images with breed data
curl -X GET "https://api.thecatapi.com/v1/images/search?limit=5&has_breeds=1&breed_ids=beng&order=ASC&page=0" \ -H "x-api-key: YOUR_API_KEY"
Here's what each part is doing:
| Part | What it does |
|---|---|
curl -X GET | Makes an HTTP GET request — reading data, not sending any |
limit=5 | Return 5 images instead of the default 1 |
has_breeds=1 | Only return images that have breed data attached |
breed_ids=beng | Filter for Bengal cats only (beng is Bengal's ID in the API) |
order=ASC | Return images in a consistent order so pagination works correctly |
page=0 | Start from the first page of results (zero-indexed) |
-H "x-api-key: ..." | Sends the API key as a request header, which is required for filtering to work |
Minimal unauthenticated request
No key, no parameters. Returns a single random cat image. Good for a quick check that the API is responding.
curl -X GET "https://api.thecatapi.com/v1/images/search"Using format=src to embed directly
This returns the raw image file, not JSON. The URL below can be used as the src attribute of an <img> tag.
<!-- A random still cat photo, embedded directly with no JavaScript --> <img src="https://api.thecatapi.com/v1/images/search?format=src&mime_types=jpg" alt="A random cat">
When format=json (the default), the API responds with a JSON array — a list of image objects, one per result. Even if you asked for only one image, it comes back as an array with a single item.
Understanding what fields come back — and when — saves debugging time. The breeds array, for example, is always present in the response, but it's empty unless you've asked for images with breed data attached.
Every image in the response includes these fields.
| Field | Type | What it contains |
|---|---|---|
id | string | A unique identifier for this image — useful if you want to request it directly later via GET /v1/images/{image_id}. |
url | string | The direct URL to the image file. This is what you'll put in an <img> tag or display to the user. |
width | integer | Image width in pixels. Useful for calculating aspect ratios or setting container dimensions before the image loads. |
height | integer | Image height in pixels. |
breeds | array | A list of breed objects for this image. Empty ([]) if no breed data is attached. Use has_breeds=1 or breed_ids to guarantee this is populated. |
categories | array | A list of category objects for this image. Empty ([]) if no categories are assigned or if you didn't filter by category_ids. |
breeds array)When a breed is attached to an image, each item in the breeds array contains the following. Most images have either zero or one breed — multiple is uncommon.
| Field | Type | What it contains |
|---|---|---|
id | string | The breed's short identifier (e.g. beng). This is what you pass to breed_ids when filtering. |
name | string | The breed's full name (e.g. Bengal). |
description | string | A paragraph-length description of the breed's personality and characteristics. |
temperament | string | A comma-separated list of personality traits (e.g. "Alert, Agile, Energetic, Demanding, Intelligent"). |
origin | string | The country the breed originates from. |
life_span | string | Typical lifespan as a range (e.g. "12 - 15", in years). |
wikipedia_url | string | A link to the breed's Wikipedia article, if one is available. |
reference_image_id | string | The ID of the canonical reference image for this breed. You can fetch it directly using GET /v1/images/{image_id}. |
When you use order=ASC or order=DESC, the API includes an extra HTTP response header alongside the JSON body.
| Header | What it tells you |
|---|---|
pagination-count | The total number of images matching your current query — across all pages, not just the current one. Divide by your limit value to calculate how many pages exist. |
The pagination-count value arrives as an HTTP header, not inside the JSON. In curl, use the -i flag to see headers alongside the response body. In JavaScript, access it via response.headers.get('pagination-count').
This is what the API returns for a request with has_breeds=1&breed_ids=beng&limit=1. The breeds array is populated with a full breed object. The categories array is empty because no category filter was applied.
[
{
/* The image's unique ID — use this to fetch it directly later */
"id": "O3btzLlsRf",
/* The actual image URL — put this in your img src */
"url": "https://cdn2.thecatapi.com/images/O3btzLlsRf.jpg",
"width": 1200,
"height": 800,
/* breeds is populated because we used has_breeds=1 */
"breeds": [
{
"id": "beng",
"name": "Bengal",
"description": "Bengals are a lot of fun to live with, but they're
definitely not the cat for everyone, or for first-time cat owners.
Extremely active, curious, and always alert, nothing escapes
their attention.",
"temperament": "Alert, Agile, Energetic, Demanding, Intelligent",
"origin": "United States",
"life_span": "12 - 15",
"wikipedia_url": "https://en.wikipedia.org/wiki/Bengal_(cat)",
"reference_image_id": "O3btzLlsRf"
}
],
/* Empty because we didn't filter by category */
"categories": []
}
]The API uses standard HTTP status codes. If something goes wrong, the status code tells you where to look first.
| Status | What it means | Most likely cause | What to do |
|---|---|---|---|
400 |
Bad Request | You've passed a parameter value the API doesn't recognise — for example order=NEWEST or size=large. |
Check the accepted values in Section 04. Typos in parameter values are the most common cause. |
401 |
Unauthorized | The API key is missing, malformed, or invalid. Also fires if the header name is wrong. | Double-check: (1) the header is named x-api-key in lowercase, (2) the key value is copied exactly from your dashboard with no extra spaces, (3) you haven't accidentally committed a placeholder like YOUR_API_KEY. |
429 |
Too Many Requests | You've used up your monthly request allowance — 10,000 on the free tier. | Upgrade to a premium plan, or wait until the start of the next billing month for the allowance to reset. If you're hitting this in development, consider caching responses locally rather than calling the API repeatedly. |
500 |
Internal Server Error | Something went wrong on the API's side. Your request was fine — the server had a problem. | Wait a moment and try again. If it keeps happening, check thecatapi.com for any service status announcements. Use exponential backoff if you're retrying automatically — don't hammer a struggling server. |
If a request fails and you retry automatically, don't retry immediately — wait a moment first, then progressively longer between each attempt. For example: wait 1 second, retry; wait 2 seconds, retry; wait 4 seconds, retry. This avoids flooding a server that's already struggling, and is considered standard practice for handling transient failures.
Pagination lets you fetch large result sets in manageable chunks instead of all at once. Here's how it works in practice.
Say you want to show all Bengal cat images, 10 at a time. Your first request looks like this:
?breed_ids=beng&order=ASC&limit=10&page=0
The response body gives you 10 images. The pagination-count response header tells you, say, 87 — meaning there are 87 Bengal images in total. That means 9 pages (⌈87 ÷ 10⌉ = 9). To get the next batch, increment page:
?breed_ids=beng&order=ASC&limit=10&page=1 # images 11–20 ?breed_ids=beng&order=ASC&limit=10&page=2 # images 21–30 # ...and so on
Pagination only works when order is ASC or DESC. With RANDOM (the default), the API returns a different random set every time — there's no stable sequence to page through. Setting page=2 with order=RANDOM doesn't return the "second page of random results" — it just returns another random set and ignores page entirely.
Rate limits on the Cat API are monthly, not per-second. You won't get throttled for making rapid requests — but you will run out of allowance if you make too many calls across the month.
If you're building something in development and burning through requests quickly, cache the responses locally. Fetching the same breed's images over and over during testing is a quick way to hit your limit before anything is even deployed.
The API doesn't error when you pass filtering parameters without a key — it just ignores them and returns a random image. This is the most common source of confusion when first using the API.
If you're getting random results when you expected filtered ones, and everything looks right in your code, the problem is almost always a missing or invalid x-api-key header. Check these in order:
x-api-key in lowercase?