PSD to SVG API
POST a .psd to /v2/convert/psd/to/svg: the API merges the visible layers, traces the result and returns SVG paths. With default settings the sticker became 64 filled paths in 41 colors, 26,655 bytes.
- Endpoint
- POST /v2/
convert/ psd/ to/ svg - Accepts
- psd
- Sample timing
- 0.102 s median of 5 runsHow we measure
- Request size
- Up to 10 MB on the Free plan or 100 MB on paid plans, all files together
Request and response
Every sample below ran against the API before this page was published. Set PDFCONVERSIONAPI_KEY to your key and run it as is.
curl -sS -X POST \
https://api.pdfconversionapi.com/v2/convert/psd/to/svg \
-H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
-F File=@night-market-sticker.psd \
-o response.json
# FileData is base64. Save the first file in converted/,
# or print the JSON error.
if jq -e '.Files' response.json > /dev/null; then
mkdir -p converted
name=$(jq -r '.Files[0].FileName' response.json)
jq -r '.Files[0].FileData' response.json \
| base64 --decode > "converted/$name"
else
cat response.json
fiimport base64
import os
import requests
key = os.environ["PDFCONVERSIONAPI_KEY"]
response = requests.post(
"https://api.pdfconversionapi.com/v2/convert/psd/to/svg",
headers={"Authorization": f"Bearer {key}"},
files=[("File", open("night-market-sticker.psd", "rb"))],
timeout=180,
)
result = response.json()
if not response.ok:
raise SystemExit(f"{result['Code']}: {result['Message']}")
os.makedirs("converted", exist_ok=True)
for file in result["Files"]:
path = os.path.join("converted", file["FileName"])
with open(path, "wb") as out:
out.write(base64.b64decode(file["FileData"]))
print(path, file["FileSize"], "bytes")
import { mkdir, readFile, writeFile } from "node:fs/promises";
import { join } from "node:path";
const form = new FormData();
const file = "night-market-sticker.psd";
form.append("File", new Blob([await readFile(file)]), file);
const url = "https://api.pdfconversionapi.com/v2/convert/psd/to/svg";
const key = process.env.PDFCONVERSIONAPI_KEY;
const response = await fetch(url, {
method: "POST",
headers: { Authorization: `Bearer ${key}` },
body: form,
});
const result = await response.json();
if (!response.ok) {
throw new Error(`${result.Code}: ${result.Message}`);
}
await mkdir("converted", { recursive: true });
for (const file of result.Files) {
const path = join("converted", file.FileName);
await writeFile(path, Buffer.from(file.FileData, "base64"));
console.log(path, file.FileSize, "bytes");
}
{
"ConversionCost": 1,
"ConversionTime": 0.102,
"Files": [
{
"FileName": "night-market-sticker.svg",
"FileExt": "svg",
"FileSize": 26655,
"FileData": "PD94bWwgdmVyc2lvbj0iMS4w…"
}
]
}Response from our test run on 2026-11-03. ConversionTime shows the median of 5 runs. FileData is shortened here; the real response carries the whole file as base64.
The sample, converted
The same file the code sends. Download the input and the output and compare them yourself.

