viewa/docs
API Reference

Upload a photo

POST
/images

Send the photo, get back an image resource that is already preprocessing. One request — the file goes in the body; there is no separate upload step against storage. JPEG, PNG and WebP only, 4MB maximum. Both limits are enforced against the bytes actually sent: the declared content type is not trusted, so a file that decodes as anything else is rejected even when it is labeled as one of the three. The photo is resized server-side before preprocessing, so width and height on the response describe the stored image, not your original. Preprocessing begins immediately but does not block this call — poll the returned resource until it is ready. This is the one pipeline call that never requires a visitor token on any instance, and it is where tokens come from. Sent without X-Viewa-Visitor-Token, it mints a new anonymous shopper and returns visitor on the created image. Sent with one, the upload attaches to that existing shopper — their earlier images, areas, renders and history stay reachable — and visitor comes back with a refreshed expiresAt. Either way the block is present, so the client always has a current token to store.

Authorization

AuthorizationBearer <token>

Publishable key (browser-safe), sent as Authorization: Bearer pk_…. This is the lower API-key tier and is sufficient for browser-safe routes that require the pk tier. Requests using a publishable key are additionally validated against the key's domain allowlist via the Origin header. Used for upload, areas, renders, polling, catalog reads, and history (history additionally requires a visitor token).

In: header

Header Parameters

Idempotency-Key?string

Repeat this value to retry an upload safely: the retry returns the image the first call created instead of processing the photo again, together with the visitor that upload created — which is how a client recovers when the original response was lost. Scoped to your instance, so your keys never collide with another integrator's. Reusing another shopper's key returns idempotency_key_reused.

Lengthlength <= 200

Request Body

The photo, either as a file part in a multipart form or as the raw request body. The server stores a normalised copy: EXIF orientation applied, resized to fit 1024 px, re-encoded as JPEG (quality 90) with the camera EXIF block kept (orientation reset to 1) so the depth pass can read the lens data. HEIC is not accepted; iOS transcodes to JPEG when the file input's accept list excludes it.

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

application/problem+json

curl -X POST "https://example.com/images" \  -F file="string"
{  "id": "img_7bQ2mR9vXpL4dK1sZeCt",  "status": "preprocessing",  "width": 1024,  "height": 768,  "url": "https://api.viewa.com/api/v1/images/img_7bQ2mR9vXpL4dK1sZeCt/file",  "error": {    "code": "preprocessing_failed",    "detail": "string"  },  "visitor": {    "id": "vis_5nQ8xR2wKt7bZm3LpVdC",    "token": "string",    "expiresAt": "2019-08-24T14:15:22Z"  }}