MintRender
All docs pages

Images and assets

An image in a template comes from an uploaded asset (asset:img_…) or from a URL that we fetch. Upload images that many renders use, like logos. Use URLs for images that change per render, like product photos.

Upload a file

Send multipart/form-data with the file in the field file and an optional name (at most 200 characters; default: the file name).

curl

curl -X POST "https://mintrender.com/v1/assets" \  -H "Authorization: Bearer $MINTRENDER_KEY" \  -F "file=@logo.png" \  -F "name=Logo"

JavaScript

import { readFile } from "node:fs/promises"; const form = new FormData();form.append("file", new Blob([await readFile("logo.png")]), "logo.png");form.append("name", "Logo");const res = await fetch("https://mintrender.com/v1/assets", {  method: "POST",  headers: { Authorization: `Bearer ${process.env.MINTRENDER_KEY}` },  body: form,});const asset = await res.json();if (!res.ok) throw new Error(`${asset.error.code}: ${asset.error.message}`);console.log(asset.src); // asset:img_…

Python

import os import requests with open("logo.png", "rb") as f:    res = requests.post(        "https://mintrender.com/v1/assets",        headers={"Authorization": f"Bearer {os.environ['MINTRENDER_KEY']}"},        files={"file": ("logo.png", f)},        data={"name": "Logo"},        timeout=120,    )asset = res.json()if not res.ok:    raise RuntimeError(f"{asset['error']['code']}: {asset['error']['message']}")print(asset["src"])  # asset:img_…

Upload from a URL

Send JSON with url. We fetch it once and store the bytes. The default name is the last part of the URL's path.

curl

curl -X POST "https://mintrender.com/v1/assets" \  -H "Authorization: Bearer $MINTRENDER_KEY" \  -H "Content-Type: application/json" \  -d '{"url":"https://example.com/logo.png","name":"Logo"}'

JavaScript

const res = await fetch("https://mintrender.com/v1/assets", {  method: "POST",  headers: {    Authorization: `Bearer ${process.env.MINTRENDER_KEY}`,    "Content-Type": "application/json",  },  body: JSON.stringify({    url: "https://example.com/logo.png",    name: "Logo",  }),});const body = await res.json();if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message} (${body.error.request_id})`);console.log(body);

Python

import os import requests res = requests.post(    "https://mintrender.com/v1/assets",    headers={"Authorization": f"Bearer {os.environ['MINTRENDER_KEY']}"},    json={        "url": "https://example.com/logo.png",        "name": "Logo",    },    timeout=120,)body = res.json()if not res.ok:    raise RuntimeError(f"{body['error']['code']}: {body['error']['message']} ({body['error']['request_id']})")print(body)

The asset object

{  "id": "img_9Lk2mQ8xP0aB4nC7vR2s",  "kind": "image",  "name": "Logo",  "mime": "image/png",  "bytes": 18211,  "sha256": "3f8a…",  "width": 640,  "height": 240,  "src": "asset:img_9Lk2mQ8xP0aB4nC7vR2s",  "source_url": null,  "created": "2026-11-01T09:30:00.000Z"}
FieldAbout
idimg_… for an image, csv_… for a CSV.
kindimage or csv.
mimeThe type read from the bytes: image/png, image/jpeg, image/gif, image/webp, image/svg+xml or text/csv.
bytes, sha256The stored file's size and hash.
width, heightPixels of an image. null for a CSV.
srcUse this as an image value in data or as src in a scene.
source_urlThe URL it was fetched from, or null for a file upload.

Use a CSV's id as csv_asset in a batch.

Types and sizes

TypeLimitNotes
PNG, JPEG, GIF, WebP20 MB, 16 megapixelsWe read the type from the bytes. The file name does not matter.
SVG20 MBCleaned on upload: scripts, foreignObject, event attributes and every outside reference are removed. It needs a width and height, or a viewBox. It is drawn as an image.
CSV5 MBUTF-8 text with no NUL bytes.

An image over 16 megapixels is refused with image_too_large. The editor makes such images smaller in your browser before it uploads them. Font files cannot be uploaded: fonts come from Google Fonts.

Image URLs in data

Asset (asset:img_…)URL in data
TypesPNG, JPEG, GIF, WebP, SVGPNG, JPEG, GIF, WebP
Size20 MB, 16 megapixels20 MB, 16 megapixels
When we read itStored once, at uploadFetched when a render needs it. Signed links reuse a fetch for an hour.
Same file againYes, while the template and data stay the sameYes, when the URL gives the same bytes

We fetch URLs with these rules: http or https on port 80 or 443, no user name or password, a public host (no localhost, .local, .internal and similar, and no private or reserved IP address), an answer within 10 seconds, at most 3 redirects, each checked again. Our requests send User-Agent: MintRender/1.0 (+https://mintrender.com).

List, download and delete

List assets, newest first, at most 500. Filter with kind=image or kind=csv.

curl

curl "https://mintrender.com/v1/assets?kind=image" \  -H "Authorization: Bearer $MINTRENDER_KEY"

JavaScript

const res = await fetch("https://mintrender.com/v1/assets?kind=image", {  method: "GET",  headers: {    Authorization: `Bearer ${process.env.MINTRENDER_KEY}`,  },});const body = await res.json();if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message} (${body.error.request_id})`);console.log(body);

