HTTP API · shapeaddress.com/v1
The same picture over HTTP
For a page with no build step, a language with no port yet, or a quick look. Every response is the output of the same core library, cached as immutable for a year.
Two addresses, straight from the API:
<img src="https://shapeaddress.com/v1/0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045.svg?size=64" width="64" alt=""> <img src="https://shapeaddress.com/v1/0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045.svg?layout=coin&size=64" width="64" height="64" alt="">
Routes
| Route | Content type | Body |
|---|---|---|
GET /v1/{address}.svg | image/svg+xml | The SVG, exactly shapeaddress(address, options). Works in <img>, CSS url() and as a file. |
GET /v1/{address}.json | application/json | The cells as data, exactly shapeaddress.cells(address, options): dictionary, layout, hex, one entry per cell with byte, indices, names and colour hex, plus the checksum cell. |
GET /v1/{address}.txt | text/plain | The spoken legend on one line, cells separated by a comma and a space: purple flower, purple three-dots, … |
GET /v1/dictionaries | application/json | What this server can draw: [{ id, name, colors, glyphs, license }]. |
{address} is hex, with or without 0x, any case, even length. It need not be 20 bytes. Anything that is not hex is a 400.
Query parameters
The names are the core options, with bg for background. Omitted parameters take the core defaults, so a bare URL gives the same picture as a bare shapeaddress(address) call.
| Parameter | Values | Default |
|---|---|---|
layout | grid, coin | grid |
size | 16 to 1024, clamped into that range | 64 |
style | tile, glyph | tile |
cell | rounded, circle, square | rounded |
gap | 0 to 40 | 8 |
radius | 0 to 50 | 14 |
bg | a CSS colour, URL-encoded (%23ffffff for white) | transparent |
palette | default, cvd | default |
dictionary | an id from /v1/dictionaries | sa330 |
labels (1 or true) and title (up to 200 characters) are accepted; highlight is not served, it is presentation for a page that already has the library. Any other parameter, or a value outside its set, is a 400.
https://shapeaddress.com/v1/0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045.svg?layout=coin&size=128&style=glyph&bg=%23ffffff https://shapeaddress.com/v1/0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045.json?dictionary=fa330 https://shapeaddress.com/v1/0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045.txt
Headers and caching
A ShapeAddress of a given address and options never changes, so the response says so.
| Header | Value | Why |
|---|---|---|
Cache-Control | public, max-age=31536000, immutable | Browsers and CDNs keep it for a year and never revalidate. |
ETag | hash of the body | If-None-Match gets a 304. |
Access-Control-Allow-Origin | * | Fetch it from any page. |
X-Content-Type-Options | nosniff | SVG is served as an image, never sniffed as a document. |
Set-Cookie | never | No session, no tracking. |
A 400 response is cached for an hour, so a bad URL does not become a load on the server. There is no PNG route: the server keeps zero dependencies, and every browser renders SVG in <img>. For raster output, draw the SVG onto a canvas on the client.
Privacy: wallets should bundle the library
Every request to this API tells a server which address someone looked at and when. For a wallet, an explorer or anything that shows a user's own accounts, that is a leak. The library is one file, 5 kB gzipped, with no dependencies. Bundle it and render locally. Use the API for public pages, prototypes and languages with no port.
Self-host
The server is the @shapeaddress/api package: a Node http handler with no dependencies. Run it anywhere Node 22 runs.
# one command, listens on $PORT
npx @shapeaddress/api
# as a module, in your own server (Node http, or any framework that gives you req and res)
const { createHandler, toNode } = require('@shapeaddress/api');
require('node:http').createServer(toNode(createHandler())).listen(8787);# Docker, from the repository git clone https://github.com/ShapeAddress/shapeaddress.git cd shapeaddress docker build -t shapeaddress-api . docker run --rm -p 8787:8787 shapeaddress-api curl -s http://localhost:8787/v1/dictionaries
A self-hosted server registers the dictionaries it starts with, so a private dictionary stays private. Put a CDN in front of it; the cache headers do the rest.