Skip to main content

Createrington Skin API - Python client

createrington-skin-api

Official Python client for the Createrington Skin API. Renders Minecraft player skins into named poses and returns PNG bytes. Sync and async clients, fully typed.

pip install createrington-skin-api

Access is invite-only. Request an API key at https://api.createrington.com.

Quickstart

from createrington_skin_api import SkinApiClient

client = SkinApiClient(api_key="sk_...")  # or set SKIN_API_KEY

# Render a known pose for a Minecraft account by UUID.
png = client.render("wave", uuid="069a79f444e94726a5befca90e38aaf5")

# `png` is `bytes` of a PNG image.
with open("notch-waving.png", "wb") as f:
    f.write(png)

Async

import asyncio
from createrington_skin_api import AsyncSkinApiClient


async def main() -> None:
    async with AsyncSkinApiClient(api_key="sk_...") as client:
        png = await client.render("wave", username="Notch", slim=True)
        with open("notch-waving.png", "wb") as f:
            f.write(png)


asyncio.run(main())

Client

SkinApiClient(
    api_key=None,          # required; falls back to the SKIN_API_KEY env var
    base_url="https://api.createrington.com",
    timeout=30.0,          # seconds
    retries=2,             # retries 429/502/503/504 and network errors
    user_agent="createrington-skin-api",
)

AsyncSkinApiClient takes the same arguments. Both are usable as context managers (with / async with) and expose close() / aclose() for explicit cleanup of the underlying connection pool.

render

client.render(
    pose,                  # a pose name (e.g. "wave"), or any pose string
    *,
    # exactly one skin source:
    uuid=None,             # Mojang UUID, resolved server-side
    username=None,         # Mojang username, resolved server-side
    skin_url=None,         # public URL to a 64x64 PNG
    skin_base64=None,      # base64-encoded 64x64 PNG (data URL prefix optional)
    png=None,              # raw 64x64 PNG bytes, sent as multipart/form-data
    # options:
    slim=None,             # override slim/Alex arm geometry; default uses skin metadata
    outline=False,         # draw an outline around the skin; default off
    style="default",       # "default" or "cel" (cel shading with ink lines over the skin's pixels)
    width=None,            # default 400 (64..2048)
    height=None,           # default 600 (64..2048)
) -> bytes

Exactly one skin source must be supplied; passing none or more than one raises ValueError.

Poses exposes every pose known to the SDK at publish time as a named constant, so you can reference one by name instead of a bare string:

from createrington_skin_api import Poses

png = client.render(Poses.wave, uuid="069a79f444e94726a5befca90e38aaf5")

pose accepts any string, so server-side poses added after this release work without an SDK upgrade; fetch GET /v1/poses directly if you need the live catalogue with descriptions.

random_pose() returns a uniformly random known pose name:

from createrington_skin_api import random_pose

png = client.render(random_pose(), uuid="069a79f444e94726a5befca90e38aaf5")

avatar

client.avatar(
    *,
    # exactly one skin source (same as render):
    uuid=None,             # Mojang UUID, resolved server-side
    username=None,         # Mojang username, resolved server-side
    skin_url=None,         # public URL to a 64x64 PNG
    skin_base64=None,      # base64-encoded 64x64 PNG (data URL prefix optional)
    png=None,              # raw 64x64 PNG bytes, sent as multipart/form-data
    # options:
    size=None,             # output edge length in px; default 64 (8..512), square
    overlay=None,          # composite the hat layer; on by default
) -> bytes

Returns a flat 2D front-view avatar: a square PNG of the skin's face with the hat layer composited on top. Exactly one skin source must be supplied, the same way as render; passing none or more than one raises ValueError. overlay is on by default and the request omits the parameter unless you pass overlay=False.

png = client.avatar(uuid="069a79f444e94726a5befca90e38aaf5", size=128)

The async client exposes await client.avatar(...) with the same arguments.

resolve

