VORQ Docs
Reference

Submit

client.submit — every argument, SLA windows, local validation, unit derivation and reference-asset limits.

client.submit(args: SubmitArgs): Promise<JobHandle>
interface SubmitArgs {
  model: string;
  input: string | Record<string, unknown>;
  sla?: string;                                   // default "batch"
  rateIn?: string | number | bigint | null;
  rateOut?: string | number | bigint | null;
  provider?: number;
  validateParams?: boolean;                       // default true
  confidential?: boolean;                         // default false
  unitsOut?: number;
  customId?: string;
}

Submissions are always sealed: a client missing its signer or cipher raises ValidationError before anything is sent. The returned handle is described in Jobs and results; the steps a submission runs are in Job lifecycle.

Arguments

ArgumentTypeDefaultMeaning
modelstring—A model id from client.models.list(). A model the catalog gives no numeric model_id raises ValidationError.
inputstring | object—A string is shorthand for { input: string }. An object is the model's own input, sealed as-is.
slastring"batch"A tier ("async" / "batch") or a window ("1h" / "24h"). See SLA windows.
rateInstring | number | bigint | nullnullThe input-side bid as a scaled integer. With both rates null, the order takes the market (see No bid named); with only one null, that side bids zero.
rateOutsamenullThe output-side bid, same scaling.
providernumber—A provider's registry id; the payload is sealed to its published key. With no rates named, the bid is this provider's ask, and ValidationError is raised when it is not live for the model. Omit, with rates named, for an open order.
validateParamsbooleantrueRun local validation before sealing.
confidentialbooleanfalseVerify the named provider's attestation evidence before sealing to it. Requires a verifier.
unitsOutnumberderivedThe output unit count, exactly, overriding the derived value. A non-negative integer; 0 for an embedding.
customIdstring—Your own label, sealed inside the payload and returned as .customId on the opened result. Never sent in the clear.

Rates are bigint in code and decimal strings on the wire. They are uint128 on chain, which a number cannot hold exactly, so build large ones with BigInt("…"). A digits-only string also works; a fraction ("0.03"), a negative or a non-integer number raises ValidationError.

Recipient. With provider, or with no rates (the market pins one), the payload is sealed to the key in that provider's registry record (GET /evm/providers/{id}); a record with no key raises VerificationError. With rates and no provider, the payload is sealed to the coordinator's verified escrow key, which requires a verifier; without one, or if the key does not verify, EscrowKeyUnverified is raised and nothing is posted.

confidential: true without a verifier raises ValidationError before any request. With one, the named provider's evidence must verify or VerificationError is raised; another provider is never substituted. On an open order it adds nothing, since the escrow key is verified on that path anyway.

stream, metadata and user are not job params: a sealed result is delivered once, at settlement, and a caller-chosen identifier would link your jobs to each other across providers.

No bid named

With neither rateIn nor rateOut, submit first asks the coordinator for the market: a POST /v1/jobs with no rates and no signature, so it costs no wallet prompt. The coordinator answers with every live provider that has a free slot and an ask in the order's window, ranked by what this job would cost at their ask, and among equal prices the provider picked least recently first. submit bids the first candidate's own ask and pins it, so providers at the same price take turns.

With provider as well, the probe is pinned too, and the bid is that provider's ask. With confidential: true and no provider, the list is first filtered to candidates whose attestation verifies. When no provider is live for the model in the window, ValidationError is raised before anything is signed; name rates to post a bid that rests instead.

SLA windows

TierWindowSeconds signed
"async""1h"3600
"batch""24h"86400

Other windows of the form <n>h, <n>m or <n>s are signed as written and validated by the network; a string of any other form is signed as 3600 s. Job rows report the window as vorq.sla_secs.

The order's expiry is the window plus the settlement margin ($VORQ_SETTLEMENT_MARGIN, default 3600 s), capped at 86400 s from signing.

Local validation

