DocsAPI Reference

API Reference

Endpoints, request and response shapes, authentication, and error codes.

The Veralens REST API is a small, predictable surface. Every endpoint lives under one base URL, speaks JSON, and returns the same envelope shape whether it succeeds or fails.

text
https://veralens.ai/api/v1

Authentication

Programmatic requests authenticate with an API key as a Bearer token. Create keys under API Keys in the dashboard. Each secret starts with vl_ and is shown once.

http
Authorization: Bearer vl_your_secret_key

Key management endpoints (create, list, rotate, revoke) are part of the dashboard and use your logged-in session. You cannot manage keys with an API key. Everything below under Jobs accepts an API key.

Response envelope

Success responses wrap the payload in data:

json
{ "status": "success", "data": { "id": "V1StGXR8_Z5jdHi6B", "status": "pending" } }

Errors carry a stable error_code plus a matching HTTP status:

json
{ "status": "error", "error_code": "insufficient_balance" }

Branch on the HTTP status and error_code. The codes are stable, and human-readable text is advisory only.

POST /jobs/create

Create an extraction job. Returns immediately with a job id; the work runs asynchronously.

Body

FieldTypeRequiredDescription
FieldsourcesTypearrayRequiredyesDescriptionOne or more inputs. Each is { "type": "text" | "image" | "document", "data": string }. See the source types below.
FieldschemaTypeobjectRequiredconditionalDescriptionA JSON Schema describing the output object. When present, target must be json (or omitted).
FieldtargetTypestringRequiredconditionalDescriptionOutput format: json, markdown, or plaintext. Required when no schema is given. Defaults to json when a schema is present.
Fieldglobal_promptTypestringRequirednoDescriptionNatural-language instructions applied to the whole extraction.
FieldengineTypestringRequirednoDescriptionvera-1.0-high (default) or vera-1.0-low. See Pricing.
Fieldwebhook_urlTypestringRequirednoDescriptionHTTPS URL to receive the result. API-key auth only: from a dashboard session it returns 400 invalid_input. See Jobs & Queue.

You must send at least one of schema or target. Provide a schema for strict typed JSON, or only a target (with an optional global_prompt) for freeform Markdown/plaintext or schemaless JSON.

Source types

typedataAccepted
typetextdataThe raw text.AcceptedAny text.
typeimagedataA base64 data URL, data:image/png;base64,....AcceptedAny raster image: PNG, JPEG, WebP, GIF, HEIC and others. SVG is rejected with job_image_mime_unsupported.
typedocumentdataA base64 data URL, data:application/pdf;base64,....AcceptedPDF (application/pdf), Word (application/vnd.openxmlformats-officedocument.wordprocessingml.document), Excel (application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel), CSV (text/csv, application/csv), plain text (text/plain) and Markdown (text/markdown). Any other type returns job_document_mime_unsupported.

Document limits, all returned as 400:

  • 20 MB per file, measured on the decoded file, not the base64 text (job_document_too_large).
  • 200 pages per PDF (job_document_too_many_pages).
  • 800,000 characters of text per Word, Excel, CSV, text or Markdown file (job_document_content_too_large).

PDFs are read page by page as images. The other document types are read as text.

Response: 201 Created. Returns the full job object (same shape as GET /jobs/:jobId/get below), already in pending. model, target, and the hold (usage.cost) are set immediately. output and settled token usage fill in once the job runs.

json
{
  "status": "success",
  "data": {
    "id": "V1StGXR8_Z5jdHi6B",
    "status": "pending",
    "createdAt": "2025-03-01T10:15:00.000Z",
    "source": "key",
    "target": "json",
    "sources": { "images": 1, "texts": 0, "documents": 0 },
    "model": "vera-1.0-high",
    "usage": { "cost": 0.0021, "inputTokens": null, "outputTokens": null },
    "output": null,
    "durationMs": null
  }
}

Example

bash
curl -X POST https://veralens.ai/api/v1/jobs/create \
  -H "Authorization: Bearer vl_your_secret_key" \
  -H "Content-Type: application/json" \
  -d '{
    "sources": [{ "type": "image", "data": "data:image/png;base64,iVBORw0KGgo..." }],
    "engine": "vera-1.0-high",
    "schema": {
      "type": "object",
      "properties": {
        "merchant": { "type": "string", "description": "Store or merchant name." },
        "total":    { "type": "number", "description": "Grand total paid." }
      },
      "required": ["merchant", "total"]
    }
  }'

GET /jobs/:jobId/get

Fetch a single job by id. Poll this until status is no longer pending.

Response

json
{
  "status": "success",
  "data": {
    "id": "V1StGXR8_Z5jdHi6B",
    "status": "completed",
    "createdAt": "2025-03-01T10:15:00.000Z",
    "source": "key",
    "target": "json",
    "sources": { "images": 1, "texts": 0, "documents": 0 },
    "model": "vera-1.0-high",
    "usage": { "cost": 0.0031, "inputTokens": 812, "outputTokens": 44 },
    "output": "{\"merchant\":\"Acme\",\"total\":19.9}",
    "durationMs": 2100
  }
}

