reference · envelope v1

The whole API is the URL.

Base URL https://avatarsapi.com. Success is image bytes; add ?json for the metadata envelope. No auth on the anonymous tier. Image URLs are never versioned — the bare URL has to keep working forever.

$ curl avatarsapi.com/github/Fyko # the image, 400px, cached 7d
01

Lookups

/:source/:handleOne named Source. /x/jack, /telegram/durov.
/email/:addressWalks the email Ladder: gravatar and github race, then BIMI.
/domain/:domainWalks the domain Ladder: BIMI, then DuckDuckGo and Google favicons.
/:handleInfers email or domain from the Handle’s shape. A bare username is rejected with EAMBIGUOUS — a username is ambiguous without a Source, so name one.
/p/:publishableKey/…Runs any Lookup through one Project — its Plan, config revision, and cache identity. Key authorization is resolved before every cache read; revocation takes effect on the next request.
/sourcesJSON catalogue of every Source and the Ladder each Kind uses.
/health{"status":"ok","sources":72}

Prefixed Handles

Some Sources take a type:value prefix when the id is not a username: /spotify/artist:0OdU…, /steam/group:valve, /linkedin/company:anthropic, /apple-store/name:Things@us. A Handle is one path segment — percent-encode any slash (/producthunt/products%2Ffoo).

02

Query parameters

paramdoesrangedefault
?jsonThe metadata envelope instead of image bytes.flagoff
?ttl=Edge-cache lifetime; sets cache-control. Accepts seconds or units: 3600, 1h, 28d. Starter Projects only; other Lookups ignore it and use the default.1h – 28d, clamped7d
?size=Square output in px. Sources that accept a size use it.16 – 1000, clamped400

Unknown or repeated parameters return EQUERY. The retired fallback parameter returns EFALLBACK for every value except the legacy no-op fallback=false. A Miss is a 404 envelope unless the URL uses a Starter Project with a managed Fallback: then a Miss, Fault, or timeout returns that image with x-avatar-result: fallback and x-lookup-outcome.

avatarsapi.com/x/jack?size=64&ttl=28d
03

Responses

hit — with ?json
{
  "version": 1,
  "data": {
    "url": "https://github.com/Fyko.png?size=400",
    "source": "github",
    "kind": "username"
  }
}
miss or fault
{
  "version": 1,
  "error": {
    "code": "ENOTFOUND",
    "message": "github: avatar URL answered 404",
    "docs": "https://avatarsapi.com/docs#errors"
  }
}

message is for humans and will change; branch on code. version covers the JSON envelope only — image URLs are never versioned.

04

Errors

codestatusmeans
EAMBIGUOUS400A bare username needs a Source named.
EFALLBACK400Anonymous runtime Fallback URLs are retired.
EQUERY400A query parameter is unknown or repeated.
EFORBIDDEN403A resolved or redirected address is private or reserved, so we refuse to follow it.
ENOTFOUND404No Source had an avatar for this Handle. A Miss is an ordinary answer, not a malfunction.
ERATELIMIT429Fresh anonymous or free-Project work exceeded its per-minute or daily limit. Cache Hits never trip it.
EUPSTREAM502A Source is broken, unreachable, or returned an unusable image. Often transient.
ETIMEOUT504The Lookup outran its budget.
EINTERNAL500Our fault. Retry; if it persists, tell us.

EUPSTREAM is always 502, even when the Source answered 429 or 403 — their rate limit is not ours, and forwarding it would tell you we throttled you.

05

Caching

Every response carries x-cache-status: HIT | MISS — the Worker’s own edge cache, checked before any Source is contacted. There is no redirect: the validated bytes come back from this URL, so browsers cache the image directly, and forwarded upstream etags let them revalidate with a 304 instead of pulling bytes again.

outcomecache-control
Validated Hitpublic, max-age=<ttl>, stale-while-revalidate=86400
Ordinary Miss or route factpublic, max-age=300
Query rejection, security refusal, rate limit, or Faultno-store
06

Every Hit is probed

A candidate URL is only a Hit after validation. gravatar?d=404 and github.com/:user.png are well-formed for handles that don’t exist — reachability is what separates a Hit from a Miss. Every candidate and redirect must:

07

Limits & Plans

planlimitprice
anonymous50 fresh Lookups / day per IP. Attribution required.$0
free project1,000 fresh Lookups / day per Project. Attribution required. Includes a browser-safe pk_ key.$0 / project / mo
starterManaged Fallback, no daily or per-minute limit, custom ?ttl, no attribution. Includes 5,000 unique avatar identities each month.$19 / project / mo

Cached images do not count toward usage or rate limits. Each Project is billed separately, and upgrading keeps its key and image URLs. The Starter monthly allowance is not currently enforced, and there are no overage charges. Daily limits reset at midnight UTC; a 429 carries retry-after and x-rate-limit-scope. Free tiers also have a burst limit of 120 fresh Lookups / minute per edge location. Attribution means a visible “Avatars by avatarsapi.com” link where the images appear.

<img src="https://avatarsapi.com/p/pk_…/github/Fyko" alt="">