About this walkthrough
This page walks through a single task run from start to finish against a real subnet, showing each request, the success response, and the error responses you can expect along the way. It complements Task Management, which covers the conceptual model. The examples use the subnet ID01KRDZGFZ8ZXQNFY8DWFYTDFCG. Replace it with your own and replace brb_... with the API key you generated from your subnet’s API Keys page.
All requests target the production API at https://api.bitrobot.ai. Swap in https://api-stage.bitrobot.ai to try things out against staging first.
Step 1 — Start the task run
task_start opens a new task run for a resource. It is the only event that returns a fresh task_run_id — keep that value; you will need it for task_end and task_validate.
Happy path
The minimum request identifies the resource by name and provides anent_owner wallet that will receive its rewards:
- The resource
(bot_001, frodobot)was looked up. It did not exist, so it was created and linked to the wallet atent_owner. Its new ULID is returned asresource_id— keep it so you can identify the resource directly on future calls instead of repeatingresource_name+resource_subtype+ent_owner. - Because no
task_idwas supplied, the subnet’s single task was used automatically. (See Task auto-resolution below for what happens when the subnet has zero or many tasks.) - A new task run was created with
status: in_progressandevent_id: ride_2026_05_20_001. Its ULID is returned astask_run_id.
Useful variations
Use a known resource_id instead of name + subtype
Use a known resource_id instead of name + subtype
register_resource (or another task_start), reuse its resource_id. You can omit resource_name, resource_subtype, and ent_owner — the ENT already exists on-chain.Pick a specific task when the subnet has multiple
Pick a specific task when the subnet has multiple
task_id explicitly:Supply your own task_run_id
Supply your own task_run_id
task_end / task_validate. Useful if you want to make the request safely retryable from your side.Record the real-world start time
Record the real-world start time
started_at captures when the robot actually began the operation, separate from when the event was ingested.Provide ENT metadata for first-time resources
Provide ENT metadata for first-time resources
Task auto-resolution
Whentask_id is omitted, the API resolves it from the subnet:
task_id always reflects the task the run was attached to, regardless of which case applied.
Error responses
Alltask_start validation errors return HTTP 422 with the shape:
400, 401, or 403 with a slightly different shape:
task_start, in roughly the order they’re checked.
400 — Invalid subnet_id
400 — Invalid subnet_id
subnet_id in the URL path does not exist. Double-check the ULID — 01KRDZGFZ8ZXQNFY8DWFYTDFCG is just an example.401 — Invalid or missing API key
401 — Invalid or missing API key
Authorization header is absent, malformed, or the key doesn’t match a live record. API keys must be sent as Authorization: Bearer brb_....422 — Missing event_id
422 — Missing event_id
event_id was omitted. It’s required and must be unique per task — see Duplicate event_id.422 — Must provide either resource_id or both resource_name and resource_subtype
422 — Must provide either resource_id or both resource_name and resource_subtype
resource_id nor the resource_name + resource_subtype pair, so the run has no resource to attach to.422 — Missing ent_owner
422 — Missing ent_owner
resource_name + resource_subtype but didn’t supply ent_owner. The owner wallet is required when the resource is being created or claimed for the first time. If the resource already exists, switch to resource_id instead.422 — Invalid started_at: expected ISO 8601 format
422 — Invalid started_at: expected ISO 8601 format
started_at was supplied but could not be parsed. Use a format like 2026-05-20T14:30:00Z.422 — Resource not found with id
422 — Resource not found with id
resource_id you sent doesn’t exist. Confirm the ULID — perhaps from the resource_id returned by an earlier register_resource call.422 — Resource is already registered to a different owner
422 — Resource is already registered to a different owner
(resource_subtype, resource_name) already exists and is owned by a different wallet than the ent_owner you supplied. Either send the correct ent_owner, or call the new owner’s flow via the dashboard.422 — Task not found with id
422 — Task not found with id
task_id you supplied doesn’t exist. Tasks are created via the BitRobot dashboard; pick one that’s listed there.422 — Task belongs to a different subnet
422 — Task belongs to a different subnet
task_id exists but is not part of this subnet. Tasks are scoped per-subnet; use one of 01KRDZGFZ8ZXQNFY8DWFYTDFCG’s own tasks.422 — Multiple tasks found for subnet
422 — Multiple tasks found for subnet
task_id explicitly.422 — A task run with event_id already exists
422 — A task run with event_id already exists
event_id collides with one already used on this task. event_id is unique per task, so retries must reuse the original (idempotent), or pick a fresh value. For truly safe retries, send the Idempotency-Key header.422 — Unknown event type
422 — Unknown event type
event_type. The valid task lifecycle values are task_start, task_end, and task_validate.Step 2 — End the task run
task_end closes out the run created in Step 1 and hands BitRobot the raw output (typically a video) for on-chain verification.
Happy path
You need thetask_run_id from Step 1, a publicly reachable URL pointing at the raw output, and the IPFS CID of that file computed locally with the documented Kubo command:
- The run’s status flipped from
in_progresstocompleted, and the on-chain run is closed using the supplied URI and CID. - A background job was enqueued to download the file at
raw_data_uri, recompute its CID with the same flags, and compare. If the CID matches, the file is stored and the run becomes eligible for validation. If it doesn’t, the run is marked invalid andtask_validatewill refuse to award points (see CID verification is asynchronous below).
Useful variations
Record the real-world end time
Record the real-world end time
ended_at captures when the robot actually finished the operation, separate from when the event was ingested. Pair it with the started_at you sent on task_start for accurate run durations.End a run without raw output
End a run without raw output
raw_data_uri / raw_data_cid. The run will close on-chain against placeholder values, and BitRobot will skip the CID verification step. The run is still eligible for task_validate, but it loses the verifiable link to a real-world artifact.CID verification is asynchronous
BitRobot verifies your CID against the file atraw_data_uri in a background job — not during the API request. The verification works like this:
- The job fetches the bytes at
raw_data_uri. - It recomputes the CID using
ipfs add -n --raw-leaves --chunker=size-1048576 -Q. - It compares the result to the
raw_data_cidyou sent.
task_validate, which returns "Task run data is invalid". To recover, fix the CID (or upload a corrected file at a new URI) and retry from task_end for a new run.
Common causes of a mismatch:
- The file at
raw_data_urichanged between when you computed the CID and when BitRobot fetched it. - The URL is private, time-limited, or returns a redirect to an error page.
- The CID was computed with different flags. The documented flags
-n --raw-leaves --chunker=size-1048576 -Qare required — omitting any of them produces a different CID for the same file.
Error responses
Alltask_end validation errors return HTTP 422 with the shape:
400, 401, or 403 with the simpler { "error": "..." } shape, exactly as in Step 1.
422 — Missing task_run_id
422 — Missing task_run_id
task_run_id was omitted. It must be the ULID returned by the matching task_start.422 — Task run not found
422 — Task run not found
task_run_id you got back from task_start against the same subnet you opened the run with.422 — Invalid ended_at: expected ISO 8601 format
422 — Invalid ended_at: expected ISO 8601 format
ended_at was supplied but could not be parsed. Use a format like 2026-05-20T14:45:00Z.Step 3 — Validate the task run
task_validate is the final step. It awards the run’s Verifiable Robotic Work (VRW) points to the resource owner on-chain, which is what makes the run count toward token reward distribution at the end of the epoch.
Happy path
You need thetask_run_id from Step 1 and a vrw_points integer:
- The run was confirmed eligible for validation: the raw data CID matched (from Step 2’s async verification), the resource has a wallet that can receive rewards, and there is an active BitRobot epoch open.
- A background job was enqueued to award
vrw_pointsto the resource owner’s on-chainEpochAccountfor the current epoch. - The run is now complete. Its share of the epoch’s token reward pool is fixed by
vrw_pointsdivided by the total VRW points awarded across the epoch.
vrw_points represents how much Verifiable Robotic Work this single run accomplished — it’s an on-chain quantity, separate from Subnet Points. Pick a value that’s proportional to the work done (distance traveled, frames captured, objects manipulated — whatever your subnet treats as the unit of work). Consistency across runs matters more than any specific scale.Useful variations
Validate a run without awarding points
Validate a run without awarding points
vrw_points: 0 to mark a run as validated but not award anything on-chain. This is useful for runs that completed cleanly but didn’t produce work worth rewarding — for example, a calibration pass or a run that was cut short by the operator.vrw_points: 0, the pre-flight checks for wallet and active epoch are skipped, so this also works as a way to close out runs whose resource has no wallet or whose epoch boundary has just passed.Error responses
Alltask_validate validation errors return HTTP 422 with the shape:
400, 401, or 403 with the simpler { "error": "..." } shape, exactly as in Step 1.
422 — Missing task_run_id
422 — Missing task_run_id
task_run_id was omitted. It must be the ULID returned by the matching task_start.422 — Missing vrw_points
422 — Missing vrw_points
vrw_points was omitted. It’s required even when you intend to award zero — send "vrw_points": 0 explicitly.422 — Task run not found
422 — Task run not found
task_start.422 — Task run data is invalid
422 — Task run data is invalid
raw_data_uri could not be fetched, or its recomputed CID did not match the raw_data_cid you sent. The run is permanently marked invalid; to recover, start a fresh run from task_start with a corrected URI and CID.422 — Resource has no wallet
422 — Resource has no wallet
vrw_points > 0 to a resource that isn’t linked to an owner wallet. Re-register the resource with an ent_owner, or send vrw_points: 0 to validate without awarding.422 — No active epoch found
422 — No active epoch found
vrw_points > 0 outside of any open BitRobot epoch. This is rare in production and usually means an epoch is being rolled over. Retry shortly, or send vrw_points: 0.You’re done
That’s the complete lifecycle:task_start → task_end → task_validate. The run is now permanently recorded, the resource owner has been awarded VRW points on-chain, and the run will contribute to that resource owner’s share of the epoch’s token reward distribution when the epoch closes.
From here you can:
- Inspect the run in the Task Management page of the BitRobot dashboard.
- Repeat the flow for the next run — reuse the
resource_idfrom Step 1 so you don’t have to resend the resource name, subtype, and owner each time. - Bulk-import historical runs via the Task Batch Upload endpoint, which runs each row through this same start → end → validate flow asynchronously.