- Input
- night-market-sticker.psd (173 KB)
- Output
- night-market-sticker.svg (26 KB)
- Source
- A layered event sticker we drew for this site: 400 x 300 pixels, 8 bits per channel, transparent around the sticker, with seven layers including a soft shadow, a Screen-blended moon, a two-layer text group and a hidden draft stamp. Written as a PSD by our own script from the published file format specification. (CC0-1.0). How it was made
- Made by
- 2026-11-04, API build
9eeeb0640aba
Parameters
Send these as form fields next to the file. Names are case-insensitive. If you set one of the documented options below that we don't support yet, the request fails with a 400 that names it instead of returning a file made without it.
| Parameter | What it does |
|---|---|
Presetenum, default none | Bundles of the settings below. On the sticker, bw gave 10 paths, photo 47 and poster 115. Options you send yourself take priority over the preset.Values: none, bw, poster, photo |
ColorModeenum, default color | bw traces a two-tone version: 10 paths, 15,435 bytes.Values: color, bw |
FilterSpeckleinteger, default 4 | Drops patches smaller than this many pixels. 0 kept everything, including the hyphen in "6-11", but made 2,666 paths and 205,011 bytes; 20 left 24 paths.Values: 0–128 |
ColorPrecisioninteger, default 6 | Bits per channel used to group colors. 3 merged similar shades: 63 paths, 22,594 bytes.Values: 1–8 |
GradientStepinteger, default 16 | Smallest color difference between stacked layers of the trace; 64 gave 58 paths.Values: 0–128 |
CurveModeenum, default spline | polygon writes straight segments only and cut the file to 8,101 bytes; pixel follows pixel edges (21,140 bytes).Values: spline, polygon, pixel |
CornerThresholdinteger, default 60 | Angle in degrees below which a joint stays a sharp corner; 120 gave 37,000 bytes.Values: 0–180 |
SegmentLengthnumber, default 4 | Length of curve segments; 8 gave 22,088 bytes. Values under 3.5 return 400.Values: 3.5–10 |
SpliceThresholdinteger, default 45 | Angle at which a spline is split; 90 gave 23,384 bytes.Values: 0–180 |
Layeringenum, default stacked | cutout makes shapes with holes instead of shapes painted over each other: 47 paths.Values: stacked, cutout |
ImageWidthinteger | Scales the merged image before tracing. 800 gave the tracer twice the width to work with: 209 paths, and the hyphen in "6-11" came back.Values: 1–20000 |
ImageHeightinteger | Scales by height before tracing; with a width it sets a box.Values: 1–20000 |
FileNamestring | Base name of the SVG. |
StoreFileboolean, default false | true returns a 3-hour link instead of the SVG text. |
Not supported yet
Setting one of these to anything but its default returns 400.
| Option | What to do instead |
|---|---|
ImageResolution | An SVG has no pixel resolution. ConvertAPI's default of 200 passes; other values return 400 'ImageResolution is not supported yet for PSD → SVG'. |
ColorSpace | Only default and truecolors pass, and both trace the same as leaving it out. gray, rgb and the rest return 400 'ColorSpace is not supported yet for PSD → SVG'; use ColorMode=bw for a two-tone trace. |
ImageQuality | 75 passes; other values return 400. |
What carries over, and what doesn't
Kept
- Flat colored shapes: the rounded card, the moon and the three lanterns trace as clean filled paths
- Large lettering: NIGHT MARKET stays readable at the default settings
- Clear areas: paths cover only the drawn part, and most of the transparent corners stay empty
- The canvas size, as
width="400"andheight="300"on the root element
Lost or not yet supported
- Soft transparency. The partly clear shadow is traced as a solid black shape, a hard edge where the PSD had a fade.
- Small marks. At the default
FilterSpeckleof 4 the hyphen in "6-11" disappeared; it also stayed lost at 1, 2 and withPreset=poster. - Exact color. Thin features such as the lantern string pick up neighbouring colors; rendered back to pixels, opaque areas differ by 3.1 levels on average.
- A
viewBox. The root element has only width and height, so add one before scaling the SVG with CSS.
Limits
- One PSD per request.
- Requests up to 10 MB on the Free plan or 100 MB on paid plans, all files and fields together.
- Tracing works on at most 12,000,000 pixels. A 4,001 × 3,000 PSD returned 413 'vectorizing is limited to 12,000,000 pixels, and this image is 4,001×3,000; set ImageWidth or ImageHeight to scale it down', and converted with
ImageWidth=4000. If the size you send is still too large, the message ends 'lower ImageWidth or ImageHeight' instead. - Up to 100,000,000 pixels after flattening before any scaling, or 413.
- 120 seconds per conversion, then 504.
- Type layers are not kept as text: the trace sees pixels only. Type layers, smart objects and layer effects were not in our test files.
Where teams use it
Stickers, decals and cut files
Flat artwork designed in PSD can become paths for vinyl cutters, laser engravers or print-on-demand sticker tools that want vectors. Use ColorMode=bw for single-color cuts.
Vector versions of simple graphics
Icons, badges and logos drawn as pixel layers can be traced to SVG for the web, where they scale without blurring. Check small lettering afterwards, or trace at a larger ImageWidth.
Questions
Are vector or text layers from the PSD kept as vectors?
No. The API flattens the visible layers into pixels first and traces that picture. Paths come from the tracer, not from shapes or type stored in the PSD.
Small text breaks apart. What helps?
Trace a larger copy. With ImageWidth=800 the sticker's details line kept its hyphen; at the default size it was dropped. FilterSpeckle=0 also keeps it, at the cost of 2,666 paths.
Why did the soft shadow turn black?
The tracer gives every shape one solid fill, with no transparency. Pixels that are partly see-through in the PSD become part of a solid dark shape. Hide the shadow layer before converting if you only want the flat art.
Convert your first PSD file in a minute.