# Waiting for results, or working async

How long POST /v1/vectorizations waits, how to answer at once, and how to poll.

> **Coming soon:** The Developer API opens soon. You can read the docs now; API keys arrive when it opens.

`POST /v1/vectorizations` can wait for the conversion to finish, or answer at once. You choose with
the `Prefer` header ([RFC 7240](https://www.rfc-editor.org/rfc/rfc7240)).

## The `Prefer` header

| You send | The API waits up to | `Preference-Applied` |
|---|---|---|
| nothing | 120 seconds | not sent |
| `Prefer: wait=30` | 30 seconds (any value from 1 to 120; `0` counts as 1, larger values as 120) | `wait=30` |
| `Prefer: respond-async` | 0: it answers at once | `respond-async` |
| `Prefer: respond-async, wait=30` | 30 seconds, then it answers async | `respond-async, wait=30` |

The rule is always the same:

- **Finished within the wait → `201 Created`** with the finished object. A failed conversion is
  finished too: `201` with `"status": "failed"`.
- **Not finished → `202 Accepted`** with the object (`"status": "queued"` or `"processing"`), a
  `Location` header such as `/v1/vectorizations/vec_…`, and `Retry-After: 2`.

A request that is already finished when it is accepted, such as every test-mode request, answers
`201` even with `respond-async`; `Preference-Applied` then leaves `respond-async` out. When the
service is busy, it may answer `202` at once instead of waiting; it then sends no
`Preference-Applied` header.

## Poll for the result

After a `202`, call `GET /v1/vectorizations/{id}` about every 2 seconds until `status` is no longer
`queued` or `processing`:

| `status` | Meaning |
|---|---|
| `queued` | Accepted; not started yet. |
| `processing` | Running. |
| `succeeded` | Finished. The SVG is ready: see [Results](/docs/api/results). |
| `failed` | Finished without an SVG. The result's `error` says why. No credit was used. |

(`partially_succeeded` is reserved for requests with several results; a v1 request has one.)

Polling is free. Every 2 seconds is 30 requests a minute, well within the read limit (see
[Limits](/docs/api/limits)).

## Set your client's timeout

With the default wait, a request can stay open for up to 120 seconds. Set your HTTP client's
timeout above that, for example 130 seconds, or send `Prefer: wait=N` with a shorter wait. Some
defaults are much shorter: Python's `httpx` gives up after 5 seconds and .NET's `HttpClient` after
100 seconds. Python's `requests` has no timeout unless you set one.

## If the connection drops

The conversion keeps running, and it is charged if it succeeds. To get it:

- call `GET /v1/vectorizations/{id}` if you have its `id`; or
- send the same `POST` again with the same `Idempotency-Key`. You get the same conversion in its
  current state, and it is not charged again (see [Idempotency](/docs/api/idempotency)).

Without an `Idempotency-Key` and without the `id`, you cannot find the conversion again: there is no
list endpoint. Always send an `Idempotency-Key`.

## Get the SVG in the response

Send `Accept: image/svg+xml`. When the conversion succeeded within the wait, the `201` body is the
SVG itself, with the download headers described in [Results](/docs/api/results). In every other
case (`202`, a failed conversion, an error) the body is JSON, whatever `Accept` says. Check the
`Content-Type` header before you save the body. If your `Accept` header ranks JSON as high as SVG,
you get JSON.

## One conversion at a time

Each account runs one live conversion at a time. A second `POST` while one is running answers
`429 too_many_in_flight` with `Retry-After: 5`, or `402 insufficient_credits` when your available
credits cover only the running conversion. Send the next image when the running one has finished. Higher limits are available on request: see [Limits](/docs/api/limits).

[Site index](https://perfectvector.com/llms.txt) — available pages and descriptions.
