VORQ Docs
Reference

Client API

Every /v1/* route, for models, jobs, files and batches.

Routes under /v1/*. Encoding, headers, paging and body limits are in API conventions; the error envelope and retry rule are in Errors.

Models

GET /v1/models

The model catalog. GET /evm/models returns the same body.

Auth: public · Index-backed: yes · Paged: yes

Response 200

{
  "object": "list",
  "data": [
    { "id": "model-name", "object": "model", "owned_by": "vorq", "vorq": { "model_id": "3", "enabled": true } }
  ],
  "as_of_block": "12345672"
}
FieldMeaning
idThe model's name.
vorq.model_idThe id orders use (model_id).
vorq.enabledWhether new orders for it are accepted.
curl -s https://api.vorq.co/v1/models

GET /v1/models/{name}

One model by name. Names may contain /; send them as-is or percent-encoded.

Auth: public · Index-backed: yes

Response 200: one model object, as in GET /v1/models, plus as_of_block.

Errors

StatuscodeCause
404model_not_foundNo model has this name. This body has no param field and no x-vorq-retryable header.

Jobs

POST /v1/jobs

Quote or submit an order. The same body, sent without and then with a payment, first returns a 402 quote and then posts the job. See Submit a job.

Auth: public (the order and payment signatures are the authority) · Index-backed: no · Body limit: 20 MiB

Order fields (every request)

FieldTypeRule
cbytes32Commitment to the sealed container.
model_iduint32An enabled model.
sla_secsuint32An SLA the chain allows; at most 86400.
rate_in, rate_outuint128Prices per 10^6 units, in base units of the payment token.
units_in, units_outuint32Unit counts the order pays for at most.
designateduint320 for an open bid, or the provider id the job is reserved for.
expires_atuint64Unix seconds, in (now, now + 86400].
owneraddressThe order's owner and payer.
job_idbytes32Must equal keccak256(owner ‖ c).
signature65 bytesThe owner's Order signature.

Submission fields (second request only)

FieldTypeRule
auth_sig65 bytesThe owner's ReceiveWithAuthorization signature over the quoted authorization.
amountuint256The quoted amount.
containerbase64The sealed container, up to 15 679 488 bytes decoded.
container_cidstringInstead of container: the vorq.cid of an input upload by owner.

Send exactly one of container and container_cid.

Market probe (a body with neither rate_in nor rate_out): model_id, sla_secs, units_in, units_out and optional designated, unsigned. The answer is 402 with {"candidates": [...]} only: every live ask for the model and window, ranked as below, with no quote. See Matching and leases.

Response 402: the quote, when auth_sig is absent. x-vorq-retryable: false.

{
  "quote": {
    "cap": "9600",
    "fee_bps": 100,
    "fee": "96",
    "gas_fee": "2000",
    "amount": "11696",
    "authorization": {
      "domain": { "name": "…", "version": "…", "chainId": 84532, "verifyingContract": "0x…" },
      "to": "0x…",
      "value": "11696",
      "valid_after": "0",
      "valid_before": "1786003601",
      "nonce": "0x…"
    }
  },
  "candidates": [{ "provider_id": "7", "box_key": "0x…", "rate_in": "1500", "rate_out": "6000" }],
  "accepts": [{ "scheme": "eip3009", "network": "eip155:84532" }]
}
FieldMeaning
quote.capThe escrow ceiling: max(1, ceil((rate_in·units_in + rate_out·units_out) / 10^6)).
quote.feefloor(cap · fee_bps / 10000).
quote.gas_feeThe flat relay charge, read from the JobRegistry.
quote.amountcap + fee + gas_fee.
quote.authorizationThe payment to sign: token domain, to (the JobRegistry), value (= amount), valid_after (0), valid_before (expires_at + 1), nonce (= job_id).
candidatesUp to MATCH_CANDIDATES live providers whose ask clears the order, cheapest first, with the ask's rates. Empty when none match. See Matching and leases.
acceptsThe payment scheme and CAIP-2 network.

Response 201: the job was posted.

{ "job_id": "0x…", "task_cid": "bafy…", "tx_hash": "0x…" }

task_cid is the IPFS CID the container was stored under. The job is normally readable at GET /v1/jobs/{id} as soon as this returns.

Errors

StatuscodeCause
400nullA malformed field (param names it); job_id mismatch; expires_at out of range; sla_secs over 86400 or not allowed; model not enabled.
400cap_overflowcap does not fit a uint128.
400invalid_order_signaturesignature does not recover to owner.
400container_without_paymentA container was sent without auth_sig.
400container_requiredauth_sig was sent without a container.
400container_ambiguousBoth container and container_cid.
400invalid_payment_signatureauth_sig does not recover to owner over the authorization for amount.
400payer_has_codeowner has contract code (a smart account or an EIP-7702 delegation). Pay from an account with no code.
400unknown_containercontainer_cid names no input upload by owner, or it expired.
400too_short, bad_version, commitment_mismatchThe container is malformed or does not reproduce c.
409(quote body)amount is not the current cap + fee + gas_fee, usually because gas_fee or fee_bps changed. The body is a fresh {quote, candidates, accepts}. Sign a new payment and resubmit.
409contract error nameThe chain refuses the post, for example DuplicateJob (use a fresh c).
429, 503, 504See Errors.

The quote is answered after the order signature is checked and before model, SLA-allowlist and payer checks, so a 402 does not guarantee the submission will pass them.

GET /v1/jobs/{id}

The client view of one job.

Auth: public · Index-backed: yes

PathMeaning
idThe job_id, 32-byte hex.

Response 200

{
  "id": "0x…",
  "object": "job",
  "model": "model-name",
  "status": "completed",
  "in_progress_at": "1786000100",
  "result_cid": "bafy…",
  "vorq": {
    "job_id": "0x…", "owner": "0x…", "model_id": "3", "sla_secs": "3600",
    "rate_in": "1500", "rate_out": "6000", "units_in": "1200", "units_out": "800",
    "designated": "0", "provider_id": "7", "expires_at": "1786003600", "task_cid": "bafy…",
    "completion_tok": "800", "state": 2, "ended_because": 1
  },
  "as_of_block": "12345700"
}
FieldMeaning
statusqueued, in_progress, completed, failed or cancelled. See Job lifecycle.
in_progress_atClaim time in Unix seconds, or null before a claim.
result_cidThe sealed result's IPFS CID once settled, else null.
modelThe model's name, or null if the catalog does not know it.

Errors: 400 for a malformed id; 404 until the coordinator has a record of the job.

curl -s https://api.vorq.co/v1/jobs/0x…

POST /v1/jobs/{id}/cancel

Cancel an open job. See Cancel a job.

Auth: public (the owner's signature is the authority) · Index-backed: no · Body limit: 8 KiB

Request

FieldTypeRule
issued_atuint64Unix seconds, within ±600 of the coordinator's clock.
signature65 bytesThe owner's Cancel signature over (id, issued_at).

Response 200

{ "job_id": "0x…", "tx_hash": "0x…" }

Cancelling a job that has already settled or ended succeeds and changes nothing.

Errors

StatuscodeCause
409StaleOpissued_at outside ±600 seconds.
409NotCancellableThe job is claimed.
409NotTheOwnerThe signature does not recover to the job's owner, or the job does not exist.
409other contract error nameThe chain refused the cancel.
429, 503, 504See Errors.

Files

POST /v1/files

Upload a sealed container, a sealed result or a batch input. The file is streamed to the object store.

Auth: session · Index-backed: no · Body: multipart/form-data

PartRule
purposeinput, result or batch. Must come before the file part.
fileOne file part, up to MAX_BLOB_BYTES (200 MiB by default).
purposeContentsChecks
inputA sealed containerFraming; the commitment is computed during upload so POST /v1/jobs can compare it with c.
resultA sealed resultNon-empty.
batchJSONL, one request per lineAt least one and at most 50 000 non-blank lines.

Response 200

{
  "id": "file-3b1f…",
  "object": "file",
  "bytes": 1048576,
  "created_at": 1786000000,
  "expires_at": 1786000300,
  "filename": "container",
  "purpose": "input",
  "status": "uploaded",
  "vorq": { "cid": "bafy…", "lines": 0 }
}

vorq.cid is what container_cid and result_cid reference; id is what input_file_id references. expires_at is 300 seconds after upload until the file is attached; see File retention. lines counts non-blank lines for batch files and is 0 otherwise.

Errors

StatuscodeCause
400invalid_purposepurpose is not input, result or batch.
400empty_fileNo bytes, or a batch file with no requests.
400too_many_linesA batch file over 50 000 lines.
400bad_containerAn input file that is not a valid container.
400nullMissing purpose or file part, or a malformed form.
413file_too_largeOver MAX_BLOB_BYTES.
503store_unavailable, store_rejectedThe object store failed. Retryable.
curl -s -X POST https://api.vorq.co/v1/files \
  -H "authorization: Bearer $TOKEN" \
  -F purpose=input -F file=@container.bin

GET /v1/files/{id}

The file object, as returned by POST /v1/files. Batch output files have purpose: "batch_output" and status: "processed".

Auth: session; only the file's owner · Index-backed: no

Errors: 404 for an unknown file or one owned by another address.

GET /v1/files/{id}/content

The file's bytes.

Auth: session; only the file's owner · Index-backed: no

Response 200: application/jsonl for batch uploads, application/octet-stream for every other file, including batch output files.

Errors: 404 for an unknown file or one owned by another address; 503 with code: "object_missing" when the object store no longer holds it.

Batches

Batch objects follow the OpenAI batch shape. Every line of the input file is a complete POST /v1/jobs submission body; see Run a batch.

POST /v1/batches

Create a batch from an uploaded batch file.

Auth: session · Index-backed: no

Request

{ "input_file_id": "file-…", "endpoint": "/v1/responses", "completion_window": "24h", "metadata": { "run": "nightly" } }
FieldRule
input_file_idA batch upload by this session's address.
endpoint/v1/responses or /v1/embeddings. A line's url, when present, must equal it.
completion_window1h or 24h. The batch expires this long after creation.
metadataOptional; at most 16 string pairs, keys up to 64 and values up to 512 characters.

Response 200: a batch object with status: "validating".

Batch plan (a body with no input_file_id): for lines that name no bid, ask how the network would take them before sealing anything.

{ "completion_window": "24h", "models": [{ "model_id": 3, "lines": 120, "units_in": 48000, "units_out": 491520 }] }

units_in and units_out are the totals over that model's lines; models lists 1–16 models. The answer is 402 with, per model, the providers to seal to, their ask and how many lines each takes:

{ "plan": [{ "model_id": "3", "lines": "120", "allocation": [{ "provider_id": "1", "box_key": "0x…", "rate_in": "2118400", "rate_out": "10626400", "lines": "120" }] }] }

Each live provider's share is at most its on-chain capacity less what it already holds: claimed jobs and open orders designated to it. Providers are filled cheapest first for the model's unit mix, and equal prices take turns. Nothing is reserved. When the allocation lines add up to fewer than lines, the network cannot take the batch in that window now; the SDKs refuse it before sealing.

Errors

StatuscodeCause
400invalid_endpointUnsupported endpoint.
400invalid_completion_windowNot 1h or 24h.
400invalid_input_fileNo batch file with this id for this address.
400nullMalformed metadata or missing field.

GET /v1/batches

This address's batches, newest first.

Auth: session · Index-backed: yes

QueryDefaultRule
limit201–100
after—A batch id; returns the batches after it.

Response 200

{ "object": "list", "data": [ { "id": "batch_…", "object": "batch", "…": "…" } ], "first_id": "batch_…", "last_id": "batch_…", "has_more": false, "as_of_block": "12345700" }

Pass last_id as after to get the next page while has_more is true.

GET /v1/batches/{id}

One batch object plus as_of_block.

Auth: session; only the batch's owner · Index-backed: yes

Errors: 404 for an unknown batch or one owned by another address.

POST /v1/batches/{id}/cancel

Stop a batch. Lines not yet posted are not posted. Lines already on chain are not cancelled: open ones stay open until claimed or expired, and claimed ones run to completion. The owner can cancel each job. Repeating the call is a no-op.

Auth: session; only the batch's owner · Index-backed: yes

Response 200: the batch object plus as_of_block, with cancelling_at set.

Errors

StatuscodeCause
400batch_not_cancellableThe batch is not validating, in_progress or cancelling.
404nullUnknown batch, or owned by another address.

Batch object

{
  "id": "batch_5e2a…",
  "object": "batch",
  "endpoint": "/v1/responses",
  "input_file_id": "file-…",
  "completion_window": "24h",
  "status": "in_progress",
  "errors": null,
  "output_file_id": null,
  "error_file_id": null,
  "created_at": 1786000000,
  "expires_at": 1786086400,
  "in_progress_at": 1786000010,
  "finalizing_at": null,
  "completed_at": null,
  "failed_at": null,
  "expired_at": null,
  "cancelling_at": null,
  "cancelled_at": null,
  "request_counts": { "completed": 10, "failed": 1, "total": 50 },
  "metadata": {},
  "vorq": { "sla": "24h" }
}
FieldMeaning
statusvalidating (not yet processed), in_progress, finalizing (every line ended, files being written), completed, failed, expired (the window ended first), cancelling, cancelled.
request_countstotal lines recorded; completed settled; failed skipped, cancelled, failed, reclaimed or expired.
output_file_id, error_file_idSet when the batch finishes; null when that file would be empty.
TimestampsUnix seconds, or null.

Status and counts are computed from the member jobs on every read.

Batch output files

Both files are JSONL, read with GET /v1/files/{id}/content. Line ids have the form batch_req_<batch>_<line number>.

Output file: one line per settled job.

{"id":"batch_req_5e2a…_1","custom_id":null,"response":{"status_code":200,"request_id":"0x<job_id>","body":null},"error":null,"vorq":{"job_id":"0x…","result_cid":"bafy…","provider":7,"rate_in":"1500","rate_out":"6000","completion_tok":800}}

Results are sealed to the owner, so body is always null: fetch each result by result_cid. Your own request ids travel inside the sealed payload and result.

Error file: one line per input line that did not settle.

{"id":"batch_req_5e2a…_2","custom_id":null,"response":null,"error":{"code":"invalid_payment_signature","message":"…"},"vorq":{"job_id":null,"line":2}}
error.codeCause
invalid_json, invalid_lineThe line is not a JSON object, or a field is malformed. Other field-level codes from POST /v1/jobs may appear.
endpoint_mismatchThe line's url differs from the batch endpoint.
container_required, unknown_container, too_short, bad_version, commitment_mismatchMissing, unknown or invalid container.
order_expired, expiry_too_far, sla_too_long, cap_overflowOrder terms out of range when the batch was processed.
insufficient_paymentamount is not exactly cap + fee + gas_fee.
invalid_order_signature, invalid_payment_signature, payer_has_codeSignature or payer checks failed.
duplicate_job_idAnother line in the file has the same job_id.
invalid_modelThe model is not enabled.
cancelledThe batch was cancelled before the line was posted, or the owner cancelled the job.
provider_fail, reclaim, expiredPosted, but the provider failed it, missed its SLA, or nobody claimed it in time.
contract error nameThe chain refused to post the line.

On this page