Provider API
Every /evm/* route, for the deployment, the job book, provider operations, asks, providers and the allowlist.
Routes under /evm/*. The read routes are public and used by clients too; the write routes relay provider-signed messages. Encoding, headers, paging and body limits are in API conventions; the error envelope and retry rule are in Errors.
Deployment
GET /evm/chain
The deployment parameters a client or provider needs to sign.
Auth: public · Index-backed: no (reads the chain)
Response 200
{
"chain_id": 84532,
"contracts": {
"job_registry": "0x…",
"provider_registry": "0x…",
"ask_registry": "0x…",
"usdc": "0x…"
},
"decimals": 6,
"token_domain": { "name": "…", "version": "…" },
"gas_price": "1000000",
"head_block": "12345678",
"block_time_ms": 2000,
"fee_bps": 100
}| Field | Meaning |
|---|---|
contracts.usdc | The payment token's address. |
decimals | The payment token's decimals. |
token_domain | The payment token's EIP-712 name and version, for signing the payment. |
gas_price | The chain's current gas price, in wei. |
head_block | The chain head the node sees. |
block_time_ms | The node's poll interval. |
fee_bps | The protocol fee, in basis points. |
Errors: 503 chain_unreachable or relay_unavailable (config_read).
Job book
GET /evm/jobs
The job book, filtered. With free=N it is also the provider's poll.
Auth: public; a provider session with free · Index-backed: yes · Paged: yes
| Query | Meaning |
|---|---|
state | Open, Claimed, Settled or Cancelled. Cancelled means every ended job: cancelled, expired, failed or reclaimed. |
model | A model_id. |
provider | A provider id: jobs claimed by it. |
owner | An owner address. |
min_rate_in, min_rate_out | Only jobs with rates at or above these (decimal integers). |
posted_before | Only jobs posted at or before this block. |
order | oldest (default, by posting block) or newest. |
free | Provider poll: lease up to this many jobs. See below. |
Response 200
{
"jobs": [
{
"job_id": "0x…", "owner": "0x…", "c": "0x…",
"model_id": "3", "sla_secs": "3600", "designated": "0",
"rate_in": "1500", "rate_out": "6000", "units_in": "1200", "units_out": "800",
"expires_at": "1786003600", "state": 0, "ended_because": 0,
"provider_id": "0", "claimed_at": "0", "completion_tok": "0",
"task_cid": "bafy…", "result_cid": null, "posted_block": "12345600"
}
],
"as_of_block": "12345672"
}state and ended_because are as in Job lifecycle; an open job past expires_at reads as 3 / 5. provider_id, claimed_at and completion_tok are "0" until claimed or settled.
Provider poll. With free=N (0–4294967295), the request needs a provider session, state=Open and a model in the catalog. The node records the provider as live for that model with N free slots, leases it up to N of the oldest matching jobs it may claim (open bids, or designated to it) for MATCH_LEASE_MS, counting leases it already holds, and returns only the jobs it holds. See Matching and leases. Without free, the session is ignored.
On a coordinator whose escrow has lost keys, open undesignated jobs posted before its current key custody are left out of the book.
Errors
| Status | code | Cause |
|---|---|---|
400 | null | A bad filter; free without state=Open or model; a model not in the catalog. |
401 | invalid_session | free without a valid session. |
403 | not_registered | free with a session that is not a provider session. |
curl -s "https://api.vorq.co/evm/jobs?state=Open&model=3&free=4" \
-H "authorization: Bearer $TOKEN"GET /evm/jobs/summary
Totals for one owner, overall and per model.
Auth: public · Index-backed: yes
| Query | Meaning |
|---|---|
owner | Required. An owner address. |
Response 200
{
"jobs": "12", "completed": "10", "priced": "12", "escrowed": "91000",
"by_model": [{ "model_id": "3", "jobs": "12", "completed": "10", "priced": "12", "escrowed": "91000" }],
"as_of_block": "12345672"
}| Field | Meaning |
|---|---|
jobs | All jobs by this owner. |
completed | Settled jobs. |
priced | Jobs whose rates are whole numbers. |
escrowed | The sum of cap over priced jobs. |
GET /evm/jobs/{job_id}
One job in the book's shape, plus as_of_block.
Auth: public · Index-backed: yes
Errors: 400 for a malformed id; 404 for an unknown job.
Provider operations
POST /evm/ops
Relay one signed provider op. The coordinator verifies the signature, simulates the transaction, sends it and waits for the receipt.
Auth: session (any address; the op signature is the authority) · Index-backed: no · Body limit: 20 MiB
Request: a flat object with op, signature (the provider wallet's signature over the op's signed message) and the op's fields.
op | Fields | Signed message |
|---|---|---|
claim | job_id, issued_at | Claim |
settle | job_id, completion_tok, issued_at, and exactly one of result (the sealed result, base64, non-empty) or result_cid (the vorq.cid of a result upload by this session's address) | Settle |
fail | job_id, issued_at | Fail |
set_identity | box_key (bytes32), evidence (hex bytes, at most 32 768), issued_at | SetIdentity |
request_capacity | n (uint32), issued_at | RequestCapacity |
{ "op": "claim", "job_id": "0x…", "issued_at": 1786000000, "signature": "0x…" }claim, settle and fail need issued_at within ±600 seconds of the node's clock. set_identity and request_capacity need issued_at greater than the last accepted one for that op and at most one hour ahead.
Response 201
{ "tx_hash": "0x…", "status": "success", "block_number": "12345678", "result_cid": "bafy…" }result_cid is present on settle only: the IPFS CID the result was stored under.
Errors
| Status | Body or code | Cause |
|---|---|---|
400 | result_required, result_ambiguous, unknown_result, or null | A malformed op, or a missing, doubled or unknown result. |
401 | invalid_session | No valid session. |
403 | type invalid_op_signature | The signature does not recover to a registered provider. |
409 | {"ok": false, "reason": "<ContractError>"} | The chain refuses the op, for example StaleOp, NotOpen, AtCapacity, SlaExpired. When reason is unknown, raw carries the revert data. x-vorq-retryable: false. |
429, 503, 504 | See Errors. A 504 message names the route to poll. |
POST /evm/simulate/claim
An advisory check before signing a claim. It reads the chain, not the index, so it is accurate while the index lags.
Auth: public · Index-backed: no
Request
{ "job_id": "0x…", "address": "0x<provider wallet>" }Response 200
{ "ok": false, "reason": "NotDesignated" }{"ok": true}, or the first failing check, in the contract's order: UnknownJob, NotOpen, UnknownProvider, NotListed, ModelNotAllowed, NotDesignated, AtCapacity. It does not check the payment, the signature or the ±600-second window; POST /evm/ops simulates the real transaction.
Asks
PUT /evm/asks
Publish a signed ask snapshot to the AskRegistry. See Publish asks.
Auth: session (any address; the snapshot signature is the authority) · Index-backed: no · Body limit: 32 KiB
Request
{
"snapshot": {
"provider_id": 7,
"signed_at": 1786000000,
"quotes": [{ "model_id": 3, "sla": 3600, "rate_in": "1500", "rate_out": "6000" }]
},
"signature": "0x…"
}| Field | Rule |
|---|---|
snapshot.provider_id | The signer's provider id. |
snapshot.signed_at | Newer than the provider's latest snapshot; at most one hour ahead of the node's clock. |
snapshot.quotes | At most 64. Each sets the ask for its (model_id, sla); both rates 0 withdraws it. |
signature | The provider wallet's AskSnapshot signature. |
Response 200: after the publication is mined and confirmed.
{ "provider_id": "7", "signed_at": "1786000000", "published": true, "tx_hash": "0x…" }Errors
| Status | code | Cause |
|---|---|---|
400 | null | A malformed snapshot; signed_at too far ahead. |
401 | invalid_session | No valid session. |
403 | invalid_signature | The signature does not recover over the snapshot. |
403 | not_registered | The signer is not a registered provider. |
403 | provider_mismatch | The signer operates a different provider than snapshot.provider_id. |
409 | stale_snapshot | signed_at is not newer than the provider's latest. |
409 | superseded | A newer snapshot is already on chain. |
503 | publication_skipped | Mined, but the chain recorded no publication. Retry. |
504 | tx hash | No receipt within 60 seconds. The snapshot is stored; check GET /evm/asks rather than pushing it again. |
GET /evm/asks
Published asks of listed providers.
Auth: public · Index-backed: yes · Paged: yes
| Query | Meaning |
|---|---|
model | Only this model_id. |
Response 200
{ "asks": [{ "provider_id": "7", "model_id": "3", "sla": "3600", "rate_in": "1500", "rate_out": "6000" }], "as_of_block": "12345672" }GET /evm/asks/floors
The lowest ask per (model_id, sla) across listed providers, for catalog models. rate_in and rate_out are each minimised on their own, so a floor row may combine two providers' rates.
Auth: public · Index-backed: yes · Paged: yes
| Query | Meaning |
|---|---|
model | Only this model_id. |
sla | Only this SLA, in seconds. |
Response 200
{ "floors": [{ "model_id": "3", "sla": "3600", "rate_in": "1200", "rate_out": "5000" }], "as_of_block": "12345672" }Providers and catalog
GET /evm/providers
Registered providers, by id.
Auth: public · Index-backed: yes · Paged: yes
Response 200
{
"providers": [
{
"provider_id": "7", "operator": "0x…", "box_key": "0x…", "evidence": {},
"listed": true, "reputation": "1000",
"allow_all_models": false, "allowed_models": ["3"],
"capacity": "12", "active_jobs": "2"
}
],
"as_of_block": "12345672"
}| Field | Meaning |
|---|---|
operator | The provider's wallet address. |
box_key | The X25519 key designated orders are sealed to; null until set. |
evidence | The identity evidence published with set_identity, as JSON, or null. |
reputation | 100–1000. |
capacity | Effective capacity: max(1, reputation × min(requested, ceiling) / 1000). |
active_jobs | Jobs it currently holds claimed. |
GET /evm/providers/{id}
One provider plus as_of_block.
Auth: public · Index-backed: yes
Errors: 400 for an id that is not a uint32; 404 for an unknown provider.
GET /evm/models
The model catalog; the same body as GET /v1/models.
GET /evm/allowlist
Entries of the contracts' attestation allowlist.
Auth: public · Index-backed: yes · Paged: yes
Response 200
{ "entries": [{ "key": "0x…", "status": 1, "entry": {} }], "as_of_block": "12345672" }