Submitting tasks
A task is one call (worker, function, input, gas_limit) executed by a committee. Tasks come from one of
two sources set in the manifest’s consensus.work.task_source.
Scheduled tasks
Section titled “Scheduled tasks”{"kind": "schedule", "function": "work", "interval_secs": 60, "gas_limit": 2000000}: the Hub creates a task
every interval with this input (canonical JSON):
{"epoch": 497631, "project_id": "0x…", "seed": "0x…", "seq": 12}seed is the slot’s sortition seed: unpredictable before the epoch beacon and identical for every committee
member. Use it as the randomness of continuous jobs (simulations, challenge generation, sampling). The
reference project Hash Chain Lab runs this way.
API tasks
Section titled “API tasks”{"kind": "api"}: your backend submits tasks with an API key that has tasks:submit (or anyone, if
scheduling.public_tasks is true, rate-limited per IP).
curl -s -X POST "https://testnet-rpc.necter.network/v1/projects/$PROJECT_ID/tasks?wait=60" \ -H "Authorization: Bearer $NECTER_API_KEY" -H 'content-type: application/json' \ -d '{"function":"aggregate","input":{"pair":"ETH/USD","round":7,"reports":[…]},"idempotency_key":"eth-usd-7"}'| Field | |
|---|---|
function |
one of consensus.work.functions |
input |
string (passed byte for byte) or JSON (canonical, no floats), ≤ 1 MiB; or input_b64 for binary |
gas_limit |
optional; default and maximum max_gas_limit |
idempotency_key |
optional, ≤ 64 chars; the same key within 24 h returns the same task instead of a new one |
Query parameters: wait=0..120 seconds to block until the task is final, and accept=final (default) or
accept=agreed to return as soon as the committee has a clean quorum (optimistic, before validator
finality).
Response (200 when done within wait, else 202):
{ "task_id": "task:0x…", "project_id": "0x…", "round_id": "task:0x…", "epoch": 497631, "seq": 43, "function": "aggregate", "input_hash": "0x…", "status": "finalized", "success": true, "output": "{\"pair\":\"ETH/USD\",\"price\":3200120000,…}", "receipt_hash": "0x…", "gas_used": 69709, "events": [{ "name": "price.aggregated", "data": { … } }], "error": null, "created_at": 1791474233, "finalized_at": 1791474290}status moves through queued → running → committee_agreed → finalized. Other end states:
escalated (no finality in time; the call was re-run on validators to get your output), fallback (no
committee was possible: too few miners, no attested snapshot, or the vault is underfunded; the call ran on
validators and paid no miner), failed. Poll with GET /v1/tasks/{task_id}?wait=60.
Choosing wait and accept
Section titled “Choosing wait and accept”- Low latency, small stakes:
accept=agreed. A clean committee quorum is very likely final; validators still audit it. - Settlement-grade:
accept=final(default). The output is backed by a validator quorum’s finality signatures. - Rounds last up to
round_secs(plus finality), so setwaitat least that long or poll.
Errors
Section titled “Errors”Status / error |
Cause |
|---|---|
401 unauthorized |
No API key and the project does not accept public tasks |
403 forbidden / 403 scope_missing |
The key belongs to another developer, or lacks tasks:submit |
409 invalid_state |
The project is not listed (still pending_review, paused or delisted) |
400 invalid_field |
Unknown function, both input and input_b64, bad wait/accept |
413 too_large |
Input over 1 MiB |
429 rate_limited |
Slow down (Retry-After) |