client.resolve(
    *,
    # exactly one identifier:
    uuid=None,             # player UUID, dashed or compact
    username=None,         # Minecraft username, case-insensitive
) -> ResolvedPlayer

Resolves a player identity in either direction: pass uuid to get the current username, or username to get the UUID. Exactly one identifier must be supplied; passing none or both raises ValueError. Returns a ResolvedPlayer dataclass: uuid is always the canonical dashed lowercase form and username carries the canonical casing (None only when a degraded fallback provider could not supply the name). An unknown player raises SkinApiError with code == "not_found".

player = client.resolve(username="Notch")
print(player.uuid)      # "069a79f4-44e9-4726-a5be-fca90e38aaf5"
print(player.username)  # "Notch"

Lookups share the server's resolution cache, so a recent name change can take up to a day to appear. Resolutions do not count toward the image volume quota.

The async client exposes await client.resolve(...) with the same arguments.

Errors

Every non-2xx response (and network/timeout failures) raises SkinApiError:

from createrington_skin_api import SkinApiError

try:
    client.render("wave", uuid="bad-uuid")
except SkinApiError as err:
    print(err.code, err.status, err)
    if err.code == "rate_limited" and err.retry_after_ms:
        ...  # back off and retry

err.code is one of "bad_request", "unauthorized", "forbidden", "not_found", "conflict", "unsupported_media_type", "rate_limited", "internal", "render_failed", "upstream_unavailable", "timeout", "aborted", "network_error", "unknown". err.status is the HTTP status (or 0 for network/timeout failures). err.retry_after_ms is populated on 429 responses when the server reports it.

The client retries 429, 502, 503, 504, and network errors up to retries times with exponential backoff; 429 responses honour the server's retryAfterMs when present.

Building

pip install -e ".[dev]"
pytest
mypy

_poses.py is generated from the published OpenAPI document (fetched live, not committed):

python scripts/generate_poses.py

render accepts any pose string, so a new server-side pose works without an SDK change; Poses and KNOWN_POSES only provide names known at build time.

Contributing

Issues and pull requests are welcome. By submitting a contribution you agree it is licensed under the project's Apache-2.0 terms (section 5 of the license); no separate CLA is required.

License

Apache-2.0. See LICENSE.

Release files for createrington-skin-api 2.14.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for createrington-skin-api 2.14.0
File Size Uploaded
createrington_skin_api-2.14.0.tar.gz 21.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for createrington-skin-api 2.14.0
File Interpreter ABI Platform
createrington_skin_api-2.14.0-py3-none-any.whl Python 3 none any Details

Total release size: 42.3 kB

Release files / createrington_skin_api-2.14.0.tar.gz

Download URL createrington_skin_api-2.14.0.tar.gz
Size 21.9 kB
Tags Source
SHA-256 checksum
How to use checksums
3f49869da36efbffe7c53d8acb48169071f2b8cf137e1df4e9ca1d9c7c2cdb6f
BLAKE2b-256 checksum
How to use checksums
c96e58bc4e2b125d7cac87f9240aabcd4babd28e9a98c97075cd83076751eb93
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.13

Release files / createrington_skin_api-2.14.0-py3-none-any.whl

Download URL createrington_skin_api-2.14.0-py3-none-any.whl
Size 20.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
dbee1045c5aba1b6fb22c82b34c253adfe52f71920da967cbed3a7db1df83617
BLAKE2b-256 checksum
How to use checksums
05539d040ba7f1dd2b08e95e7b713604df588677a1a5f8742a60c51e6722a839
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.13

Release history Release notifications | RSS feed

This release

2.14.0 This release

2 release files

2.12.0

2 release files

2.11.0

2 release files

2.9.0

2 release files

2.8.0

2 release files

2.7.0

2 release files

2.6.0

2 release files

2.5.0

2 release files

2.4.0

2 release files

2.3.3

2 release files

2.3.2

2 release files

1.3.1

2 release files

1.3.0

2 release files

1.2.0

2 release files

1.1.0

2 release files

1.0.1

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page