Create an agent session, stream the first response, and send a follow-up.
The Sessions API lets you start a conversation with a Blocks agent and stream its responses over plain HTTP. Every endpoint lives under /rest/v1, accepts and returns JSON, and authenticates with a workspace-scoped API key.
Create a Blocks account, then generate a workspace API key from Settings > API Keys. Set the API key in your environment as BLOCKS_API_KEY before running the snippets below. For example:
Create a session — POST /rest/v1/sessions. The response includes _links.final_message.href, a pre-built URL for polling the assistant’s reply.
Poll the URL — GET it until items is non-empty.
const BASE_URL = "https://api.blocks.team";const headers = { Authorization: `ApiKey ${process.env.BLOCKS_API_KEY}`, "Content-Type": "application/json",};// 1. Create a session.const session = await fetch(`${BASE_URL}/rest/v1/sessions`, { method: "POST", headers, body: JSON.stringify({ agent_name: "claude", message: "Say hello and tell me a one-sentence fun fact about octopuses.", }),}).then((r) => r.json());// 2. Poll for the assistant's final message.while (true) { const page = await fetch(session._links.final_message.href, { headers }).then((r) => r.json()); if (page.items.length > 0) { console.log(page.items[0].message); break; } await new Promise((r) => setTimeout(r, 5000));}
import os, time, requestsBASE_URL = "https://api.blocks.team"HEADERS = { "Authorization": f"ApiKey {os.environ['BLOCKS_API_KEY']}", "Content-Type": "application/json",}# 1. Create a session.session = requests.post(f"{BASE_URL}/rest/v1/sessions", headers=HEADERS, json={ "agent_name": "claude", "message": "Say hello and tell me a one-sentence fun fact about octopuses.",}).json()# 2. Poll for the assistant's final message.while True: page = requests.get(session["_links"]["final_message"]["href"], headers=HEADERS).json() if page["items"]: print(page["items"][0]["message"]) break time.sleep(5)
BASE_URL="https://api.blocks.team"AUTH="Authorization: ApiKey $BLOCKS_API_KEY"# 1. Create a session.SESSION=$(curl -s -X POST "$BASE_URL/rest/v1/sessions" \ -H "$AUTH" -H "Content-Type: application/json" \ -d '{"agent_name":"claude","message":"Say hello and tell me a one-sentence fun fact about octopuses."}')SESSION_ID=$(echo "$SESSION" | jq -r '.id')FINAL_URL=$(echo "$SESSION" | jq -r '._links.final_message.href')# 2. Poll for the assistant's final message.while :; do PAGE=$(curl -s -H "$AUTH" "$FINAL_URL") if [ "$(echo "$PAGE" | jq '.items | length')" -gt 0 ]; then echo "$PAGE" | jq -r '.items[0].message' break fi sleep 5done
import java.net.URI;import java.net.http.*;import com.fasterxml.jackson.databind.*;String BASE_URL = "https://api.blocks.team";String AUTH = "ApiKey " + System.getenv("BLOCKS_API_KEY");HttpClient http = HttpClient.newHttpClient();ObjectMapper json = new ObjectMapper();// 1. Create a session.JsonNode session = json.readTree(http.send( HttpRequest.newBuilder(URI.create(BASE_URL + "/rest/v1/sessions")) .header("Authorization", AUTH).header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString( "{\"agent_name\":\"claude\",\"message\":\"Say hello and tell me a one-sentence fun fact about octopuses.\"}")) .build(), HttpResponse.BodyHandlers.ofString()).body());String sessionId = session.get("id").asText();String finalUrl = session.at("/_links/final_message/href").asText();// 2. Poll for the assistant's final message.while (true) { JsonNode page = json.readTree(http.send( HttpRequest.newBuilder(URI.create(finalUrl)).header("Authorization", AUTH).build(), HttpResponse.BodyHandlers.ofString()).body()); if (page.get("items").size() > 0) { System.out.println(page.at("/items/0/message").asText()); break; } Thread.sleep(5000);}
require "net/http"require "json"BASE_URL = "https://api.blocks.team"HEADERS = { "Authorization" => "ApiKey #{ENV['BLOCKS_API_KEY']}", "Content-Type" => "application/json",}# 1. Create a session.session = JSON.parse(Net::HTTP.post( URI("#{BASE_URL}/rest/v1/sessions"), JSON.generate({ agent_name: "claude", message: "Say hello and tell me a one-sentence fun fact about octopuses.", }), HEADERS,).body)# 2. Poll for the assistant's final message.loop do page = JSON.parse(Net::HTTP.get(URI(session["_links"]["final_message"]["href"]), HEADERS)) break puts(page["items"][0]["message"]) if page["items"].any? sleep 5end
package mainimport ( "bytes" "encoding/json" "fmt" "net/http" "os" "time")const BaseURL = "https://api.blocks.team"func main() { auth := "ApiKey " + os.Getenv("BLOCKS_API_KEY") // 1. Create a session. body, _ := json.Marshal(map[string]string{ "agent_name": "claude", "message": "Say hello and tell me a one-sentence fun fact about octopuses.", }) req, _ := http.NewRequest("POST", BaseURL+"/rest/v1/sessions", bytes.NewReader(body)) req.Header.Set("Authorization", auth) req.Header.Set("Content-Type", "application/json") res, _ := http.DefaultClient.Do(req) var session struct { ID string `json:"id"` Links struct { FinalMessage struct{ Href string } `json:"final_message"` } `json:"_links"` } json.NewDecoder(res.Body).Decode(&session) res.Body.Close() // 2. Poll for the assistant's final message. for { req, _ := http.NewRequest("GET", session.Links.FinalMessage.Href, nil) req.Header.Set("Authorization", auth) res, _ := http.DefaultClient.Do(req) var page struct { Items []struct{ Message string } `json:"items"` } json.NewDecoder(res.Body).Decode(&page) res.Body.Close() if len(page.Items) > 0 { fmt.Println(page.Items[0].Message) break } time.Sleep(5 * time.Second) }}
Send a follow-up — POST /rest/v1/sessions/{session_id}/messages. The response returns its own _links.final_message.href, the same shortcut as create.
Poll the new thread’s URL — same pattern as above.
Follow-ups can be sent at any time — including while the agent is still working — and will interrupt the in-flight turn.
The snippets below assume session, headers, and BASE_URL are still in scope from the previous step.
// 3. Send a follow-up.const followup = await fetch(`${BASE_URL}/rest/v1/sessions/${session.id}/messages`, { method: "POST", headers, body: JSON.stringify({ message: "Cool — now tell me one about cuttlefish." }),}).then((r) => r.json());// 4. Poll the follow-up's thread.while (true) { const page = await fetch(followup._links.final_message.href, { headers }).then((r) => r.json()); if (page.items.length > 0) { console.log(page.items[0].message); break; } await new Promise((r) => setTimeout(r, 5000));}
# 3. Send a follow-up.followup = requests.post( f"{BASE_URL}/rest/v1/sessions/{session['id']}/messages", headers=HEADERS, json={"message": "Cool — now tell me one about cuttlefish."},).json()# 4. Poll the follow-up's thread.while True: page = requests.get(followup["_links"]["final_message"]["href"], headers=HEADERS).json() if page["items"]: print(page["items"][0]["message"]) break time.sleep(5)
# 3. Send a follow-up.FOLLOWUP=$(curl -s -X POST "$BASE_URL/rest/v1/sessions/$SESSION_ID/messages" \ -H "$AUTH" -H "Content-Type: application/json" \ -d '{"message":"Cool — now tell me one about cuttlefish."}')FOLLOW_URL=$(echo "$FOLLOWUP" | jq -r '._links.final_message.href')# 4. Poll the follow-up's thread.while :; do PAGE=$(curl -s -H "$AUTH" "$FOLLOW_URL") if [ "$(echo "$PAGE" | jq '.items | length')" -gt 0 ]; then echo "$PAGE" | jq -r '.items[0].message' break fi sleep 5done
// 3. Send a follow-up.JsonNode followup = json.readTree(http.send( HttpRequest.newBuilder(URI.create(BASE_URL + "/rest/v1/sessions/" + sessionId + "/messages")) .header("Authorization", AUTH).header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString( "{\"message\":\"Cool — now tell me one about cuttlefish.\"}")) .build(), HttpResponse.BodyHandlers.ofString()).body());String followUrl = followup.at("/_links/final_message/href").asText();// 4. Poll the follow-up's thread.while (true) { JsonNode page = json.readTree(http.send( HttpRequest.newBuilder(URI.create(followUrl)).header("Authorization", AUTH).build(), HttpResponse.BodyHandlers.ofString()).body()); if (page.get("items").size() > 0) { System.out.println(page.at("/items/0/message").asText()); break; } Thread.sleep(5000);}
# 3. Send a follow-up.followup = JSON.parse(Net::HTTP.post( URI("#{BASE_URL}/rest/v1/sessions/#{session['id']}/messages"), JSON.generate({ message: "Cool — now tell me one about cuttlefish." }), HEADERS,).body)# 4. Poll the follow-up's thread.loop do page = JSON.parse(Net::HTTP.get(URI(followup["_links"]["final_message"]["href"]), HEADERS)) break puts(page["items"][0]["message"]) if page["items"].any? sleep 5end