Create a test job request and place it on the specified queue
Most parameters passed in the data section of this API will be specific to the
type of agent receiving them. The job_queue parameter is used to designate the
queue used, but all others will be passed along to the agent.
Parameters:
job_queue(JSON): queue name to use for processing the job
Returns:
{ "job_id": "<job_id (UUID)>" }Status Codes:
HTTP 200 (OK)HTTP 422 (Unprocessable Content): The submitted job contains references to secrets and these secrets are, for any reason, inaccessible.
Examples:
curl http://localhost:8000/v1/job -X POST \
--header "Content-Type: application/json" \
--data '{ "job_queue": "myqueue", "option":"foo" }'Get a test job from the specified queue(s)
When an agent wants to request a job for processing, it can make this request along with a list of one or more queues that it is configured to process. The server will only return one job.
Parameters:
queue (multivalue): queue name(s) that the agent can process
Returns:
JSON job data that was submitted by the requestor, or nothing if no jobs in the specified queue(s) are available.
Status Codes:
HTTP 200 (OK)HTTP 400 (Bad Request): this is returned if no queue is specifiedHTTP 204 (NO DATA): if there are no jobs in the specified queues
Example:
curl http://localhost:8000/v1/job?queue=foo\&queue=barNote
Any secrets that are referenced in the job are "resolved" when the job is retrieved by an agent through this endpoint. Any secrets that are inaccessible at the time of retrieval will be resolved to the empty string.
Search for jobs by tag(s) and state(s)
Parameters:
tags(array): List of string tags to search formatch(string): Match mode fortags(string, "all" or "any", default: "any")state(array): List of job states to include (or "active" to search all states other than cancelled and completed)
Returns:
Array of matching jobs
Example:
curl 'http://localhost:8000/v1/job/search?tags=foo&tags=bar&match=all'This will find jobs tagged with both "foo" and "bar".
Post job outcome data for the specified job_id
Parameters:
job_id(UUID): test job identifier
Request Body:
status(object): Dictionary mapping phase names to exit codesdevice_info(object, optional): Device informationjob_state(string, optional): Current job state
Status Codes:
HTTP 200 (OK)
Example:
curl http://localhost:8000/v1/result/00000000-0000-0000-0000-000000000000 \
-X POST --header "Content-Type: application/json" \
--data '{ "status": {"setup": 0, "provision": 0, "test": 0}, "device_info": {} }'Return previously submitted job outcome data
This endpoint reconstructs results from the new logging system to maintain backward compatibility. It combines phase status information with logs to provide a complete view of job results.
Parameters:
job_id(UUID): test job identifier
Status Codes:
HTTP 200 (OK)HTTP 204 (NO DATA): if there are no results for that ID yet
Returns:
JSON data with flattened structure including:
{phase}_status: Exit code for each phase{phase}_output: Standard output logs for each phase (if available){phase}_serial: Serial console logs for each phase (if available)- Additional metadata fields (device_info, job_state, etc.)
Example:
curl http://localhost:8000/v1/result/00000000-0000-0000-0000-000000000000 -X GETPost a log fragment for the specified job_id and log type
This is the new logging endpoint that agents use to stream log data in fragments. Each fragment includes metadata for tracking and querying.
Parameters:
job_id(UUID): test job identifierlog_type(string): Type of log - eitheroutputorserial
Request Body:
fragment_number(integer): Sequential fragment number starting from 0timestamp(string): ISO 8601 timestamp when the fragment was createdphase(string): Test phase name (setup, provision, firmware_update, test, allocate, reserve, cleanup)log_data(string): The log content for this fragment
Status Codes:
HTTP 200 (OK)HTTP 400 (Bad Request): Invalid log_type or missing required fields
Example:
curl http://localhost:8000/v1/result/00000000-0000-0000-0000-000000000000/log/output \
-X POST --header "Content-Type: application/json" \
--data '{
"fragment_number": 0,
"timestamp": "2025-10-15T10:00:00+00:00",
"phase": "setup",
"log_data": "Starting setup phase..."
}'Retrieve logs for the specified job_id and log type
This endpoint supports querying logs with optional filtering by phase, fragment number, or timestamp. Logs are persistent and can be retrieved multiple times.
Parameters:
job_id(UUID): test job identifierlog_type(string): Type of log - eitheroutputorserial
Query Parameters (all optional):
phase(string): Filter logs to a specific test phasestart_fragment(integer): Return only fragments from this number onwardsstart_timestamp(string): Return only logs created after this ISO 8601 timestamp
Status Codes:
HTTP 200 (OK)HTTP 204 (NO DATA): if there are no logs for that ID yetHTTP 400 (Bad Request): Invalid log_type or query parameters
Returns:
JSON object with logs organized by phase. Each phase includes:
last_fragment_number: The highest fragment number for this phaselog_data: Combined log text from all matching fragments
Example:
# Get all output logs for a job
curl http://localhost:8000/v1/result/00000000-0000-0000-0000-000000000000/log/output
# Get only setup phase output logs
curl http://localhost:8000/v1/result/00000000-0000-0000-0000-000000000000/log/output?phase=setup
# Get logs from fragment 5 onwards
curl http://localhost:8000/v1/result/00000000-0000-0000-0000-000000000000/log/output?start_fragment=5
# Get logs after a specific timestamp
curl "http://localhost:8000/v1/result/00000000-0000-0000-0000-000000000000/log/output?start_timestamp=2025-10-15T10:30:00Z"Response example:
{
"output": {
"setup": {
"last_fragment_number": 5,
"log_data": "Starting setup...\nSetup complete\n"
},
"provision": {
"last_fragment_number": 12,
"log_data": "Provisioning device...\nDevice ready\n"
}
}
}Upload a file artifact for the specified job_id
Parameters:
job_id(UUID): test job identifier
Status Codes:
HTTP 200 (OK)
Example:
curl -X POST -F "file=@README.rst" localhost:8000/v1/result/00000000-0000-0000-0000-000000000000/artifactDownload previously submitted artifact for this job
Parameters:
job_id(UUID): test job identifier
Status Codes:
HTTP 200 (OK)HTTP 204 (NO DATA): if there are no results for that ID yet
Returns:
JSON data previously submitted to this job_id via the POST API
Example:
curl http://localhost:8000/v1/result/00000000-0000-0000-0000-000000000000/artifact \
-X GET -O artifact.tar.gzPost names/descriptions of queues serviced by this agent
Status Codes:
HTTP 200 (OK)
Example:
curl http://localhost:8000/v1/agents/queues \
-X POST --header "Content-Type: application/json" \
--data '{ "myqueue": "queue 1", "myqueue2": "queue 2" }'Retrieve the list of well-known queues
Status Codes:
HTTP 200 (OK)
Returns:
JSON data previously submitted by all agents via the POST API
Example:
curl http://localhost:8000/v1/agents/queues -X GETPost known images for the specified queue
Status Codes:
HTTP 200 (OK)
Example:
curl http://localhost:8000/v1/agents/images \
-X POST --header "Content-Type: application/json" \
--data '{ "myqueue": { "image1": "url: http://place/imgae1" }}'Retrieve all known image names and the provisioning data used for them, for the specified queue
Parameters:
queue: name of the queue to use
Status Codes:
HTTP 200 (OK)
Returns:
JSON data previously submitted by all agents via the POST API
Example:
curl http://localhost:8000/v1/agents/images/myqueue -X GETExecute action for the specified job_id
Parameters:
job_id(UUID): test job identifier
Status Codes:
HTTP 200 (OK)HTTP 400 (Bad Request): The job is already completed or cancelledHTTP 404 (Not Found): The job isn't foundHTTP 422 (Unprocessable): The action or the argument to it could not be processed
Supported Actions:
Cancel: cancel a job that hasn't been completed yet
Example:
curl http://localhost:8000/v1/job/00000000-0000-0000-0000-000000000000/action \
-X POST --header "Content-Type: application/json" \
--data '{ "action":"cancel" }'Retrieve all agent data
Status Codes:
HTTP 200 (OK)
Returns:
JSON data for all known agents, useful for external systems that need to gather this information
Example:
curl -X GET http://localhost:8000/v1/agents/dataRetrieve data from a specified agent.
Status Codes:
HTTP 200 (OK)HTTP 404 (Not Found): The agent isn't found
Returns:
JSON data for specified agent, useful for getting information from a single agent.
Example:
curl -X GET http://localhost:8000/v1/agents/data/fooPost provision log data for the specified agent
Status Codes:
HTTP 200 (OK)
Example:
curl http://localhost:8000/v1/agents/provision_logs/myagent \
-X POST --header "Content-Type: application/json" \
--data '{ "job_id": "00000000-0000-0000-0000-000000000000", \
"exit_code": 1, "detail":"foo" }'Receive job status updates from an agent and posts them to the specified webhook.
The job_status_webhook parameter is required for this endpoint. Other
parameters included here will be forwarded to the webhook.
Parameters:
job_id(UUID): test job identifierjob_status_webhook: webhook URL to post status updates to
Returns:
Text response from the webhook if the server was successfully able to post.
Status Codes:
HTTP 200 (OK)HTTP 400 (Bad request): The arguments could not be processed by the serverHTTP 504 (Gateway Timeout): The webhook URL timed out
Example:
curl -X POST \
-H "Content-Type: application/json" \
-d '{"agent_id": "agent-00", "job_queue": "myqueue", "job_status_webhook": "http://mywebhook", "events": [{"event_name": "started_provisioning", "timestamp": "2024-05-03T19:11:33.541130+00:00", "detail": "my_detailed_message"}]}' http://localhost:8000/v1/job/00000000-0000-0000-0000-000000000000/eventsGet wait time metrics - optionally take a list of queues
Parameters:
queue(array): list of queues to get wait time metrics for
Returns:
JSON mapping of queue names to wait time metrics
Example:
curl http://localhost:8000/v1/queues/wait_times?queue=foo\&queue=barGet the list of agents listening to a specified queue
Parameters:
queue_name(string): name of the queue for which to get the agents that are listening to it
Status Codes:
HTTP 200 (OK)HTTP 204 (NO DATA): if there are no agents in the specified queue.HTTP 404 (NOT FOUND): if the queue does not exists.
Returns:
JSON array of agents listening to the specified queue
Example:
curl http://localhost:8000/v1/queues/foo/agentsSearch for jobs in a specified queue.
Parameters:
queue_name (string): queue name(s) where to get the jobs.
Status Codes:
HTTP 200 (OK)HTTP 204 (NO DATA): if there are no jobs in the specified queue.
Returns:
JSON job data with information about the ID, creation time and state for jobs in the specified queue.
Example:
curl 'http://localhost:8000/v1/queues/foo/jobs'This will find jobs in the queue foo and return its IDs, creation time and state.
Authenticate a client and return an access token and refresh token.
Headers:
- Basic Authorization: client_id:client_key (Base64 Encoded)
Status Codes:
HTTP 200 (OK)HTTP 401 (Unauthorized): invalid client_id or client-key
Returns:
{
"access_token": "<JWT access token>",
"token_type": "Bearer",
"expires_in": 30,
"refresh_token": "<opaque refresh token>",
}Notes:
expires_inis the lifetime (in seconds) of the access token.- Refresh tokens default to 30 days; admin may issue non-expiring tokens for trusted integrations.
Example:
curl http://localhost:8000/v1/oauth2/token \
-X POST --header "Authorization: Basic ABCDEF12345"Exchange a valid refresh token for a new access token.
Parameters (JSON body):
token(string): The opaque refresh token issued earlier.
Status Codes:
HTTP 200 (OK)HTTP 400 (Bad Request): missing, invalid, revoked or expired refresh token
Returns:
{
"access_token": "<new JWT access token>",
"token_type": "Bearer",
"expires_in": 30
}Example:
curl http://localhost:8000/v1/oauth2/refresh \
-X POST --header "Content-Type: application/json" \
--data '{"refresh_token": "opaque-refresh-token"}'Revoke a refresh token so it can no longer be used.
Parameters (JSON body):
token(string): The opaque refresh token to revoke.
Status Codes:
HTTP 200 (OK)HTTP 400 (Bad Request): invalid request
Returns:
{
"message": "Refresh token revoked successfully"
}Example:
curl http://localhost:8000/v1/oauth2/revoke \
-X POST --header "Content-Type: application/json" \
--data '{"refresh_token": "opaque-refresh-token"}'Retrieve the list of all restricted queues and their owners.
Headers:
- Bearer Token: JWT Token with permissions (Base64 Encoded)
Status Codes:
HTTP 200 (OK)HTTP 401 (Unauthorized): Invalid client_id or client-keyHTTP 403 (Forbidden): Incorrect permissions for authenticated user
Returns:
JSON data with a list of restricted queues
Example:
curl http://localhost:8000/v1/restricted-queues \
-X GET --header "Authorization: Bearer <JWT Token>"Retrieve the specified restricted queue and its owners.
Headers:
- Bearer Token: JWT Token with permissions (Base64 Encoded)
Status Codes:
HTTP 200 (OK)HTTP 401 (Unauthorized): Invalid client_id or client-keyHTTP 403 (Forbidden): Incorrect permissions for authenticated user
Returns:
JSON data with restricted queue and who owns it
Example:
curl http://localhost:8000/v1/restricted-queues/foo \
-X GET --header "Authorization: Bearer <JWT Token>"Add an owner to the specific restricted queue. If the queue does not exist yet, it will be created automatically.
Headers:
- Bearer Token: JWT Token with permissions (Base64 Encoded)
Status Codes:
HTTP 200 (OK)HTTP 400 (Bad Request): Missing client_id to set as owner of restricted queue.HTTP 401 (Unauthorized): Invalid client_id or client-keyHTTP 403 (Forbidden): Incorrect permissions for authenticated userHTTP 404 (Not Found): Queue does not exists or is not associated to an agent.
Example:
curl http://localhost:8000/v1/restricted-queues/foo \
-X POST --header "Authorization: Bearer <JWT Token>" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data '{"client_id": "foo"}'Delete an owner from the specific restricted queue.
Headers:
- Bearer Token: JWT Token with permissions (Base64 Encoded)
Status Codes:
HTTP 200 (OK)HTTP 400 (Bad Request): Missing client_id to set as owner of restricted queue.HTTP 401 (Unauthorized): Invalid client_id or client-keyHTTP 403 (Forbidden): Incorrect permissions for authenticated userHTTP 404 (Not Found): Queue is not in the restricted queue list
Example:
curl http://localhost:8000/v1/restricted-queues/foo \
-X DELETE --header "Authorization: Bearer <JWT Token>" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data '{"client_id": "foo"}'Retrieve the list all client_id and its permissions
Headers:
- Bearer Token: JWT Token with permissions (Base64 Encoded)
Status Codes:
HTTP 200 (OK)HTTP 401 (Unauthorized): Invalid client_id or client-keyHTTP 403 (Forbidden): Incorrect permissions for authenticated user
Returns:
JSON data with a list all client IDs and its permission excluding the hashed secret stored in database
Example:
curl http://localhost:8000/v1/client-permissions \
-X GET --header "Authorization: Bearer <JWT Token>"Retrieve the permissions associated with a client_id
Headers:
- Bearer Token: JWT Token with permissions (Base64 Encoded)
Status Codes:
HTTP 200 (OK)HTTP 401 (Unauthorized): Invalid client_id or client-keyHTTP 403 (Forbidden): Incorrect permissions for authenticated userHTTP 404 (Not Found): Specified client_id does not exist
Returns:
JSON data with the permissions of a specified client excluding the hashed secret stored in database
Example:
curl http://localhost:8000/v1/client-permissions/foo \
-X GET --header "Authorization: Bearer <JWT Token>"Create new client_id with specified permissions.
Headers:
- Bearer Token: JWT Token with permissions (Base64 Encoded)
Status Codes:
HTTP 200 (OK)HTTP 400 (Bad Request): Missing client_id and/or client_secret in JSON dataHTTP 401 (Unauthorized): Invalid client_id or client-keyHTTP 403 (Forbidden): Incorrect permissions for authenticated userHTTP 409 (Conflict): Specified client_id already exists
Example:
curl http://localhost:8000/v1/client-permissions \
-X POST --header "Authorization: Bearer <JWT Token>"
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data '{"client_id": "foo", "client_secret": "my-secret-password", "max_priority": {}, "max_reservation_time": {"*": 40000}, "role": "contributor"}'Edit the permissions for a specified client_id.
Headers:
- Bearer Token: JWT Token with permissions (Base64 Encoded)
Status Codes:
HTTP 200 (OK)HTTP 401 (Unauthorized): Invalid client_id or client-keyHTTP 403 (Forbidden): Incorrect permissions for authenticated userHTTP 404 (Not Found): Specified client_id does not exist
Example:
curl http://localhost:8000/v1/client-permissions/foo \
-X PUT --header "Authorization: Bearer <JWT Token>"
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data '{"max_priority": {"q1": 10}, "max_reservation_time": {}, "role": "contributor"}'Delete a client_id along with its permissions
Headers:
- Bearer Token: JWT Token with permissions (Base64 Encoded)
Status Codes:
HTTP 200 (OK)HTTP 401 (Unauthorized): Invalid client_id or client-keyHTTP 403 (Forbidden): Incorrect permissions for authenticated userHTTP 404 (Not Found): Specified client_id does not existHTTP 422 (Unprocessable Entity): System admin can't be removed using the API
Example:
curl http://localhost:8000/v1/client-permissions/foo \
-X DELETE --header "Authorization: Bearer <JWT Token>"