> ## Documentation Index
> Fetch the complete documentation index at: https://docs.simular.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# curl

> The whole loop from a shell, with jq.

Set the key and host once:

```bash theme={null}
export SAI_API_KEY="sapi_..."
export SAI_API_URL="https://api.simular.ai"
```

## Start a task

```bash theme={null}
SESSION=$(curl -s "$SAI_API_URL/v1/agents/message" \
  -H "Authorization: Bearer $SAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"message":"Open Notepad, type hello, save it to the desktop as hello.txt","wait":false}' \
  | jq -r .sessionId)
echo "$SESSION"
```

## Poll until done

```bash theme={null}
CURSOR=""
while :; do
  RESP=$(curl -s "$SAI_API_URL/v1/agents/events?sessionId=$SESSION&since=$CURSOR&wait=30" \
    -H "Authorization: Bearer $SAI_API_KEY")
  CURSOR=$(echo "$RESP" | jq -r .cursor)
  STATUS=$(echo "$RESP" | jq -r .status)
  echo "$RESP" | jq -c '.events[] | select(.type=="data-progress") | .data.text'
  case "$STATUS" in
    running) ;;
    needs_approval)
      echo "$RESP" | jq '.events[] | select(.type=="data-approval-request") | .data'
      break ;;
    idle)
      echo "$RESP" | jq -r .text
      break ;;
    error)
      echo "$RESP" | jq '.events[] | select(.type=="error")'
      break ;;
  esac
done
```

An empty `since` on the first call is the same as omitting it.

## Answer an approval

When the loop prints an approval with `"isLinkOnly": false`:

```bash theme={null}
curl -s "$SAI_API_URL/v1/agents/approve" \
  -H "Authorization: Bearer $SAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"approvalId":"ap_7Qw","response":"yes"}'
```

When it prints `"isLinkOnly": true`, open the `approvalUrl` in a browser. Then run the poll loop again with the same `SESSION` and `CURSOR`.

The poll response also carries the blocking approval as a top-level `approval` field, so `jq .approval` works when the event has already scrolled past.

## Attach a file

```bash theme={null}
ATTACHMENT=$(curl -s "$SAI_API_URL/v1/agents/upload" \
  -H "Authorization: Bearer $SAI_API_KEY" \
  -H "x-filename: report.pdf" \
  --data-binary @./report.pdf)

curl -s "$SAI_API_URL/v1/agents/message" \
  -H "Authorization: Bearer $SAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --argjson a "$ATTACHMENT" \
    '{message:"Summarise the attached PDF in five bullets", wait:false, attachments:[$a]}')"
```

## Stop a task

```bash theme={null}
curl -s "$SAI_API_URL/v1/agents/abort" \
  -H "Authorization: Bearer $SAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"sessionId\":\"$SESSION\"}"
```

## Stream instead

Leave `wait` out and read the SSE frames as they arrive:

```bash theme={null}
curl -N "$SAI_API_URL/v1/agents/message" \
  -H "Authorization: Bearer $SAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"message":"What is on the screen right now?"}'
```
