Background jobs
Start background jobs
Run your skills and workflows in the background, one at a time or several as a batch.
POST
/
v1
/
jobs
Start background jobs
curl --request POST \
--url https://api.valendata.com/v1/jobs \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"items": [
{
"skill": "<string>",
"workflow_id": "<string>",
"inputs": {},
"max_results": 250,
"label": "<string>"
}
],
"label": "<string>"
}
'import requests
url = "https://api.valendata.com/v1/jobs"
payload = {
"items": [
{
"skill": "<string>",
"workflow_id": "<string>",
"inputs": {},
"max_results": 250,
"label": "<string>"
}
],
"label": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
items: [
{
skill: '<string>',
workflow_id: '<string>',
inputs: {},
max_results: 250,
label: '<string>'
}
],
label: '<string>'
})
};
fetch('https://api.valendata.com/v1/jobs', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.valendata.com/v1/jobs",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'items' => [
[
'skill' => '<string>',
'workflow_id' => '<string>',
'inputs' => [
],
'max_results' => 250,
'label' => '<string>'
]
],
'label' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.valendata.com/v1/jobs"
payload := strings.NewReader("{\n \"items\": [\n {\n \"skill\": \"<string>\",\n \"workflow_id\": \"<string>\",\n \"inputs\": {},\n \"max_results\": 250,\n \"label\": \"<string>\"\n }\n ],\n \"label\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.valendata.com/v1/jobs")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"items\": [\n {\n \"skill\": \"<string>\",\n \"workflow_id\": \"<string>\",\n \"inputs\": {},\n \"max_results\": 250,\n \"label\": \"<string>\"\n }\n ],\n \"label\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.valendata.com/v1/jobs")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"items\": [\n {\n \"skill\": \"<string>\",\n \"workflow_id\": \"<string>\",\n \"inputs\": {},\n \"max_results\": 250,\n \"label\": \"<string>\"\n }\n ],\n \"label\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"jobs": [
{
"id": "<string>",
"origin_kind": "session",
"kind": "skill",
"status": "queued",
"origin_id": "",
"group_id": "<string>",
"label": "",
"target_id": "",
"run_ref": "<string>",
"summary": "<string>",
"result": {},
"error": "<string>",
"cancel_requested": false,
"attempts": 0,
"created_at": "2023-11-07T05:31:56Z",
"started_at": "2023-11-07T05:31:56Z",
"ended_at": "2023-11-07T05:31:56Z",
"link": ""
}
],
"batch": {
"id": "<string>",
"origin_kind": "session",
"kind": "skill",
"status": "queued",
"origin_id": "",
"group_id": "<string>",
"label": "",
"target_id": "",
"run_ref": "<string>",
"summary": "<string>",
"result": {},
"error": "<string>",
"cancel_requested": false,
"attempts": 0,
"created_at": "2023-11-07T05:31:56Z",
"started_at": "2023-11-07T05:31:56Z",
"ended_at": "2023-11-07T05:31:56Z",
"link": ""
},
"refused": [
"<string>"
]
}{
"detail": "The request is malformed: the body is not JSON, the cursor or Idempotency-Key is not valid.",
"code": "invalid_json",
"type": "invalid_request_error",
"request_id": "3f9a1c2b7d4e"
}{
"detail": "The API key is missing, malformed, revoked, or expired.",
"code": "unauthorized",
"type": "authentication_error",
"request_id": "3f9a1c2b7d4e"
}{
"detail": "The key lacks a scope, is limited to other skills or workflows, or you may not do this.",
"code": "permission_denied",
"type": "permission_error",
"request_id": "3f9a1c2b7d4e"
}{
"detail": "A conflict with the current state, or a request with this Idempotency-Key is still running.",
"code": "conflict",
"type": "conflict_error",
"request_id": "3f9a1c2b7d4e"
}{
"detail": "Invalid request — name: Field required",
"code": "validation_error",
"type": "invalid_request_error",
"request_id": "3f9a1c2b7d4e",
"param": "name",
"errors": [
{
"type": "missing",
"loc": [
"body",
"name"
],
"msg": "Field required"
}
]
}{
"detail": "Too many requests for this key, or too many runs in progress. Wait `Retry-After` seconds.",
"code": "rate_limited",
"type": "rate_limit_error",
"request_id": "3f9a1c2b7d4e"
}{
"detail": "Something broke on our side. Retry; runs that fail on our side are refunded.",
"code": "internal_error",
"type": "api_error",
"request_id": "3f9a1c2b7d4e"
}Give
MCP tool:
items, 1 to 6 things to run. Each is kind: skill with skill (its id or slug) or kind: workflow with workflow_id, plus optional inputs, max_results (skills, 1–500), and a short label. Two or more items start a batch; label at the top names it.
The answer comes at once (202): jobs holds each job that started, and batch the batch when there are two or more. Nothing calls you back: poll Get a background job for each job, or for the batch, which ends when they all have.
An item that cannot start (no such skill, inputs that do not fit, not enough credits) is listed in refused with the reason, and the others still start. Research helpers start only from a chat in the app, not here.
Starting twice runs twice, so send an Idempotency-Key to make a retry safe. See Idempotency.
| Status | Why |
|---|---|
403 | The key lacks jobs:write, skills:invoke or workflows:invoke for what you start, or is limited to other skills or workflows. |
422 | A field is wrong (param names it), more than 6 items, or none of the items could start (detail lists why for each). |
start_jobs.Authorizations
ApiKeyAuthApiKeyHeader
API key with the vd_sk_ prefix, as Authorization: Bearer vd_sk_.... Create keys in Settings → API Keys.
Headers
Any unique string (such as your order id). Resending the same request with the same key within 24 hours returns the first answer (with Idempotent-Replayed: true) and does nothing twice; the same key with a different request is a 422 idempotency_key_reused.
Required string length:
1 - 255Body
application/json
Response
Successful Response
⌘I
Start background jobs
curl --request POST \
--url https://api.valendata.com/v1/jobs \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"items": [
{
"skill": "<string>",
"workflow_id": "<string>",
"inputs": {},
"max_results": 250,
"label": "<string>"
}
],
"label": "<string>"
}
'import requests
url = "https://api.valendata.com/v1/jobs"
payload = {
"items": [
{
"skill": "<string>",
"workflow_id": "<string>",
"inputs": {},
"max_results": 250,
"label": "<string>"
}
],
"label": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
items: [
{
skill: '<string>',
workflow_id: '<string>',
inputs: {},
max_results: 250,
label: '<string>'
}
],
label: '<string>'
})
};
fetch('https://api.valendata.com/v1/jobs', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.valendata.com/v1/jobs",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'items' => [
[
'skill' => '<string>',
'workflow_id' => '<string>',
'inputs' => [
],
'max_results' => 250,
'label' => '<string>'
]
],
'label' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.valendata.com/v1/jobs"
payload := strings.NewReader("{\n \"items\": [\n {\n \"skill\": \"<string>\",\n \"workflow_id\": \"<string>\",\n \"inputs\": {},\n \"max_results\": 250,\n \"label\": \"<string>\"\n }\n ],\n \"label\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.valendata.com/v1/jobs")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"items\": [\n {\n \"skill\": \"<string>\",\n \"workflow_id\": \"<string>\",\n \"inputs\": {},\n \"max_results\": 250,\n \"label\": \"<string>\"\n }\n ],\n \"label\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.valendata.com/v1/jobs")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"items\": [\n {\n \"skill\": \"<string>\",\n \"workflow_id\": \"<string>\",\n \"inputs\": {},\n \"max_results\": 250,\n \"label\": \"<string>\"\n }\n ],\n \"label\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"jobs": [
{
"id": "<string>",
"origin_kind": "session",
"kind": "skill",
"status": "queued",
"origin_id": "",
"group_id": "<string>",
"label": "",
"target_id": "",
"run_ref": "<string>",
"summary": "<string>",
"result": {},
"error": "<string>",
"cancel_requested": false,
"attempts": 0,
"created_at": "2023-11-07T05:31:56Z",
"started_at": "2023-11-07T05:31:56Z",
"ended_at": "2023-11-07T05:31:56Z",
"link": ""
}
],
"batch": {
"id": "<string>",
"origin_kind": "session",
"kind": "skill",
"status": "queued",
"origin_id": "",
"group_id": "<string>",
"label": "",
"target_id": "",
"run_ref": "<string>",
"summary": "<string>",
"result": {},
"error": "<string>",
"cancel_requested": false,
"attempts": 0,
"created_at": "2023-11-07T05:31:56Z",
"started_at": "2023-11-07T05:31:56Z",
"ended_at": "2023-11-07T05:31:56Z",
"link": ""
},
"refused": [
"<string>"
]
}{
"detail": "The request is malformed: the body is not JSON, the cursor or Idempotency-Key is not valid.",
"code": "invalid_json",
"type": "invalid_request_error",
"request_id": "3f9a1c2b7d4e"
}{
"detail": "The API key is missing, malformed, revoked, or expired.",
"code": "unauthorized",
"type": "authentication_error",
"request_id": "3f9a1c2b7d4e"
}{
"detail": "The key lacks a scope, is limited to other skills or workflows, or you may not do this.",
"code": "permission_denied",
"type": "permission_error",
"request_id": "3f9a1c2b7d4e"
}{
"detail": "A conflict with the current state, or a request with this Idempotency-Key is still running.",
"code": "conflict",
"type": "conflict_error",
"request_id": "3f9a1c2b7d4e"
}{
"detail": "Invalid request — name: Field required",
"code": "validation_error",
"type": "invalid_request_error",
"request_id": "3f9a1c2b7d4e",
"param": "name",
"errors": [
{
"type": "missing",
"loc": [
"body",
"name"
],
"msg": "Field required"
}
]
}{
"detail": "Too many requests for this key, or too many runs in progress. Wait `Retry-After` seconds.",
"code": "rate_limited",
"type": "rate_limit_error",
"request_id": "3f9a1c2b7d4e"
}{
"detail": "Something broke on our side. Retry; runs that fail on our side are refunded.",
"code": "internal_error",
"type": "api_error",
"request_id": "3f9a1c2b7d4e"
}
