# Vectorize

One call: an image in, its SVG out, waited for in the same request.

### Vectorize an image

`POST /v1/vectorize`

Converts one image and hands you its SVG in the same request. Send exactly one of `file` (multipart), `url` or `inputKey`. If it finishes within `wait` seconds the answer is 200 with the result and its files; otherwise 202 with the conversion, which finishes on its own (`Location` names it: read it, stream its events, or await your webhook). Every client MUST handle the 202: most images take seconds, a few take minutes. It always UNLOCKS: 1 credit per image, held now and refunded if the conversion fails; an image already unlocked costs nothing again. Past your limit of conversions at once it waits its turn instead of refusing. Test keys: free (the sample result). With `Accept: image/svg+xml` a finished conversion answers 303 to the web file itself.

| Field | In | Type | Required | What |
| --- | --- | --- | --- | --- |
| `Idempotency-Key` | header | string | no | Retry safely: the same key answers the conversion it already made, never a second one and never a second charge (8–200 letters, digits and `._:~-`). The same key with another image is 409 `idempotency_key_reused`. |
| `Accept` | header | string | no | `image/svg+xml`: a finished conversion answers 303 to its web file. Follow it to take the file. |
| `url` | body | string | no | An https link to the image: we fetch it, up to 10 MB in 10 seconds, public addresses only, at most 3 redirects. |
| `inputKey` | body | string | no | An upload you already made (POST /uploads), for files up to 10 MB. |
| `wait` | body | integer, 0 to 60 | no | Seconds to hold the request open for the result. 0 answers at once (202): use it with a webhook. |
| `preset` | body | one of `default` | no |  |
| `options` | body | object | no | Optional choices about this image beside its preset. `{}` for none. Two conversions share a cached result only with the same options. Not offered yet: `merge` (a redraw that merges two colors is not offered yet; merge them in the Colors tab, or ask for fewer colors). |
| `filename` | body | string | no | OPTIONAL: the image's name, kept as its label and the download's name. Default: the file's or the URL's own. |

The body may also be sent as `multipart/form-data`, the image as its `file` part.

curl:

```bash
curl -X POST https://api.vecsnap.com/v1/vectorize \
  -H "Authorization: Bearer $VECSNAP_API_KEY" \
  -F file=@logo.png
```

Node.js:

```js
import { readFile, writeFile } from "node:fs/promises";
import { VecSnap } from "@vecsnap/sdk";

const vecsnap = new VecSnap(); // reads VECSNAP_API_KEY
const result = await vecsnap.vectorize({ file: await readFile("logo.png"), filename: "logo.png" });
await writeFile("logo.svg", await vecsnap.download(result));
console.log(`${result.result?.anchorPoints} anchor points`);
```

Python:

```python
from vecsnap import VecSnap

vecsnap = VecSnap()  # reads VECSNAP_API_KEY
result = vecsnap.vectorize(file=open("logo.png", "rb").read(), filename="logo.png")
open("logo.svg", "wb").write(vecsnap.download(result))
print(result["result"]["anchorPoints"], "anchor points")
```

Answer 200:

```json
{
  "object": "conversion",
  "id": "00000000-0000-4000-8000-000000000000",
  "livemode": false,
  "status": "completed",
  "phase": null,
  "preset": "default",
  "options": {},
  "imageId": "00000000-0000-4000-8000-000000000001",
  "filename": "logo",
  "inputFormat": null,
  "unlocked": true,
  "allowance": "credit",
  "engineVersion": "sample-27a924dbb20e",
  "result": {
    "anchorPoints": 29,
    "fileSize": 550,
    "formats": [
      {
        "background": "dropped",
        "bytes": 550,
        "currentColor": false,
        "default": true,
        "editableText": false,
        "id": "web",
        "profile": "web"
      },
      {
        "background": "kept",
        "bytes": 600,
        "currentColor": false,
        "default": false,
        "editableText": false,
        "id": "web-background",
        "profile": "web"
      },
      {
        "background": "dropped",
        "bytes": 759,
        "currentColor": false,
        "default": true,
        "editableText": false,
        "id": "design",
        "profile": "design"
      },
      {
        "background": "kept",
        "bytes": 823,
        "currentColor": false,
        "default": false,
        "editableText": false,
        "id": "design-background",
        "profile": "design"
      }
    ]
  },
  "failure": null,
  "inputDeletedAt": null,
  "createdAt": "2026-10-24T12:00:00.000Z",
  "updatedAt": "2026-10-24T12:00:00.000Z",
  "files": {
    "web": "https://files.vecsnap.com/…/web.svg",
    "web-background": "https://files.vecsnap.com/…/web-background.svg",
    "design": "https://files.vecsnap.com/…/design.svg",
    "design-background": "https://files.vecsnap.com/…/design-background.svg"
  },
  "filesExpireAt": "2026-10-24T12:00:00.000Z"
}
```

