Quickstart
Before you begin
- Make sure your organization has at least one agent that you can run. If it has none, create one in the app or with Create an agent.
- Install the tools for the language you use:
curlandjq, theanthropicPython package, or the@anthropic-ai/sdkNode package.
env_default. For every other difference, see
Coming from Anthropic’s API.-
Create a key and set your host
In the app, go to Settings > API > Task keys > New key and create a Personal key with the default capabilities. Use a personal key because your own code calls agents on your behalf. If an automation calls them, see Choose a key. Copy the key, because it is shown only once. In every shell you use, export
CONTEXT_BASE_URLandCONTEXT_API_KEYas shown in the cURL tab. The Python and TypeScript clients read both from the environment. SetCONTEXT_BASE_URLto the host without/v1, because the SDKs add/v1themselves.cURL export CONTEXT_BASE_URL="https://api.context.ai"export CONTEXT_API_KEY="tsk_..."Python import osfrom anthropic import Anthropicclient = Anthropic(base_url=os.environ["CONTEXT_BASE_URL"],api_key=os.environ["CONTEXT_API_KEY"],max_retries=0,)TypeScript import Anthropic, { toFile } from "@anthropic-ai/sdk"import { readFile } from "node:fs/promises"const client = new Anthropic({baseURL: process.env.CONTEXT_BASE_URL,apiKey: process.env.CONTEXT_API_KEY,maxRetries: 0,}) -
Pick an agent
List the agents your key can run. In the last line, replace the example ID with the ID of the agent you want.
cURL curl -sS "$CONTEXT_BASE_URL/v1/agents" -H "x-api-key: $CONTEXT_API_KEY" | jq -r '.data[] | "\(.id) \(.name)"'export AGENT_ID="6f1c2a9e-0d4b-4c57-9a3e-2b7d8e1f4c60"Python for agent in client.beta.agents.list():print(agent.id, agent.name)agent_id = "6f1c2a9e-0d4b-4c57-9a3e-2b7d8e1f4c60"TypeScript for await (const agent of client.beta.agents.list()) console.log(agent.id, agent.name)const agentId = "6f1c2a9e-0d4b-4c57-9a3e-2b7d8e1f4c60" -
Upload a file
Make a small CSV and upload it. The file goes to your Drive in the app.
cURL printf 'city,population\nTokyo,37400000\nDelhi,31000000\n' > cities.csvexport FILE_ID=$(curl -sS -X POST "$CONTEXT_BASE_URL/v1/files" -H "x-api-key: $CONTEXT_API_KEY" \-F "file=@cities.csv;type=text/csv" | jq -r .id)Python from pathlib import PathPath("cities.csv").write_text("city,population\nTokyo,37400000\nDelhi,31000000\n")file_id = client.beta.files.upload(file=Path("cities.csv")).idTypeScript import { writeFile } from "node:fs/promises"await writeFile("cities.csv", "city,population\nTokyo,37400000\nDelhi,31000000\n")const fileId = (await client.beta.files.upload({file: await toFile(await readFile("cities.csv"), "cities.csv", { type: "text/csv" }),})).id -
Create a session with the file
Create a session that runs the agent with the file attached. Set
environment_idtoenv_defaultto run it in a cloud sandbox that Context starts for the session. For more information, see Environments. The session startsidle. The response lists the file underresourceswithmount_path: "inputs/cities.csv", which is where the session finds it. If the agent isn’t in a workspace you work in, the request returns400with a message that names the agent; create the agent withmetadata.workspace_idor pick another agent.cURL export SESSION_ID=$(curl -sS -X POST "$CONTEXT_BASE_URL/v1/sessions" -H "x-api-key: $CONTEXT_API_KEY" \-H "content-type: application/json" \-d "{\"agent\": \"$AGENT_ID\", \"environment_id\": \"env_default\", \"title\": \"Quickstart\",\"resources\": [{\"type\": \"file\", \"file_id\": \"$FILE_ID\"}]}" | jq -r .id)Python session = client.beta.sessions.create(agent=agent_id,environment_id="env_default",title="Quickstart",resources=[{"type": "file", "file_id": file_id}],)print(session.id, session.resources[0].mount_path)TypeScript const session = await client.beta.sessions.create({agent: agentId,environment_id: "env_default",title: "Quickstart",resources: [{ type: "file", file_id: fileId }],})console.log(session.id, session.resources[0].mount_path) -
Open the stream, then send a message
The stream carries only what happens after it opens, so open it first. With cURL, run the stream in one terminal and send the message from a second terminal that has the same variables set. The agent has finished replying when the stream sends a
session.status_idleevent whosestop_reason.typeisn’trequires_action. If the agent asks to run a tool that needs your approval, follow the tool approvals playbook.cURL # Terminal 1: watch the streamcurl -sSN "$CONTEXT_BASE_URL/v1/sessions/$SESSION_ID/events/stream" -H "x-api-key: $CONTEXT_API_KEY"# Terminal 2: send the messagecurl -sS -X POST "$CONTEXT_BASE_URL/v1/sessions/$SESSION_ID/events" -H "x-api-key: $CONTEXT_API_KEY" \-H "content-type: application/json" \-d '{"events": [{"type": "user.message", "content": [{"type": "text", "text": "Read inputs/cities.csv and name the largest city."}]}]}'Python with client.beta.sessions.events.stream(session.id) as stream:client.beta.sessions.events.send(session.id,events=[{"type": "user.message", "content": [{"type": "text", "text": "Read inputs/cities.csv and name the largest city."}]}],)for event in stream:if event.type == "agent.message":print("".join(block.text for block in event.content))if event.type == "session.status_idle" and event.stop_reason.type != "requires_action":breakTypeScript const stream = await client.beta.sessions.events.stream(session.id)await client.beta.sessions.events.send(session.id, {events: [{ type: "user.message", content: [{ type: "text", text: "Read inputs/cities.csv and name the largest city." }] }],})for await (const event of stream) {if (event.type === "agent.message") console.log(event.content.map((block) => block.text).join(""))if (event.type === "session.status_idle" && event.stop_reason.type !== "requires_action") break}The agent replies with something like
Tokyo is the largest city, with 37,400,000 people.With cURL, terminal 1 prints one frame per event. The reply arrives as anagent.messageframe, and asession.status_idleframe marks the end of the reply. Each frame hasid,eventanddatalines, as shown in Stream events. -
Archive the session and delete the file
Archiving ends the session and returns it with status
terminated. Its history stays readable. You can delete a file after every session that uses it is archived. Deleting it earlier returns400. Deleting a file is permanent.cURL curl -sS -X POST "$CONTEXT_BASE_URL/v1/sessions/$SESSION_ID/archive" -H "x-api-key: $CONTEXT_API_KEY" | jq -r .statuscurl -sS -X DELETE "$CONTEXT_BASE_URL/v1/files/$FILE_ID" -H "x-api-key: $CONTEXT_API_KEY"Python print(client.beta.sessions.archive(session.id).status) # terminatedclient.beta.files.delete(file_id)TypeScript console.log((await client.beta.sessions.archive(session.id)).status) // terminatedawait client.beta.files.delete(fileId)
What happened in this quickstart
- The session is a task in the Context app. Its transcript is there, under the title you gave it.
- The upload went to your Drive in the app. The session reads it from its
inputs/folder. - The stream was live from the moment it opened and carried nothing from before. List events returns the whole history.
- Archiving ended the session and kept its history readable. To remove a session for good, use Delete a session with a key that has
sessions:delete.
Next steps
- Sessions explains what each session status means and how to rename and archive a session.
- Stream events shows which frames the stream sends, how it ends and how to reconnect without losing events.
- The tool approvals playbook shows how to approve or deny a tool call when a session goes idle with
requires_action.