Icon Generator API
Quickstart
Get a PNG straight to disk
curl -X POST https://hytaleicon.com/api/v1/icons \
-H "X-API-Key: hig_live_xxxxxxxxxxxx.yyyyyyyy" \
-F "[email protected]" \
-F "[email protected]" \
-F "size=128" \
-o sword_icon.png
Get JSON with metadata
curl -X POST https://hytaleicon.com/api/v1/icons \
-H "X-API-Key: hig_live_xxxxxxxxxxxx.yyyyyyyy" \
-H "Accept: application/json" \
-F "[email protected]" \
-F "[email protected]" \
-F "size=128"
Authentication
Every request needs an API key in the X-API-Key header. Keys are issued by the site operator and stored hashed — the plaintext token is shown once, at creation, and cannot be recovered.
To request a key, contact Hylterium.
A key embedded in browser JavaScript is public by construction. For production, call the API from your own backend and keep the key there.
Parameters
Identical names in multipart/form-data and JSON mode. Unlike the website, the API rejects out-of-range values instead of silently clamping them.
| Name | Type | Range | Default | Description |
|---|---|---|---|---|
model |
file / object | required | — |
The .blockymodel file. In JSON mode: the object itself or a base64 string. |
texture |
file / base64 | required | — |
The PNG texture. A data:image/png;base64, prefix is accepted. |
size |
integer | 16 – 512 | 64 |
Output size in pixels (square). |
supersample |
integer | 1 – 8 | 2 |
Antialiasing factor. size x supersample must stay under 1024. |
yaw |
float | -180.0 – 180.0 | -75.0 |
Horizontal camera angle, in degrees. |
pitch |
float | -90.0 – 90.0 | 25.0 |
Vertical camera angle, in degrees. |
padding |
float | 0.3 – 1.0 | 0.92 |
Fraction of the frame the model fills. |
transparent |
boolean | true / false | true |
Transparent background. Ignored when background is set. |
background |
string | #RRGGBB or #RRGGBBAA | — |
Explicit background colour. Takes precedence over transparent. |
shading |
boolean | true / false | false |
Per-face shading (top bright, bottom dark). |
center |
boolean | true / false | true |
Recenter the visible silhouette in the frame. |
format |
string | png / json | png |
Response format. Accept: application/json has the same effect. |
disposition |
string | inline / attachment | inline |
Content-Disposition in PNG mode. |
filename |
string | — | icon.png |
Base name of the returned file. |
Responses
By default the response body is the raw PNG, with metadata in headers:
HTTP/1.1 200 OK
Content-Type: image/png
Content-Disposition: inline; filename="sword_icon.png"
X-Icon-Width: 128
X-Icon-Height: 128
X-RateLimit-Limit: 10
X-RateLimit-Remaining: 9
X-Quota-Limit: 1000
X-Quota-Remaining: 941
X-Request-Id: a1b2c3d4e5f6
With format=json or Accept: application/json:
{
"image": "iVBORw0KGgo...",
"encoding": "base64",
"mime_type": "image/png",
"filename": "sword_icon.png",
"width": 128,
"height": 128,
"bytes": 1837,
"options": { "size": 128, "supersample": 2, "yaw": -75.0, "pitch": 25.0 },
"model": { "cubes": 12, "faces": 41 },
"rate_limit": { "limit": 10, "remaining": 9, "reset": 18 },
"quota": { "limit": 1000, "remaining": 941, "reset": "2026-08-14T00:00:00+00:00" },
"request_id": "a1b2c3d4e5f6"
}
Errors
Errors are always JSON, whatever the requested format. Each carries a stable code and a request_id you can quote when reporting a problem.
{
"error": {
"code": "invalid_parameter",
"message": "size must be between 16 and 512, got 9999",
"field": "size",
"request_id": "a1b2c3d4e5f6"
}
}
| Code | HTTP | Meaning |
|---|---|---|
malformed_request |
400 | The request body could not be parsed. |
missing_api_key |
401 | No X-API-Key header was sent. |
invalid_api_key |
401 | The key is unknown or the secret does not match. |
key_revoked |
403 | This key has been revoked. |
parameter_exceeds_key_limit |
403 | The value is above the ceiling allowed for your key. |
not_found |
404 | No such API endpoint. |
method_not_allowed |
405 | Wrong HTTP method for this endpoint. |
payload_too_large |
413 | The request, the model or the texture is above the size cap. |
unsupported_media_type |
415 | Send multipart/form-data or application/json. |
missing_field |
422 | A required field (model or texture) is missing. |
invalid_parameter |
422 | A parameter is unparseable or out of range. |
invalid_model |
422 | The model is not valid BlockyModel JSON. |
model_has_no_geometry |
422 | The model parsed but contains no visible cube. |
model_too_complex |
422 | The model has too many cubes to render. |
invalid_texture |
422 | The texture could not be decoded as an image. |
texture_too_large |
422 | The texture exceeds the maximum dimensions. |
render_too_large |
422 | size x supersample is above the allowed budget. |
rate_limited |
429 | Too many requests. Back off and retry. |
quota_exceeded |
429 | Daily quota exhausted. Resets at UTC midnight. |
internal_error |
500 | Unexpected server error. Quote the request_id when reporting it. |
Rate limits and quotas
Two limits apply: a per-key burst allowance that refills continuously, and a daily quota that resets at UTC midnight. Failed requests are refunded — only successful renders count against your quota.
| Limit | Value |
|---|---|
size | 16 – 512 |
supersample | 1 – 8 |
size × supersample | ≤ 1024 |
model | ≤ 2 MiB |
texture | ≤ 4 MiB, 4096 × 4096 px |
| request | ≤ 8 MiB |
| cubes | ≤ 5000 |
Every response carries the current state:
X-RateLimit-Limit 10
X-RateLimit-Remaining 9
X-RateLimit-Reset 18
X-Quota-Limit 1000
X-Quota-Remaining 941
X-Quota-Reset 2026-08-14T00:00:00+00:00
Retry-After 12 # 429 only
CORS
All /api/v1 endpoints send Access-Control-Allow-Origin: * and expose the rate-limit headers, so browser clients can read their own budget and back off correctly.
OpenAPI schema
The full machine-readable schema is available at
https://hytaleicon.com/api/v1/openapi.json