Guides / Reference

Dog Image API curl examples

By the Dog Image API team. Updated .

Every Dog Image API call works from a terminal with curl. Breed lists and previews need no key. Full-size PNGs and usage need an Authorization: Bearer header. This cookbook gives one short command per task, with the output you should expect, and ends with every error reply.

Set two variables once, so the commands below stay short.

BASE=https://dogimage.dev
export DOG_IMAGE_API_KEY="paste-your-key-here"   # only needed from the full-size section on

List the breeds

curl -s "$BASE/api/v1/breeds" | head -c 300

The reply is JSON with a views list and a breeds list. No key is needed, and browsers on other sites may call this endpoint too.

Pipe it to jq

Count the breeds, without hardcoding a number anywhere:

curl -s "$BASE/api/v1/breeds" | jq '.breeds | length'

Print every slug, one per line:

curl -s "$BASE/api/v1/breeds" | jq -r '.breeds[].slug'

Find the breeds that come in more than one color, with how many variants each has:

curl -s "$BASE/api/v1/breeds" \
  | jq -r '.breeds[] | select(.variants | length > 1) | "\(.slug) \(.variants | length)"'

On the day of writing this prints seven breeds, from french-bulldog to great-dane. List the nine view ids:

curl -s "$BASE/api/v1/breeds" | jq -r '.views[].id'

Print the crossbreeds only:

curl -s "$BASE/api/v1/breeds" | jq -r '.breeds[] | select(.crossbreed) | .name'

Look at one breed

curl -s "$BASE/api/v1/breeds/pug" | jq '{name, default_variant, summary: .summary.title}'

The reply carries a summary (which may be null), and for each variant a views object with preview_512, preview_1024 and full links. Pull out the colors of a breed and the link to one full-size file:

curl -s "$BASE/api/v1/breeds/golden-retriever" | jq -r '.variants[].slug'
curl -s "$BASE/api/v1/breeds/pug" | jq -r '.variants[0].views.head.full'

The full link is a pointer to the full-size endpoint. Opening it still needs your key.

Download a free preview

The preview endpoint redirects. Without -L, curl shows the redirect and stops.

curl -s -i "$BASE/api/v1/images/pug/default/front?size=512" | head -n 3

You see HTTP/2 302 and a location: line that points at a .webp file. With -L, curl follows it:

curl -sSL "$BASE/api/v1/images/pug/default/front?size=512" -o pug-front-512.webp
file pug-front-512.webp

Sizes are 512 and 1024, and 1024 is the default. A preview is a transparent WebP, and showing one on a page requires the credit link from the license.

Download a full-size PNG

curl -sS --fail-with-body \
  -H "Authorization: Bearer $DOG_IMAGE_API_KEY" \
  "$BASE/api/v1/images/pug/default/front?size=full" \
  -o pug-front.png

The file is a 2048 x 2048 transparent PNG, about 1 to 7 MB. --fail-with-body makes curl exit with an error code on a 4xx or 5xx, so your shell script can tell success from failure.

Download all nine views of one breed, using the view ids from the breeds list:

for view in $(curl -s "$BASE/api/v1/breeds" | jq -r '.views[].id'); do
  curl -sS --fail-with-body \
    -H "Authorization: Bearer $DOG_IMAGE_API_KEY" \
    "$BASE/api/v1/images/beagle/default/$view?size=full" \
    -o "beagle-$view.png" || break
done

The || break stops the loop on the first failure, such as a 429, instead of saving eight more error bodies.

Check usage

curl -s -H "Authorization: Bearer $DOG_IMAGE_API_KEY" "$BASE/api/v1/usage" | jq
{ "month": "2026-11", "plan": "starter", "limit": 200, "used": 12, "remaining": 188 }

That sample is the documented shape. On the All images plan, limit and remaining are null.

Read the response headers

-D - writes the headers to the terminal, and -o keeps the binary body out of the way:

curl -sS -D - -o pug-front.png \
  -H "Authorization: Bearer $DOG_IMAGE_API_KEY" \
  "$BASE/api/v1/images/pug/default/front?size=full"

A good reply includes Content-Type: image/png, a Content-Disposition header with a file name such as pug-fawn-front.png, and X-Quota-Limit, X-Quota-Used and X-Quota-Remaining. On the All images plan the quota values read unlimited.

To keep only the quota lines, write the headers to a file and filter it:

curl -sS -D headers.txt -o pug-front.png \
  -H "Authorization: Bearer $DOG_IMAGE_API_KEY" \
  "$BASE/api/v1/images/pug/default/front?size=full"
grep -i '^x-quota' headers.txt

To get only the status code of a call, use -w:

curl -s -o /dev/null -w '%{http_code}\n' "$BASE/api/v1/images/pug/default/front?size=512"

That prints 302, because -L was not set.

See every error

Errors are JSON in the shape {"error": {"code": "...", "message": "..."}}. These three you can reproduce right now with no key:

curl -s "$BASE/api/v1/images/pug/default/front?size=99"
{"error":{"code":"bad_size","message":"size must be one of 512, 1024, full.","choices":["512","1024","full"]}}
curl -s "$BASE/api/v1/images/pug/default/front?size=full"
{"error":{"code":"missing_or_invalid_key","message":"Full-size files need an API key: Authorization: Bearer <key>."}}
curl -s "$BASE/api/v1/images/nope/default/front"
{"error":{"code":"unknown_breed","message":"No breed \"nope\". GET /api/v1/breeds lists them."}}

The 404 family also includes unknown_variant and unknown_view, and on the image endpoint each lists the valid choices in the reply. The breed detail endpoint uses the same JSON error:

curl -s -w '\n%{http_code}\n' "$BASE/api/v1/breeds/nope"
{"error":{"code":"unknown_breed","message":"No breed \"nope\". GET /api/v1/breeds lists them."}}
404

The other codes need an account state you will meet in real use:

Status Code Meaning
402 no_active_plan The key is valid but has no active plan
429 quota_used_up The monthly full-size count is spent
502 file_unavailable Not counted. Try again
503 plan_check_failed Try again

Pick a retry policy in the errors and quotas reference. The docs list every endpoint.

Questions

How do I make curl follow the preview redirect?

Add -L. The preview endpoint answers with a 302 to a WebP file, and -L makes curl fetch the file itself. Add -o to name the output.

How do I see the quota headers with curl?

Use -D - to print the response headers, with -o to send the image body to a file. Look for X-Quota-Limit, X-Quota-Used and X-Quota-Remaining.

Why does curl save a small JSON file instead of my PNG?

The request failed and the error body was saved under your file name. Add --fail-with-body so curl returns a non-zero exit code and still prints the JSON error.

Is the preview image safe to use in a project?

Previews are free with a visible credit link next to the image or on the same page. They are AI-generated illustrations, not photos.

Next steps