Create a session
curl --request POST \
--url https://agp.eu.hcompany.ai/api/v2/sessions \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"agent": {},
"messages": [
{}
],
"max_steps": 123,
"max_time_s": 123,
"idle_timeout_s": 123,
"delete_after_min": {},
"delete_screenshot_after_min": {},
"queue": true,
"group_id": "<string>",
"parent_session_id": "<string>",
"overrides": {}
}
'import requests
url = "https://agp.eu.hcompany.ai/api/v2/sessions"
payload = {
"agent": {},
"messages": [{}],
"max_steps": 123,
"max_time_s": 123,
"idle_timeout_s": 123,
"delete_after_min": {},
"delete_screenshot_after_min": {},
"queue": True,
"group_id": "<string>",
"parent_session_id": "<string>",
"overrides": {}
}
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({
agent: {},
messages: [{}],
max_steps: 123,
max_time_s: 123,
idle_timeout_s: 123,
delete_after_min: {},
delete_screenshot_after_min: {},
queue: true,
group_id: '<string>',
parent_session_id: '<string>',
overrides: {}
})
};
fetch('https://agp.eu.hcompany.ai/api/v2/sessions', 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://agp.eu.hcompany.ai/api/v2/sessions",
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([
'agent' => [
],
'messages' => [
[
]
],
'max_steps' => 123,
'max_time_s' => 123,
'idle_timeout_s' => 123,
'delete_after_min' => [
],
'delete_screenshot_after_min' => [
],
'queue' => true,
'group_id' => '<string>',
'parent_session_id' => '<string>',
'overrides' => [
]
]),
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://agp.eu.hcompany.ai/api/v2/sessions"
payload := strings.NewReader("{\n \"agent\": {},\n \"messages\": [\n {}\n ],\n \"max_steps\": 123,\n \"max_time_s\": 123,\n \"idle_timeout_s\": 123,\n \"delete_after_min\": {},\n \"delete_screenshot_after_min\": {},\n \"queue\": true,\n \"group_id\": \"<string>\",\n \"parent_session_id\": \"<string>\",\n \"overrides\": {}\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://agp.eu.hcompany.ai/api/v2/sessions")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"agent\": {},\n \"messages\": [\n {}\n ],\n \"max_steps\": 123,\n \"max_time_s\": 123,\n \"idle_timeout_s\": 123,\n \"delete_after_min\": {},\n \"delete_screenshot_after_min\": {},\n \"queue\": true,\n \"group_id\": \"<string>\",\n \"parent_session_id\": \"<string>\",\n \"overrides\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://agp.eu.hcompany.ai/api/v2/sessions")
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 \"agent\": {},\n \"messages\": [\n {}\n ],\n \"max_steps\": 123,\n \"max_time_s\": 123,\n \"idle_timeout_s\": 123,\n \"delete_after_min\": {},\n \"delete_screenshot_after_min\": {},\n \"queue\": true,\n \"group_id\": \"<string>\",\n \"parent_session_id\": \"<string>\",\n \"overrides\": {}\n}"
response = http.request(request)
puts response.read_bodySessions
Create a session
Launch a session: run a pre-built or custom agent on a task, with optional overrides, idempotency key, and parent session.
POST
/
api
/
v2
/
sessions
Create a session
curl --request POST \
--url https://agp.eu.hcompany.ai/api/v2/sessions \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"agent": {},
"messages": [
{}
],
"max_steps": 123,
"max_time_s": 123,
"idle_timeout_s": 123,
"delete_after_min": {},
"delete_screenshot_after_min": {},
"queue": true,
"group_id": "<string>",
"parent_session_id": "<string>",
"overrides": {}
}
'import requests
url = "https://agp.eu.hcompany.ai/api/v2/sessions"
payload = {
"agent": {},
"messages": [{}],
"max_steps": 123,
"max_time_s": 123,
"idle_timeout_s": 123,
"delete_after_min": {},
"delete_screenshot_after_min": {},
"queue": True,
"group_id": "<string>",
"parent_session_id": "<string>",
"overrides": {}
}
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({
agent: {},
messages: [{}],
max_steps: 123,
max_time_s: 123,
idle_timeout_s: 123,
delete_after_min: {},
delete_screenshot_after_min: {},
queue: true,
group_id: '<string>',
parent_session_id: '<string>',
overrides: {}
})
};
fetch('https://agp.eu.hcompany.ai/api/v2/sessions', 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://agp.eu.hcompany.ai/api/v2/sessions",
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([
'agent' => [
],
'messages' => [
[
]
],
'max_steps' => 123,
'max_time_s' => 123,
'idle_timeout_s' => 123,
'delete_after_min' => [
],
'delete_screenshot_after_min' => [
],
'queue' => true,
'group_id' => '<string>',
'parent_session_id' => '<string>',
'overrides' => [
]
]),
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://agp.eu.hcompany.ai/api/v2/sessions"
payload := strings.NewReader("{\n \"agent\": {},\n \"messages\": [\n {}\n ],\n \"max_steps\": 123,\n \"max_time_s\": 123,\n \"idle_timeout_s\": 123,\n \"delete_after_min\": {},\n \"delete_screenshot_after_min\": {},\n \"queue\": true,\n \"group_id\": \"<string>\",\n \"parent_session_id\": \"<string>\",\n \"overrides\": {}\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://agp.eu.hcompany.ai/api/v2/sessions")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"agent\": {},\n \"messages\": [\n {}\n ],\n \"max_steps\": 123,\n \"max_time_s\": 123,\n \"idle_timeout_s\": 123,\n \"delete_after_min\": {},\n \"delete_screenshot_after_min\": {},\n \"queue\": true,\n \"group_id\": \"<string>\",\n \"parent_session_id\": \"<string>\",\n \"overrides\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://agp.eu.hcompany.ai/api/v2/sessions")
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 \"agent\": {},\n \"messages\": [\n {}\n ],\n \"max_steps\": 123,\n \"max_time_s\": 123,\n \"idle_timeout_s\": 123,\n \"delete_after_min\": {},\n \"delete_screenshot_after_min\": {},\n \"queue\": true,\n \"group_id\": \"<string>\",\n \"parent_session_id\": \"<string>\",\n \"overrides\": {}\n}"
response = http.request(request)
puts response.read_bodyCreates a session that runs an agent on a task. With a free slot, the session starts
pending and moves to running once the agent launches. Above your concurrency limit it is accepted as queued and starts when a slot frees up (set queue: false to get a 429 instead).
Returns 201 with the created session object, status pending or queued.
Headers
string
Optional idempotency key (1 to 255 characters). Safe retry within 24 hours: the same key returns the original session. Reusing it with a different body returns
422.Request body
string | object
required
A catalog identifier (e.g.
"h/web-surfer-flash") or an inline agent, which follows the same rules: environments is required (at most one per kind) and may be [] only with subagents or custom tools. The session reads environments, skills, and subagents from the agent."agent": "h/web-surfer-flash"
"agent": {
"name": "weather-agent",
"description": "Looks up weather by city",
"environments": [
{
"id": "browser",
"kind": "web",
"mode": {"type": "visual", "width": 1280, "height": 720},
"start_url": "https://www.bing.com/"
}
]
}
string | object | object[]
The initial task, queued before the agent’s first step: a plain string (one user message), one message object, or a list. Each message object has:
type(string, optional):"user_message", the default.message(string, required): the instruction or task.images(string[], optional): base64 data URIs to attach (e.g.data:image/png;base64,...).files(object[], optional): files to attach, up to 10 and 7 MB in total. Each is{ name, source, type: "base64", media_type? }(media_typeis guessed if omitted). Saved underfiles/in a workstation or code sandbox workspace, and~/Downloadson a cloud browser.caller_id(string, optional): the sender. Defaults touser. Leave it unset for normal user input.
"messages": [
{"type": "user_message", "message": "Book a flight from Paris to Tokyo on June 15"}
]
integer
Cap on steps, where each step is one decide-and-act cycle. Minimum
1. At the cap the agent is asked for a final answer from what it has so far (it is not hard-killed). Omit to run uncapped.number
Cap on wall-clock seconds, greater than
0. At the cap, as with max_steps, the agent is asked for a final answer. Omit to run uncapped.integer
integer | null
Minutes after the session finishes before it is deleted, with its events and screenshots. Minimum
1. Omit it to keep the session for the retention period in your privacy settings. A value deletes it sooner. null adds no expiry beyond that period.integer | null
Minutes after the session finishes before its screenshots are deleted, to expire visual data sooner than the session. Minimum
1. Omit it or pass null to keep screenshots as long as the session.boolean
default:"true"
At your concurrency limit, accept the session as
queued instead of rejecting it with 429. Queued sessions don’t count against your quota and start oldest first as running sessions finish. Set false to fail fast.string
Tag for grouping related sessions. Filter on it with
GET /sessions?group_id=....string
Parent session id, for multi-agent runs. The parent’s status lists this session in
subagent_session_ids. Child sessions never queue: at capacity the create fails with 429 even when queue is true, since a child queued behind its own parent would deadlock it.object
Per-run tweaks applied after the agent (and its environments, skills, and subagents) are resolved, so you can adjust a catalog agent for one run. Keys are dotted paths, and
[field=value] selects list members. Each value is validated against the field it targets: an unknown path or wrong type returns 422. See Overrides."overrides": {
"agent.environments[kind=web].start_url": "https://www.bing.com/",
"agent.answer_format": {
"type": "object",
"properties": {"price": {"type": "number"}},
"required": ["price"]
}
}
Examples
Basic session
Reference a catalog agent. Its stored spec supplies the environments:# `hai run` creates the session and blocks until the agent answers
hai run "Find the best-rated sushi restaurants in San Francisco" \
--agent h/web-surfer-flash
curl -X POST https://agp.eu.hcompany.ai/api/v2/sessions \
-H "Authorization: Bearer $HAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"agent": "h/web-surfer-flash",
"messages": [
{"type": "user_message", "message": "Find the best-rated sushi restaurants in San Francisco"}
]
}'
from hai_agents import Client
client = Client()
session = client.sessions.create_session(
agent="h/web-surfer-flash",
messages="Find the best-rated sushi restaurants in San Francisco",
)
print(session.id)
import { HaiAgentsClient } from "hai-agents";
const client = new HaiAgentsClient();
const session = await client.sessions.createSession({
body: {
agent: "h/web-surfer-flash",
messages: "Find the best-rated sushi restaurants in San Francisco",
},
});
console.log(session.id);
Response
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"request": {
"agent": {"name": "h/web-surfer-flash", "model": "holo4-35b-a3b", "...": "..."},
"messages": [
{"type": "user_message", "message": "Find the best-rated sushi restaurants in San Francisco"}
],
"...": "..."
},
"status": {
"status": "pending",
"error": null,
"error_code": null,
"outcome": null,
"steps": 0,
"usage_per_model": [],
"subagent_session_ids": []
},
"agent_view_url": "https://platform.hcompany.ai/agents/sessions/a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"latest_answer": null,
"created_at": "2026-05-07T14:30:00Z",
"started_at": null,
"finished_at": null
}
With idempotency key
curl -X POST https://agp.eu.hcompany.ai/api/v2/sessions \
-H "Authorization: Bearer $HAI_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: my-unique-key-123" \
-d '{
"agent": "h/web-surfer-flash",
"messages": [
{"type": "user_message", "message": "Search for direct flights from CDG to NRT on June 15"}
]
}'
session = client.sessions.create_session(
agent="h/web-surfer-flash",
messages="Search for direct flights from CDG to NRT on June 15",
idempotency_key="my-unique-key-123",
)
const session = await client.sessions.createSession({
idempotencyKey: "my-unique-key-123",
body: {
agent: "h/web-surfer-flash",
messages: "Search for direct flights from CDG to NRT on June 15",
},
});
With an inline agent
Pass an inline agent instead of a catalog id to set environments (or any other field) per session. Environments nest underagent.
curl -X POST https://agp.eu.hcompany.ai/api/v2/sessions \
-H "Authorization: Bearer $HAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"agent": {
"name": "web-price-finder",
"description": "Web browsing agent with a custom browser config",
"environments": [
{"id": "browser", "kind": "web", "mode": {"type": "visual", "width": 1280, "height": 720}, "start_url": "https://www.bing.com"}
]
},
"messages": [
{"type": "user_message", "message": "Find the current price of the Framework 13 laptop and report the lowest you find"}
]
}'
session = client.sessions.create_session(
agent={
"name": "web-price-finder",
"description": "Web browsing agent with a custom browser config",
"environments": [
{
"id": "browser",
"kind": "web",
"mode": {"type": "visual", "width": 1280, "height": 720},
"start_url": "https://www.bing.com",
}
],
},
messages="Find the current price of the Framework 13 laptop and report the lowest you find",
)
const session = await client.sessions.createSession({
body: {
agent: {
name: "web-price-finder",
description: "Web browsing agent with a custom browser config",
environments: [
{
id: "browser",
kind: "web",
mode: { type: "visual", width: 1280, height: 720 },
startUrl: "https://www.bing.com",
},
],
},
messages: "Find the current price of the Framework 13 laptop and report the lowest you find",
},
});
With per-run overrides
Send a catalog agent to a different start URL for this run only:hai run "Find the cheapest direct flight CDG to NRT next month" \
--agent h/web-surfer-flash \
--override 'agent.environments[kind=web].start_url=https://www.google.com/travel/flights'
curl -X POST https://agp.eu.hcompany.ai/api/v2/sessions \
-H "Authorization: Bearer $HAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"agent": "h/web-surfer-flash",
"messages": [
{"type": "user_message", "message": "Find the cheapest direct flight CDG to NRT next month"}
],
"overrides": {
"agent.environments[kind=web].start_url": "https://www.google.com/travel/flights"
}
}'
session = client.sessions.create_session(
agent="h/web-surfer-flash",
messages="Find the cheapest direct flight CDG to NRT next month",
overrides={
"agent.environments[kind=web].start_url": "https://www.google.com/travel/flights",
},
)
const session = await client.sessions.createSession({
body: {
agent: "h/web-surfer-flash",
messages: "Find the cheapest direct flight CDG to NRT next month",
overrides: {
"agent.environments[kind=web].start_url": "https://www.google.com/travel/flights",
},
},
});
Child session (multi-agent)
See Multi-agent.curl -X POST https://agp.eu.hcompany.ai/api/v2/sessions \
-H "Authorization: Bearer $HAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"agent": "h/web-surfer-flash",
"parent_session_id": "parent-session-uuid",
"group_id": "trip-planning-001",
"messages": [
{"type": "user_message", "message": "Find hotels near Shinjuku station under $150/night"}
]
}'
session = client.sessions.create_session(
agent="h/web-surfer-flash",
parent_session_id="parent-session-uuid",
group_id="trip-planning-001",
messages="Find hotels near Shinjuku station under $150/night",
)
const session = await client.sessions.createSession({
body: {
agent: "h/web-surfer-flash",
parentSessionId: "parent-session-uuid",
groupId: "trip-planning-001",
messages: "Find hotels near Shinjuku station under $150/night",
},
});
Errors
| Status | Cause |
|---|---|
400 | The resolved request is invalid (for example an override producing an impossible configuration). |
402 | Your organization’s monthly token budget is exhausted. See Plans and limits. |
404 | The referenced agent doesn’t exist or isn’t visible to you. |
409 | An Idempotency-Key from a still in-flight request was reused before it completed. Retry after Retry-After. |
422 | Body failed validation, or an Idempotency-Key was reused with a different body. |
429 | Concurrency quota exceeded with queue: false, the queue itself is full, or the create carries a parent_session_id while at capacity. See Plans and limits. |
Was this page helpful?