Python

import os import requests res = requests.get(    "https://mintrender.com/v1/assets?kind=image",    headers={"Authorization": f"Bearer {os.environ['MINTRENDER_KEY']}"},    timeout=120,)body = res.json()if not res.ok:    raise RuntimeError(f"{body['error']['code']}: {body['error']['message']} ({body['error']['request_id']})")print(body)

Download a stored file with GET /v1/assets/{id}/file and your key. Delete an asset:

curl

curl -X DELETE "https://mintrender.com/v1/assets/img_9Lk2mQ8xP0aB4nC7vR2s" \  -H "Authorization: Bearer $MINTRENDER_KEY"

JavaScript

const res = await fetch("https://mintrender.com/v1/assets/img_9Lk2mQ8xP0aB4nC7vR2s", {  method: "DELETE",  headers: {    Authorization: `Bearer ${process.env.MINTRENDER_KEY}`,  },});const body = await res.json();if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message} (${body.error.request_id})`);console.log(body);

Python

import os import requests res = requests.delete(    "https://mintrender.com/v1/assets/img_9Lk2mQ8xP0aB4nC7vR2s",    headers={"Authorization": f"Bearer {os.environ['MINTRENDER_KEY']}"},    timeout=120,)body = res.json()if not res.ok:    raise RuntimeError(f"{body['error']['code']}: {body['error']['message']} ({body['error']['request_id']})")print(body)

A delete is refused with 409 in_use while a version of a template that is not deleted uses the asset. The message names the template and version. Before a delete, GET /v1/assets/{id}/uses lists up to 100 templates whose draft or versions use it:

curl

curl "https://mintrender.com/v1/assets/img_9Lk2mQ8xP0aB4nC7vR2s/uses" \  -H "Authorization: Bearer $MINTRENDER_KEY"

JavaScript

const res = await fetch("https://mintrender.com/v1/assets/img_9Lk2mQ8xP0aB4nC7vR2s/uses", {  method: "GET",  headers: {    Authorization: `Bearer ${process.env.MINTRENDER_KEY}`,  },});const body = await res.json();if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message} (${body.error.request_id})`);console.log(body);

Python

import os import requests res = requests.get(    "https://mintrender.com/v1/assets/img_9Lk2mQ8xP0aB4nC7vR2s/uses",    headers={"Authorization": f"Bearer {os.environ['MINTRENDER_KEY']}"},    timeout=120,)body = res.json()if not res.ok:    raise RuntimeError(f"{body['error']['code']}: {body['error']['message']} ({body['error']['request_id']})")print(body)
{  "templates": [    { "id": "tpl_3k2jQ8xLm0P4nB7vR2sT", "name": "Blog OG image", "draft": true, "versions": true }  ]}

Errors

StatusCodeWhen
400invalid_requestNo file field, or JSON without url.
400unsupported_typeNot a PNG, JPEG, GIF, WebP, SVG or UTF-8 CSV.
400invalid_svgThe SVG cannot be read or has no size.
400image_too_largeThe image is over 16 megapixels.
400url_refusedWe do not fetch this URL. The message says why.
400url_failedThe URL answered with a status that is not 2xx.
402plan_limitThe workspace's uploads would pass 500 MB on Free or 10 GB on a paid plan.
404not_foundNo such asset.
409in_useA version of a template that is not deleted uses the asset.
413too_largeAn image over 20 MB or a CSV over 5 MB.
451frozenThe workspace is frozen.

Seen MintRender used for content that breaks our terms? Report it. Questions about the API: support@mintrender.com, with the request id.