API
esc

Type to search.

API reference

Introduction

The Veeton Studio API is a REST API over HTTPS with JSON bodies, organization-scoped machine keys, cursor pagination and one error envelope everywhere.

Resources are organised around what you hold and what you generate. Start with Products and Imports to get a catalogue in, Tasks to render, Exports to read everything back, and Webhooks to be told when things finish.

Within a major version only additive changes ship: new fields, new optional parameters, new values where a set is documented as open. Clients must ignore fields they do not know.

Base URL

https://api.veeton.com/v1

Authentication

Every request carries an organization-scoped machine key as a bearer token. Mint one in the dashboard under Settings → API Keys. Keys start with ak_; dashboard session tokens are not accepted.

Keys carry scopes (products:read, tasks:write, …) and a request outside them is refused with 403 insufficient_scope. Verification is cached for about a minute, so revocation takes that long to apply. See the Authentication guide.

Authenticated request

curl https://api.veeton.com/v1/products \
  -H "Authorization: Bearer $VEETON_KEY"

Errors

Conventional HTTP status codes tell you the class of outcome; the body tells you what happened. Every error is the same envelope, { error: { type, code, message, param? } }. Switch on type for behaviour and on code for messaging; message is for people and is not stable.

Attributes

  • typeenum
    Possible enum values (9)
    • invalid_request
    • not_found
    • unauthorized
    • forbidden
    • payment_required
    • conflict
    • rate_limited
    • internal
    • not_implemented
  • codestring
  • messagestring
  • paramstring

HTTP status codes

  • 200, 201, 202, 204
    The request worked. 202 means an asynchronous job was accepted.
  • 400
    The request was malformed or failed validation. Imports and tryon list every problem at once.
  • 401
    No key, or a key that is unknown, revoked or expired.
  • 402
    No active subscription or insufficient credits. Nothing was queued.
  • 403
    The key lacks a scope, or is bound to a user rather than an organization.
  • 404
    The resource does not exist in your organization.
  • 409
    A uniqueness conflict, such as a reference already in use.
  • 413, 415
    The body is too large, or its content type is not accepted.
  • 422
    The request is well-formed but cannot be applied: an idempotency key reused with a different body, a subtype and inputs that do not match.
  • 429
    Rate limited. Wait Retry-After seconds and retry.
  • 5xx
    Something failed on our side. Quote the X-Request-Id to support.

Error envelope

{
  "error": {
    "type": "invalid_request",
    "code": "product_not_found",
    "message": "Product 01HX...XY1 was not found.",
    "param": "inputs.product_id"
  }
}

Pagination

Every list endpoint takes limit (1 to 100, default 25) and cursor, and returns the same envelope. Pass next_cursor back as cursor untilhas_more is false. Cursors are opaque and keyset-based, so rows added or deleted while you page are never skipped or repeated.

List envelope

{
  "data": [  ],
  "next_cursor": "eyJpZCI6MTIzNDV9",
  "has_more": true
}

Idempotent requests

Send Idempotency-Key (any string up to 255 characters, a UUID by convention) on POST, PATCH and DELETE. The same key with the same request replays the stored response with Idempotent-Replayed: true; the same key with a different request is 422 idempotency_key_reused; a key still in flight is409 request_in_progress. Keys expire after 24 hours. A 5xx is never stored, so retrying it re-runs the request. See Idempotency.

Idempotent request

curl https://api.veeton.com/v1/tasks/beautifier \
  -H "Authorization: Bearer $VEETON_KEY" \
  -H "Idempotency-Key: 4d1b9f6e-6c2a-4c1e-9c3f-2a7e8b0d1f22" \
  -H "Content-Type: application/json" \
  -d @task.json

Rate limits

Per organization, per minute: 600 reads (GET) and 60 writes (POST, PATCH, DELETE). Every response carries the bucket's state inX-RateLimit-* headers. Past the limit you get 429 rate_limited with Retry-After; nothing was created and no idempotency key was consumed, so retrying is always safe.

Response headers

X-RateLimit-Limit: 600
X-RateLimit-Remaining: 597
X-RateLimit-Reset: 1756910040

Request ids

Every response carries X-Request-Id. Send your own value in that header (up to 128 characters of letters, digits, ., _, : and-) and it is echoed back, so one id follows a call through your logs and ours. Quote it when you contact support.

Response headers

X-Request-Id: req_7f3c2a1b9e4d4c0f8a6b