Before sealing, an object input is checked against the model's published params_schema (client.models.paramsSchema(model)):

  • A param the schema sets to false, or a value that fails its subschema, raises ValidationError and nothing is sent.
  • A param the schema does not mention is sent, with a console.warn: the serving provider may support it or ignore it.
  • Keywords evaluated: type, minimum, maximum, enum, oneOf, items, properties. Any other keyword is skipped with a warning; the provider still applies it.
  • No published schema, or a failed schema read, skips the schema check.

One check needs no schema. When the input names an output cap (max_tokens, max_output_tokens or max_completion_tokens; the smallest one counts), a reasoning_max_tokens at or above the cap, or a min_tokens above it, raises ValidationError: reasoning tokens are billed as output, out of the same cap, and would leave no room for an answer.

validateParams: false turns off both checks.

Units

The order signs units_in and units_out, which settlement meters against rateIn and rateOut. The SDK derives both from the input object.

Shape. The request is text if it names max_output_tokens, max_tokens or max_completion_tokens; else video if it names duration or duration_secs; else image if it names num_images, width or resolution, or carries a reference asset; else text.

units_out (unless unitsOut is given):

Shapeunits_out
TextThe first non-zero of max_output_tokens, max_tokens, max_completion_tokens; 4096 if none.
ImageFrame pixels × num_images (1 if absent).
VideoFrame pixels × duration seconds.

Frame pixels come from explicit width × height (a missing one counts as 1024), else from a resolution tier resolved against aspect_ratio, else 1024 × 1024.

  • Tiers: 480p, 720p, 1080p, 4k. Aspect ratios: 21:9, 16:9, 4:3, 1:1, 3:4, 9:16, plus auto and adaptive. Any other value raises ValidationError.
  • A tier is a pixel budget: at 16:9 it is 854×480, 1280×720, 1920×1080 or 3840×2160, and every other ratio is the frame of that shape with about the same area.
  • auto (or no aspect_ratio) takes the ratio closest to the first image or clip reference, or 16:9 with no references. adaptive is priced at the tier's largest frame.

Duration is duration_secs, else duration: a number (truncated to whole seconds), a digits-only string, or "auto" (priced as 15 s). Absent or not positive, it is 5 s. Anything else raises ValidationError.

units_in:

  • Text and embeddings: one unit per four bytes of the input's canonical JSON, at least 1.
  • Image and video: the reference assets in pixel-seconds, width × height × max(1, duration_secs) summed over the assets (a still counts as one second), 0 with none.

Reference assets

Reference keys are image, end_image and video, and the lists reference_images, reference_videos and reference_audios. Each asset is an object:

MemberRequiredMeaning
b64yesThe bytes, base64.
media_typeyesFor example "image/png", "video/mp4".
width, heightimages and clipsPositive integers, the asset's true size.
duration_secsclips (video, reference_videos)Positive integer seconds, rounded up.

Limits, checked before anything is sealed or signed (ValidationError):

LimitValue
reference_imagesat most 9
reference_videosat most 3
reference_audiosat most 3, each at most 15 MiB; audio counts zero units
Pixel-bearing assets per requestat most 12
Pixels per assetat most 8 294 400 (3840 × 2160)
Clip lengthat most 60 s

Assets are priced from the dimensions you declare, without decoding. Providers check them against the decoded bytes, so an asset larger or longer than declared can fail the job.

Size

A sealed container up to 15 679 488 bytes travels inline in the job body. A larger one is uploaded first with client.uploadFile(…, "input", …) and referenced by content id. There is no client-side size cap; the coordinator's own limits apply.

Low-level sealing

client.sealLine(args: SealLineArgs): Promise<SealedLine>
client.payLine(line: SealedLine, gasFee: bigint, ctx: ChainContext, feeBps: bigint): Promise<Record<string, unknown>>

The two halves batches.submit is built from, public for callers assembling a batch file by hand. sealLine seals one payload and signs its order; payLine signs the payment for it (cap + floor(cap × feeBps / 10000) + gasFee) and returns the flat JSONL row. Prefer submit for a job and batches.submit for a file.

On this page