Job fields

FieldTypeDescription
FieldidTypestringDescriptionJob id.
FieldstatusTypestringDescriptionpending, completed, or failed.
FieldcreatedAtTypestringDescriptionISO timestamp the job was created.
FieldsourceTypestringDescriptionOrigin: key (API) or playground (dashboard).
FieldtargetTypestringDescriptionjson, markdown, or plaintext.
FieldsourcesTypeobjectDescriptionCount of inputs by type: images, texts, documents.
FieldmodelTypestringDescriptionEngine for this job, set when the job is created.
FieldusageTypeobjectDescriptioncost (USD), inputTokens, outputTokens. While pending, cost is the hold and the token counts are null. Once completed, cost is the real charge, which can be higher or lower than the hold.
FieldoutputTypestringDescriptionThe extraction result, encoded as a JSON string for every target. JSON.parse it: a json job gives an object, a markdown job gives the markdown text. null until completed.
FielddurationMsTypenumberDescriptionWall-clock runtime; null while pending.

GET /jobs/list

List your jobs, most recent first.

Query parameters

ParamTypeDefaultDescription
ParamqTypestringDefaultnoneDescriptionReturns jobs whose id contains this text. It does not search inside jobs.
ParamstatusTypestringDefaultallDescriptionall, finished, pending, or failed.
ParamsourceTypestringDefaultnoneDescriptionFilter by origin: key or playground.
ParamlimitTypenumberDefault100DescriptionPage size, 1 to 500.
ParamoffsetTypenumberDefault0DescriptionRows to skip.

Response

json
{
  "status": "success",
  "data": {
    "jobs": [ { "id": "V1StGXR8_Z5jdHi6B", "status": "completed", "target": "json", "model": "vera-1.0-high", "usage": { "cost": 0.0031, "inputTokens": 812, "outputTokens": 44 } } ],
    "total": 1
  }
}

Error codes

These come back on the request itself, with the HTTP status shown.

error_codeHTTPMeaning
error_codeunauthorizedHTTP401MeaningMissing, wrong or revoked API key.
error_codeuser_bannedHTTP403MeaningThe account is blocked. Contact support@veralens.ai.
error_codeinvalid_inputHTTP400MeaningThe body failed validation, for example no schema and no target, a schema with a target other than json, a source data that is not a base64 data URL, or a webhook_url sent without an API key.
error_codevalidation_json_malformedHTTP400MeaningThe body is not valid JSON.
error_codeinsufficient_balanceHTTP400MeaningYour balance can't cover the job's hold. The body also carries message and topup_url, a link to add funds in the dashboard. See Pricing.
error_codejob_not_foundHTTP404MeaningNo job with that id for your account.
error_codejob_image_mime_unsupportedHTTP400MeaningAn image source is a vector format such as SVG. Send a raster image.
error_codejob_document_mime_unsupportedHTTP400MeaningA document source has a type we do not accept. See the source types above.
error_codejob_document_too_largeHTTP400MeaningA document source is over 20 MB.
error_codejob_document_too_many_pagesHTTP400MeaningA PDF has more than 200 pages.
error_codejob_document_content_too_largeHTTP400MeaningA Word, Excel, CSV, text or Markdown file has more than 800,000 characters of text. Split the file.
error_codeendpoint_not_foundHTTP404MeaningNo endpoint at that path. Check the method and the path, including /get on a job.
error_coderate_limit_exceededHTTP429MeaningToo many requests. Wait for Retry-After seconds. See Rate limits below.
error_codeengine_rate_limited, engine_unavailable, engine_service_unavailable, engine_timeoutHTTP429, 503, 502, 504MeaningVeralens could not size the job right now. Nothing was held. Retry shortly.
error_codeengine_invalid_requestHTTP400MeaningA source could not be read. Check the file and the schema.
error_codeinternal_server_errorHTTP500MeaningUnexpected error. Retry.

A job that ends failed. Once a job is created, a failure does not come back as an error_code. The job's status turns failed, the webhook (if any) gets { "status": "error", "job_id": "..." }, and the hold is refunded in full, so a failure costs nothing. Jobs are retried before they are marked failed. If the same document keeps failing, send a smaller document or ask for fewer fields.

Rate limits

Limits apply per API key and per endpoint. Each endpoint has a short and a long window, and you must stay under both.

EndpointShort windowLong window
EndpointPOST /jobs/createShort window20 per 10 secondsLong window60 per minute
EndpointGET /jobs/listShort window20 per 10 secondsLong window60 per minute
EndpointGET /jobs/:jobId/getShort window10 per 10 secondsLong window30 per minute

Over a limit you get 429 rate_limit_exceeded with these headers:

HeaderValue
HeaderRetry-AfterValueSeconds to wait before you retry.
HeaderRateLimit-LimitValueThe limit of the window you hit.
HeaderRateLimit-RemainingValue0.
HeaderRateLimit-ResetValueSeconds until the window resets.

To wait for one job, fetch it every 2 to 3 seconds, or use a webhook and don't poll at all.