API reference, v1
VectoSolve API
Base URL https://vectosolve.com/api/v1. JSON in, JSON out, except /vectorize which takes a multipart form. Building a platform integration? See the Platform plan. The machine-readable spec is at /openapi.json.
Authentication
Create a key in your dashboard (up to 5 per account). Keys start with vs_ and are shown once. Send it as a bearer token on every call. A key can be locked to a list of browser origins; server-to-server calls are never blocked by that lock.
curl https://vectosolve.com/api/v1/credits \
-H "Authorization: Bearer vs_your_key"A missing, revoked or mistyped key answers 401 with { "success": false, "error": "Invalid or inactive API key" }.
Vectorize one image
POST /vectorize, multipart form. Send file (PNG, JPG, WebP, GIF) or image_url (public https link).
| Field | Values | Default |
|---|---|---|
mode | standard, laser, cricut, embroidery, centerline | standard |
output_format | svg, dxf | svg |
exports | comma list of pdf, eps, ai, png, returned in the same response | none |
dxf_version, units | R12 or AC1015; mm, cm or in | R12, mm |
colors, palette | limit the number of colors, or force a palette | automatic |
verify | true: adds a fidelity report against the source | false |
curl https://vectosolve.com/api/v1/vectorize \
-H "Authorization: Bearer vs_your_key" \
-F image_url=https://example.com/logo.png \
-F mode=laser -F output_format=dxf{
"success": true,
"data": {
"svg": "<svg ...>",
"dxf": "0\nSECTION ...", // when output_format=dxf
"svg_url": "https://...",
"format": "dxf",
"mode": "laser",
"source_quality": { ... },
"processing_time_ms": 6200
}
}Batch
POST /batch, JSON. Up to 25 images per call, 3 processed in parallel. Each item takes a public url, an operation (vectorize, remove_bg, upscale) and an optional mode(standard, laser, cricut, embroidery). Failed items are refunded; the others are charged.
curl https://vectosolve.com/api/v1/batch \
-H "Authorization: Bearer vs_your_key" \
-H "Content-Type: application/json" \
-d '{
"mode": "standard",
"images": [
{ "url": "https://example.com/a.png", "operation": "vectorize" },
{ "url": "https://example.com/b.jpg", "operation": "vectorize", "mode": "cricut" }
]
}'Background jobs
Add "async": true to a batch call to get 202 and a job_id right away, then poll GET /jobs/{job_id} or wait for the webhook. A job is processing, completed (with results) or failed.
{ "images": [ ... ], "async": true, "webhook_url": "https://your-app.com/hooks/vectosolve" }
GET https://vectosolve.com/api/v1/jobs/9b2c... -> { "status": "completed", "results": [ ... ], "webhook_status": "delivered" }Webhooks
When a background job ends we POST to your webhook_url (https only), with one retry after 30 seconds. Every call carries a VectoSolve-Signature header. Read your signing secret once with GET /webhook-secret, then check each call before trusting it.
POST https://your-app.com/hooks/vectosolve
VectoSolve-Signature: t=1762200000,v1=5f1c...
{ "event": "job.completed", "job_id": "9b2c...", "status": "completed",
"total_items": 25, "failed_items": 1, "created": 1762200000 }// Node.js: verify before using the payload
import { createHmac, timingSafeEqual } from 'node:crypto'
function verify(secret, rawBody, header) {
const { t, v1 } = Object.fromEntries(header.split(',').map((x) => x.split('=')))
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false
const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex')
return timingSafeEqual(Buffer.from(expected, 'hex'), Buffer.from(v1, 'hex'))
}Machine and print formats
POST /export converts an SVG you already have (svg_content) into another format: gcode, eps, ai, dst, pes, jef, pdf, png, dxf. GET /export lists the options of each format.
Balance
GET /credits is free and returns your balance, the conversions it covers and your limits. Call it before sending a large batch.
{ "success": true, "credits": { "balance": 27.27, "remaining_conversions": 136 },
"limits": { "per_minute": 60, "daily_spend_cap_usd": 5 } }Limits and idempotency
- 60 requests per minute per key by default. A batch counts one request per image. Over the limit:
429withRetry-After. - A daily spend cap protects your balance; it rises with your balance and plan. Platform accounts get custom limits.
- Images up to 10 MB. URLs must be public https links.
- Paid calls accept an
Idempotency-Keyheader: a retry with the same key within 24 hours returns the first result and is not charged twice.
Errors
400 | Invalid input: the error message names the field. |
401 | Missing or invalid API key. |
402 | Not enough credits. Nothing was charged. |
422 | The image could not be converted. Refunded. |
429 | Rate limit or daily spend cap reached. |
502 / 503 | Temporary upstream problem. Refunded; retry with the same Idempotency-Key. |
Billing
Self-serve keys draw on your credit balance: one vectorization costs 0.20 credit, the same as on the website. On the Platform plan, usage is billed monthly by Stripe: one billable file per successful vectorization (credits used divided by 0.20, at least 1 per request), 10,000 files included in the $499 minimum, then $0.05 per file. Every call is listed in your usage log.