Send an image, get a vector file back. One endpoint does the work; the rest manage keys, credits and billing.
Quickstart
Create an API key on your account page; new accounts start with 5 free credits. Then post an image to /v1/vectorize. The response body is the file.
curl https://svgmill.com/v1/vectorize \
-H "Authorization: Bearer $SVGMILL_KEY" \
-F image=@logo.png \
-F format=svg \
-D headers.txt -o logo.svg
# Same trace as a DXF, free: use the token from headers.txtcurl https://svgmill.com/v1/download \
-H "Authorization: Bearer $SVGMILL_KEY" \
-H "Content-Type: application/json" \
-d '{"token":"img_…","format":"dxf"}' -o logo.dxf
import os, requests
key = os.environ["SVGMILL_KEY"]
with open("logo.png", "rb") as f:
r = requests.post(
"https://svgmill.com/v1/vectorize",
headers={"Authorization": f"Bearer {key}"},
files={"image": f},
data={"format": "svg", "colors": "8"},
)
r.raise_for_status()
open("logo.svg", "wb").write(r.content)
print(r.headers["X-Image-Token"], r.headers["X-Credits-Remaining"])
import { readFile, writeFile } from "node:fs/promises";
const form = new FormData();
form.append("image", new Blob([await readFile("logo.png")]), "logo.png");
form.append("format", "svg");
const res = await fetch("https://svgmill.com/v1/vectorize", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.SVGMILL_KEY}` },
body: form,
});
if (!res.ok) throw new Error((await res.json()).error.message);
await writeFile("logo.svg", Buffer.from(await res.arrayBuffer()));
console.log(res.headers.get("x-image-token"), res.headers.get("x-credits-remaining"));
Every successful conversion returns three headers: X-Image-Token (use it to download other formats for free), X-Credits-Charged and X-Credits-Remaining.
Authentication
Send your key as a Bearer token: Authorization: Bearer svgmill_live_…. Live keys spend credits; test keys (svgmill_test_…) never do. Keys are shown once when you create them and stored only as a hash, so keep them somewhere safe and revoke any you think have leaked.
The website uses a browser session instead of a key. Both spend from the same balance.
Options and formats
Field
Values
What it does
image
file
PNG, JPG, WebP, GIF (first frame), BMP or TIFF, up to 30 MB and 16 megapixels. Or send image_url or image_base64 in a JSON body.
format
svgpdfepsdxfpng
The file you get back. Default svg.
preset
logobw
Color logo and art (default), or one-color black and white.
colors
2–64
Caps the palette. Fewer colors give simpler shapes.
mode
productionpreviewtest
Production costs 1 credit. Preview is free and returns a watermarked PNG. Test needs a test key.
token
string
In a JSON body, re-traces an earlier image with new options instead of uploading it again.
Test mode
Build your integration without spending credits. Create a test key on your account page and call the API as usual: conversions are free and the result carries a “SVGMILL TEST” watermark. Test mode returns SVG, or PNG with format=png. Downloads need a live key.
Without any key, mode=preview returns a free watermarked PNG and a token you can download later for 1 credit. Anonymous previews are limited to 20 an hour per IP address.
Errors
Errors always have the same shape, and a request that ends in an error uses no credit.
{ "error": { "code": "insufficient_credits", "message": "You have no credits left. Buy a pack or a plan to continue." } }
Code
Status
Meaning
invalid_request
400
A field is missing or out of range. The message says which.
unauthorized
401
No key or session, or the key was revoked.
insufficient_credits
402
No credits left.
forbidden
403
The key can’t do this, for example test mode with a live key.
account_frozen
403
The plan is frozen after a failed payment and there are no pack credits.
not_found
404
Unknown token, or its files are past the 30 days we keep them.
decode
422
The file isn’t a readable image.
too_large
422
Over 30 MB or 16 megapixels.
rate_limited
429
Too many requests. Wait for Retry-After seconds.
internal
500
Something failed on our side. Retry with the same Idempotency-Key.
timeout
504
The trace ran past its time limit. Try a smaller image or fewer colors.
out_of_memory
507
The image needs more memory than one job allows. Try a smaller image.
Rate limits
Each API key can make 60 requests a minute. Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (Unix seconds). A 429 adds Retry-After.
Idempotency
Every POST accepts an Idempotency-Key header. Repeat a request with the same key within 24 hours and you get the stored response instead of a second charge. Use it whenever you retry after a timeout or network error.
Endpoint reference
Base URL https://svgmill.com. Generated from openapi.json (OpenAPI 3.1.0).
Vectorize
POST/v1/vectorizeOptional: API key or browser session
Convert an image to a vector.production (default) costs 1 credit and returns the file. preview is free, works anonymously and returns a watermarked PNG whose token can be downloaded later for 1 credit. test is free, needs a test key and returns a watermarked result. A failed trace is never charged. Send a JSON token to re-trace an earlier image with new options (1 credit).
Multipart body
Field
Type
Notes
imagerequired
file
mode
production | preview | test
Default production.
preset
logo | bw
Default logo.
colors
integer
2–64.
format
svg | pdf | eps | dxf | png
Default svg.
JSON body
Field
Type
Notes
image_url
string (uri)
image_base64
string
Raw base64 or a data: URL.
token
string
Re-trace an earlier image.
mode
production | preview | test
Default production.
preset
logo | bw
Default logo.
colors
integer
2–64.
format
svg | pdf | eps | dxf | png
Default svg.
Responses
200 The vector file (or the preview PNG). See X-Image-Token, X-Credits-Charged, X-Credits-Remaining.
402 No credits
403 Frozen plan and no pack credits, or test mode without a test key
422 Not a readable image, or too large
429 Rate limited
Accepts an Idempotency-Key header.
POST/v1/downloadAPI key or browser session
Download a format of an earlier trace. The first paid download of a preview token costs 1 credit. Every other format, and any later download of a paid token, is free.
JSON body
Field
Type
Notes
tokenrequired
string
format
svg | pdf | eps | dxf | png
Default svg.
Responses
200 The file
401 Not signed in
402 No credits
404 Unknown or expired token
429 Rate limited
Accepts an Idempotency-Key header.
GET/v1/conversionsAPI key or browser session
Conversion history. Newest first. Files are removed after 30 days; rows stay.
Parameters
Name
In
Notes
cursor
query
next_cursor from the previous page.
limit
query
1–100, default 50.
Responses
200 A page of conversions
401 Not signed in
429 Rate limited
Account
POST/v1/registerNo auth
Create an account. Sends a verification link. A known email gets a sign-in link instead. Always 202, so the response does not reveal which emails exist. Disposable domains get 422.
JSON body
Field
Type
Notes
emailrequired
string (email)
return_to
string
Same-origin page to return to after the link (web app).
Responses
202 Link sent
422 Disposable email domain
429 Rate limited
Accepts an Idempotency-Key header.
GET/v1/verifyNo auth
Open an email link. Verifies the email, grants 5 signup credits on the first verification only, and starts a session. With a return_to from registration it redirects there (web app); otherwise it shows the first live API key once (JSON with Accept: application/json).
Parameters
Name
In
Notes
tokenrequired
query
The token from the email link.
Responses
200 Key page (HTML) or JSON
302 Redirect to return_to (web app)
400 Expired or used link
429 Rate limited
POST/v1/loginNo auth
Send a sign-in link. Same flow as register. Existing accounts get no credits.
JSON body
Field
Type
Notes
emailrequired
string (email)
return_to
string
Same-origin page to return to after the link (web app).
Responses
202 Link sent
429 Rate limited
Accepts an Idempotency-Key header.
POST/v1/logoutbrowser session
End the browser session.
Responses
200 Signed out
401 Not signed in
429 Rate limited
Accepts an Idempotency-Key header.
GET/v1/accountAPI key or browser session
Balance, grants, plan and usage.
Responses
200 Account
401 Not signed in
429 Rate limited
DELETE/v1/accountAPI key or browser session
Delete the account. Deletes the user, keys, sessions and stored files, and cancels any plan. Ledger rows are anonymised.
Responses
200 Deleted
401 Not signed in
429 Rate limited
Keys
GET/v1/keysAPI key or browser session
List API keys.
Responses
200 Active keys
401 Not signed in
429 Rate limited
POST/v1/keysAPI key or browser session
Create an API key. The secret is returned once and stored only as a SHA-256 hash.
JSON body
Field
Type
Notes
label
string
test
boolean
Default false.
Responses
201 The new key, with its secret
401 Not signed in
429 Rate limited
Accepts an Idempotency-Key header.
DELETE/v1/keys/{id}API key or browser session
Revoke an API key.
Parameters
Name
In
Notes
idrequired
path
Responses
200 Revoked
401 Not signed in
429 Rate limited
Billing
GET/v1/plansNo auth
Packs and plans.
Responses
200 The catalogue
429 Rate limited
POST/v1/checkoutAPI key or browser session
Start a Stripe Checkout. Packs use a one-off payment, plans a subscription. Tax is calculated by Stripe.
JSON body
Field
Type
Notes
itemrequired
string
Responses
200 Checkout URL
401 Not signed in
409 Already on a plan (use /v1/subscription)
429 Rate limited
Accepts an Idempotency-Key header.
GET/v1/purchasesAPI key or browser session
Packs bought and invoices paid.
Responses
200 Purchases
401 Not signed in
429 Rate limited
GET/v1/subscriptionAPI key or browser session
Current plan.
Responses
200 Plan or null
401 Not signed in
429 Rate limited
POST/v1/subscriptionAPI key or browser session
Cancel, resume, change or reactivate the plan.cancel takes effect at the period end. change {item}: upgrades are immediate, billed pro rata, and the extra credits for the rest of this month are granted now; downgrades take effect at the period end. reactivate works only from inactive: it pays the outstanding invoice first, then returns a Checkout URL for a new subscription.