Answer 202:

```json
{
  "object": "conversion",
  "id": "00000000-0000-4000-8000-000000000000",
  "livemode": false,
  "status": "completed",
  "phase": null,
  "preset": "default",
  "options": {},
  "imageId": "00000000-0000-4000-8000-000000000001",
  "filename": "logo",
  "inputFormat": null,
  "unlocked": true,
  "allowance": "credit",
  "engineVersion": "sample-27a924dbb20e",
  "result": {
    "anchorPoints": 29,
    "fileSize": 550,
    "formats": [
      {
        "background": "dropped",
        "bytes": 550,
        "currentColor": false,
        "default": true,
        "editableText": false,
        "id": "web",
        "profile": "web"
      },
      {
        "background": "kept",
        "bytes": 600,
        "currentColor": false,
        "default": false,
        "editableText": false,
        "id": "web-background",
        "profile": "web"
      },
      {
        "background": "dropped",
        "bytes": 759,
        "currentColor": false,
        "default": true,
        "editableText": false,
        "id": "design",
        "profile": "design"
      },
      {
        "background": "kept",
        "bytes": 823,
        "currentColor": false,
        "default": false,
        "editableText": false,
        "id": "design-background",
        "profile": "design"
      }
    ]
  },
  "failure": null,
  "inputDeletedAt": null,
  "createdAt": "2026-10-24T12:00:00.000Z",
  "updatedAt": "2026-10-24T12:00:00.000Z"
}
```

Answer 402:

```json
{
  "error": {
    "code": "insufficient_credits",
    "message": "There are not enough credits for this unlock. None was spent.",
    "requestId": "req_8Gq2Lw0fTz1kVb6s"
  }
}
```

Answer 404:

```json
{
  "error": {
    "code": "not_found",
    "message": "There is nothing at that id for this caller.",
    "requestId": "req_8Gq2Lw0fTz1kVb6s"
  }
}
```

| Status | Code | What to do |
| --- | --- | --- |
| 402 | `insufficient_credits` | Buy credits, then send the same request again. |
| 402 | `unlock_required` | Unlock it (1 credit, once per image), then download. |
| 404 | `not_found` | Check the id. Another account's objects read as not found too. |
| 409 | `conversion_failed` | Convert the image again. Converting is free. |
| 409 | `idempotency_key_reused` | Make a new key for a new request. |
| 409 | `unlock_pending` | Wait for that conversion to finish. |
| 429 | `free_capacity_reached` | Come back after Retry-After (UTC midnight), or unlock with a credit. |
| 429 | `free_limit_reached` | Come back after Retry-After (UTC midnight), or unlock with a credit. |

Every other refusal it may answer: `dimensions_too_large` (400), `file_empty` (400), `file_too_large` (400), `invalid_idempotency_key` (400), `invalid_input_key` (400), `invalid_options` (400), `invalid_request` (400), `invalid_size` (400), `invalid_url` (400), `malformed_body` (400), `malformed_image` (400), `unknown_preset` (400), `unsupported_type` (400), `url_unreachable` (400), `invalid_api_key` (401), `unauthenticated` (401), `account_required` (403), `email_unverified` (403), `plan_required` (403), `account_exists` (409), `email_refused` (422), `rate_limited` (429), `internal_error` (500), `auth_unavailable` (503).

---
This page: https://vecsnap.com/docs/api/vectorize
