Embossify API
Build image to STL into your own app, site or workflow.
Quick start
Send a request with an image address, check the status, then download the STL file. Every call goes to one address and answers in JSON. Only a successful download returns the STL itself.
Each volume embossment is one High resolution (HD) file, the same file you would buy on the website, in smooth or Pixel Grid style. It comes as STL, and as 3MF, GLB, PLY, OBJ and a heightmap PNG too: one code covers every format of the same file, so asking for another format costs nothing more. Ultra detail is a checkout add-on on the website and is not available through the API yet.
https://api.embossify.com/
1. Redeem
Starts the render. Each successful redeem uses one embossment from your volume embossment code.
curl "https://api.embossify.com/?cmd=redeem&thicker=lighter&width=120&depth=5&code=YOUR_VOLUME_EMBOSSMENT_CODE&imageurl=https%3A%2F%2Fwww.embossify.com%2Fassets%2Fimg%2Fmatsu.jpg"
{"success":BID_RETURNED_FROM_API}
// or, on a problem:
{"error":"An error message here"}2. Check the status
Poll until the status is complete. Please send no more than one status request per second.
curl "https://api.embossify.com/?cmd=status&bid=BID_RETURNED_FROM_API"
{"status":"working"}
{"status":"complete"}3. Download your file
If the file is not ready you get a JSON error instead of the file. Add &format=3mf (or glb, ply, obj, png8, png16) to get another format of the same file, as many times as you like, with no extra embossment used. Open the result in the free Embossify Lens to check it.
curl -o embossment.stl "https://api.embossify.com/?cmd=download&bid=BID_RETURNED_FROM_API"
The file itself (STL unless you asked for another format)
// or a JSON error if it is not readyCheck a code's balance
To see how many embossments a code has left, call cmd=balance with the code. Customers who prefer a web page can use the code balance page.
curl "https://api.embossify.com/?cmd=balance&code=YOUR_VOLUME_EMBOSSMENT_CODE"
{"code":"ABCD-EFGH-JKMN","remaining":42,"used":8,"total":50}
// or {"error": "..."} if the code is not foundParameters
Only the first six are needed. The optional settings match the controls on the image to STL converter and in Studio, so you can try them there for free first.
| Name | Used with | Description |
|---|---|---|
cmd | all | The command: redeem, status, download or balance. |
code | redeem, balance | Your volume embossment code. Get one here. |
imageurl | redeem | URL-encoded address of the image to Embossify (JPG, PNG, GIF, WebP, BMP and more; SVG is not accepted by the API, so export it as a PNG first). |
width | redeem | Width of the model in millimeters, 1 to 1999. |
depth | redeem | Relief height of the model in millimeters, 0.1 to 500. |
thicker | redeem | lighter (light pixels are high) or darker (dark pixels are high). |
quality | redeem | Optional. high (High resolution, HD: the default) or pixelgrid, the original Embossify style. Ultra detail is not available through the API yet. See Embossment types. |
| Other settings | redeem | Optional: base, frame, unit, sizeBy, shape, brightness, contrast, gamma, blackPoint, whitePoint, steps, smooth and sharpen. The same settings as the converter form, with the same limits. Anything left out uses the default. |
format | download | Optional. stl (the default), 3mf, glb, ply, obj, png8 or png16 (CNC heightmaps). Every format of the same file is covered by the one embossment. OBJ is not offered for very large files. |
bid | status, download | The ID returned by a successful redeem. |
Full examples
Each example does the whole job: it starts a render, waits for it to finish, and saves the STL file. Replace YOUR_VOLUME_EMBOSSMENT_CODE with your code and the image address with your own.
cURL (bash)
#!/usr/bin/env bash # Starts an Embossify render, waits for it to finish, and saves the STL. # Needs only bash and curl. Replace CODE and IMAGE, then run: bash embossify.sh set -euo pipefail API="https://api.embossify.com/" CODE="YOUR_VOLUME_EMBOSSMENT_CODE" IMAGE="https://www.embossify.com/assets/img/matsu.jpg" # 1. Start the render (this uses one embossment from your code) RESPONSE=$(curl -sG "$API" \ --data-urlencode "cmd=redeem" \ --data-urlencode "code=$CODE" \ --data-urlencode "imageurl=$IMAGE" \ --data-urlencode "width=120" \ --data-urlencode "depth=5" \ --data-urlencode "thicker=lighter") BID=$(echo "$RESPONSE" | grep -o '"success":"[^"]*"' | cut -d'"' -f4 || true) if [ -z "$BID" ]; then echo "Could not start the render: $RESPONSE" >&2 exit 1 fi # 2. Wait until it is ready (please keep to one request per second or slower) until curl -s "$API?cmd=status&bid=$BID" | grep -q '"complete"'; do sleep 2 done # 3. Download the STL curl -s -o embossment.stl "$API?cmd=download&bid=$BID" echo "Saved embossment.stl"
Python
# Starts an Embossify render, waits for it to finish, and saves the STL.
# Needs Python 3 and the requests package (pip install requests).
import time
import requests
API = "https://api.embossify.com/"
CODE = "YOUR_VOLUME_EMBOSSMENT_CODE"
IMAGE = "https://www.embossify.com/assets/img/matsu.jpg"
# 1. Start the render (this uses one embossment from your code)
started = requests.get(API, params={
"cmd": "redeem",
"code": CODE,
"imageurl": IMAGE,
"width": 120,
"depth": 5,
"thicker": "lighter",
}, timeout=60).json()
if "error" in started:
raise SystemExit(started["error"])
bid = started["success"]
# 2. Wait until it is ready (please keep to one request per second or slower)
while True:
status = requests.get(API, params={"cmd": "status", "bid": bid}, timeout=30).json()
if "error" in status:
raise SystemExit(status["error"])
if status.get("status") == "complete":
break
time.sleep(2)
# 3. Download the STL
with requests.get(API, params={"cmd": "download", "bid": bid}, stream=True, timeout=300) as download:
download.raise_for_status()
with open("embossment.stl", "wb") as out:
for chunk in download.iter_content(chunk_size=256 * 1024):
out.write(chunk)
print("Saved embossment.stl")JavaScript (Node.js)
// Starts an Embossify render, waits for it to finish, and saves the STL.
// Needs Node.js 18 or newer (built-in fetch). Save as embossify.mjs and run: node embossify.mjs
import { createWriteStream } from "node:fs";
import { Readable } from "node:stream";
import { pipeline } from "node:stream/promises";
const API = "https://api.embossify.com/";
const CODE = "YOUR_VOLUME_EMBOSSMENT_CODE";
const IMAGE = "https://www.embossify.com/assets/img/matsu.jpg";
const url = (params) => `${API}?${new URLSearchParams(params)}`;
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
// 1. Start the render (this uses one embossment from your code)
const started = await (await fetch(url({
cmd: "redeem", code: CODE, imageurl: IMAGE, width: 120, depth: 5, thicker: "lighter",
}))).json();
if (started.error) throw new Error(started.error);
const bid = started.success;
// 2. Wait until it is ready (please keep to one request per second or slower)
while (true) {
const status = await (await fetch(url({ cmd: "status", bid }))).json();
if (status.error) throw new Error(status.error);
if (status.status === "complete") break;
await sleep(2000);
}
// 3. Download the STL
const download = await fetch(url({ cmd: "download", bid }));
if (!download.ok) throw new Error(`Download failed (HTTP ${download.status})`);
await pipeline(Readable.fromWeb(download.body), createWriteStream("embossment.stl"));
console.log("Saved embossment.stl");PHP
<?php
// Starts an Embossify render, waits for it to finish, and saves the STL.
// Needs PHP 7.4 or newer with allow_url_fopen on (the default). Run: php embossify.php
$api = "https://api.embossify.com/";
$code = "YOUR_VOLUME_EMBOSSMENT_CODE";
$image = "https://www.embossify.com/assets/img/matsu.jpg";
function call(string $api, array $params): array
{
$json = file_get_contents($api . "?" . http_build_query($params));
return json_decode((string) $json, true) ?: ["error" => "No answer from the API"];
}
// 1. Start the render (this uses one embossment from your code)
$started = call($api, [
"cmd" => "redeem",
"code" => $code,
"imageurl" => $image,
"width" => 120,
"depth" => 5,
"thicker" => "lighter",
]);
if (isset($started["error"])) {
exit($started["error"] . "\n");
}
$bid = $started["success"];
// 2. Wait until it is ready (please keep to one request per second or slower)
do {
sleep(2);
$status = call($api, ["cmd" => "status", "bid" => $bid]);
if (isset($status["error"])) {
exit($status["error"] . "\n");
}
} while (($status["status"] ?? "") !== "complete");
// 3. Download the STL
$in = fopen($api . "?" . http_build_query(["cmd" => "download", "bid" => $bid]), "rb");
$out = fopen("embossment.stl", "wb");
stream_copy_to_stream($in, $out);
fclose($in);
fclose($out);
echo "Saved embossment.stl\n";C#
// Starts an Embossify render, waits for it to finish, and saves the STL.
// Needs .NET 6 or newer. Create a console app (dotnet new console), paste this into Program.cs, then: dotnet run
using System.Text.Json;
const string Api = "https://api.embossify.com/";
const string Code = "YOUR_VOLUME_EMBOSSMENT_CODE";
const string Image = "https://www.embossify.com/assets/img/matsu.jpg";
using var http = new HttpClient { Timeout = TimeSpan.FromMinutes(10) };
async Task<JsonElement> Call(string query)
{
var json = await http.GetStringAsync($"{Api}?{query}");
return JsonDocument.Parse(json).RootElement;
}
// 1. Start the render (this uses one embossment from your code)
var started = await Call($"cmd=redeem&code={Uri.EscapeDataString(Code)}&imageurl={Uri.EscapeDataString(Image)}&width=120&depth=5&thicker=lighter");
if (started.TryGetProperty("error", out var startError))
throw new Exception(startError.GetString());
var bid = started.GetProperty("success").ToString();
// 2. Wait until it is ready (please keep to one request per second or slower)
while (true)
{
var status = await Call($"cmd=status&bid={bid}");
if (status.TryGetProperty("error", out var statusError))
throw new Exception(statusError.GetString());
if (status.GetProperty("status").GetString() == "complete")
break;
await Task.Delay(2000);
}
// 3. Download the STL
await using var stream = await http.GetStreamAsync($"{Api}?cmd=download&bid={bid}");
await using var file = File.Create("embossment.stl");
await stream.CopyToAsync(file);
Console.WriteLine("Saved embossment.stl");Go
// Starts an Embossify render, waits for it to finish, and saves the STL.
// Needs Go 1.18 or newer. Save as main.go and run: go run main.go
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"os"
"time"
)
const (
api = "https://api.embossify.com/"
code = "YOUR_VOLUME_EMBOSSMENT_CODE"
image = "https://www.embossify.com/assets/img/matsu.jpg"
)
func call(params url.Values) map[string]any {
resp, err := http.Get(api + "?" + params.Encode())
if err != nil {
panic(err)
}
defer resp.Body.Close()
var out map[string]any
if err := json.NewDecoder(resp.Body).Decode(&out); err != nil {
panic(err)
}
if msg, failed := out["error"]; failed {
panic(msg)
}
return out
}
func main() {
// 1. Start the render (this uses one embossment from your code)
started := call(url.Values{
"cmd": {"redeem"},
"code": {code},
"imageurl": {image},
"width": {"120"},
"depth": {"5"},
"thicker": {"lighter"},
})
bid := fmt.Sprint(started["success"])
// 2. Wait until it is ready (please keep to one request per second or slower)
for call(url.Values{"cmd": {"status"}, "bid": {bid}})["status"] != "complete" {
time.Sleep(2 * time.Second)
}
// 3. Download the STL
resp, err := http.Get(api + "?" + url.Values{"cmd": {"download"}, "bid": {bid}}.Encode())
if err != nil {
panic(err)
}
defer resp.Body.Close()
file, err := os.Create("embossment.stl")
if err != nil {
panic(err)
}
defer file.Close()
if _, err := io.Copy(file, resp.Body); err != nil {
panic(err)
}
fmt.Println("Saved embossment.stl")
}Good to know
- The API address is just
https://api.embossify.com/. There is no file name to add (https://api.embossify.com/also works). The olderhttps://api.embossify.com/keeps working for existing integrations, but new ones should use the api address. - Send your code with POST. The examples work with GET, but an address is written to web server logs, so a code in it can be read by anyone with log access. A POST body is not logged. Never put a code in a link you share.
- Use HTTPS and send a descriptive
User-Agent(the name of your program) so we can tell your calls apart. - Limits. Please send no more than one status request per second. An address that sends 10 wrong codes in an hour is paused for the rest of the hour, and a single address may start up to 120 renders an hour.
- Every call is logged (time, address, command and a fingerprint of the code, never the code itself) so problems can be traced. Addresses that guess codes or flood the API are blocked; if you think that happened to you by mistake, contact support with your address.
- One code, every format. An embossment covers the High resolution file in any format: ask for the same
bidagain with anotherformat.
When something goes wrong
You are charged for embossments that are built, not for failures on our side.
- Mistakes in your request cost nothing. A use of your code is taken only after the request has been checked: the code is valid, the parameters are valid and the picture could be fetched. A bad code, a wrong parameter or an unreachable image URL is refused before anything is taken.
- If our build fails, the use is credited back automatically. The
statuscall for thatbidreturns an error saying the use was credited back, andcmd=balanceshows it again. Just send the request again. A use is credited back once perbid, never twice. - If a file arrives but is wrong because of something on our side (a broken or empty file, for example), contact support within 30 days with the
bidand we will credit the use back by hand. - Not credited: a file that was built correctly from the parameters you sent, even if it is not what you hoped for. Try the same picture free first on the website (Standard resolution costs nothing) to check settings before you spend a use.
- Sending the same request twice builds two embossments and takes two uses. Keep the
bidyou get back and usestatusanddownloadwith it instead of repeating the request.
Need help?
Read the FAQ for embossment types and settings, or contact support with any questions about the API. Need a code first? See volume embossment codes.