# Telnyx Agent Tools: Agent Browser — Full Documentation > Complete page content for Agent Browser (Agent Tools section) of the Telnyx developer docs (https://developers.telnyx.com). > This file: https://developers.telnyx.com/docs/development/llms/agent-tools-agent-browser-llms-full-txt · Root index: https://developers.telnyx.com/llms.txt ## Agent Browser ### Overview > Source: https://developers.telnyx.com/docs/agent-browser.md Agent Browser gives your application an isolated, short-lived Chromium instance through one API: create a browser session, navigate to pages within an allowed domain list, observe the DOM to get element references, interact with elements (click, fill, select), and take screenshots. It is built as a primitive for AI agents — every action returns structured JSON ready to feed a model as tool output. The semantic observation model means agents interact with element references instead of pixel coordinates. ## What You Can Do | Capability | Endpoint | Returns | | --- | --- | --- | | [Create Session](/docs/agent-browser/sessions) | `POST /v2/browser_sessions` | An isolated browser session | | [Navigate](/docs/agent-browser/actions) | `POST /v2/browser_sessions/:id/actions` | Page load with URL and title | | [Observe](/docs/agent-browser/observations) | `POST /v2/browser_sessions/:id/actions` | Element references (`refs`) and a text tree of the DOM | | [Click / Fill / Select](/docs/agent-browser/actions) | `POST /v2/browser_sessions/:id/actions` | Interaction with elements by ref | | [Screenshot](/docs/agent-browser/actions) | `POST /v2/browser_sessions/:id/actions` | A downloadable screenshot artifact | | [Batch](/docs/agent-browser/actions) | `POST /v2/browser_sessions/:id/actions` | Multiple actions in one request (1–50, sequential) | ## Next Steps First session to screenshot in a few minutes. Session lifecycle, allowed domains, and limits. All action types, batch, and the interaction loop. The observe → ref → click/fill flow explained. --- ### Get Started > Source: https://developers.telnyx.com/docs/agent-browser/getting-started.md Run the blocks below in order in the same **Bash** shell with `curl` and `jq` installed. Set `TELNYX_API_KEY` to your API key locally before starting; do not put it in shared logs. All resource IDs and element refs below come from your actual responses. ## Set Up Requests and Polling ```bash set -euo pipefail : "${TELNYX_API_KEY:?Set TELNYX_API_KEY to your Telnyx API key first}" API_HOST=https://api.telnyx.com API_BASE="$API_HOST/v2" # Each call is bounded; HTTP errors stop the example without retrying a mutation. api() { curl --fail-with-body --silent --show-error --connect-timeout 10 \ --max-time 90 -H "Authorization: Bearer $TELNYX_API_KEY" "$@" } # Submit once, then poll the returned ID. HTTP 200 alone does not mean success. run_action() { local response action_id status remaining deadline=$((SECONDS + 90)) response=$(api --max-time 35 -X POST \ "$API_BASE/browser_sessions/$SESSION_ID/actions?wait_seconds=25" \ -H "Content-Type: application/json" -d "$1") || return action_id=$(jq -er '.data.id' <<< "$response") || return while :; do status=$(jq -er '.data.status' <<< "$response") || return case "$status" in succeeded) printf '%s\n' "$response"; return 0 ;; failed|unknown) printf '%s\n' "$response" >&2; return 1 ;; queued|running) ;; *) printf 'Unexpected action status: %s\n' "$status" >&2; return 1 ;; esac remaining=$((deadline - SECONDS)) if ((remaining <= 1)); then printf 'Polling budget reached. Inspect action %s; do not resubmit blindly.\n' "$action_id" >&2 return 1 fi sleep 1 remaining=$((deadline - SECONDS)) if ((remaining <= 0)); then return 1; fi response=$(api --max-time "$remaining" \ "$API_BASE/browser_sessions/$SESSION_ID/actions/$action_id") || return done } ``` `wait_seconds` limits the submission wait, not execution time. A 202 means the action is still queued or running; the helper polls until `succeeded`, `failed`, or `unknown`. It stops on failures and HTTP errors, including 503. See [recovery guidance](/docs/agent-browser/actions#recovering-from-execution_lost) before repeating a request with an uncertain outcome. ## Create a Session Allow the example page and the IANA domains its link may navigate to, including subdomains: ```bash SESSION_RESPONSE=$(api -X POST "$API_BASE/browser_sessions" \ -H "Content-Type: application/json" \ -d '{"policy":{"allowed_domains":["example.com","iana.org","*.iana.org"]}}') SESSION_ID=$(jq -er '.data.id' <<< "$SESSION_RESPONSE") printf 'Session: %s\n' "$SESSION_ID" SESSION_DEADLINE=$((SECONDS + 90)) while [[ $(jq -er '.data.status' <<< "$SESSION_RESPONSE") == provisioning ]]; do REMAINING=$((SESSION_DEADLINE - SECONDS)) if ((REMAINING <= 1)); then printf 'Session is not ready within the polling budget.\n' >&2 exit 1 fi sleep 1 REMAINING=$((SESSION_DEADLINE - SECONDS)) if ((REMAINING <= 0)); then exit 1; fi SESSION_RESPONSE=$(api --max-time "$REMAINING" "$API_BASE/browser_sessions/$SESSION_ID") done jq -e '.data.status == "ready"' <<< "$SESSION_RESPONSE" >/dev/null ``` Creation returns HTTP 201. Only a `ready` session accepts new actions. If it is closing, closed, failed, or expired, stop instead of retrying actions on it. ## Navigate ```bash NAVIGATION_RESPONSE=$(run_action '{"type":"navigate","url":"https://example.com/"}') jq '.data.result' <<< "$NAVIGATION_RESPONSE" ``` ## Observe and Select a Current Ref The page currently has a link to IANA. Select the link from the returned refs rather than assuming an ID such as `e13`. Full observation refs are available only in the original successful POST response. GET polling returns metadata with empty refs. If the observe action needed polling, the bounded loop below requests a fresh observation after that action finishes. It never retries a click or other mutation. ```bash OBSERVATION_RESPONSE='' for ATTEMPT in 1 2 3; do OBSERVATION_RESPONSE=$(run_action '{"type":"observe"}') if jq -e '(.data.result.observation.refs // {} | length) > 0' \ <<< "$OBSERVATION_RESPONSE" >/dev/null; then break fi done OBSERVATION_ID=$(jq -er '.data.result.observation.observation_id' <<< "$OBSERVATION_RESPONSE") LINK_REF=$(jq -er '[.data.result.observation.refs | to_entries[] | select(.value.role == "link")][0].key // error("No link ref available; inspect a fresh observation")' \ <<< "$OBSERVATION_RESPONSE") jq '.data.result.observation.refs' <<< "$OBSERVATION_RESPONSE" ``` If the page changes or no link ref is available, the script stops. Inspect a fresh observation instead of substituting a sample ref. For other pages, choose the intended element by its role and name. ## Click the Observed Link ```bash CLICK_BODY=$(jq -n --arg observation_id "$OBSERVATION_ID" --arg ref "$LINK_REF" \ '{type:"click", observation_id:$observation_id, ref:$ref}') CLICK_RESPONSE=$(run_action "$CLICK_BODY") jq '.data.result' <<< "$CLICK_RESPONSE" ``` Navigation invalidates the prior observation. Obtain a new observation before any further interaction by ref. ## Screenshot and Download ```bash SCREENSHOT_RESPONSE=$(run_action '{"type":"screenshot"}') ARTIFACT_ID=$(jq -er '.data.result.artifact.artifact_id' <<< "$SCREENSHOT_RESPONSE") ARTIFACT_RESPONSE=$(api "$API_BASE/browser_sessions/$SESSION_ID/artifacts/$ARTIFACT_ID") DOWNLOAD_PATH=$(jq -er '.data.download_url' <<< "$ARTIFACT_RESPONSE") case "$DOWNLOAD_PATH" in /v2/artifact_downloads/*) ;; *) printf 'Unexpected artifact download path\n' >&2; exit 1 ;; esac api "$API_HOST$DOWNLOAD_PATH" -o screenshot.png ``` `download_url` is a signed relative path. Prepend the API host and include Bearer authentication on the download request too. The screenshot remains downloadable until its artifact expiry; an expired download signature requires a fresh metadata request. ## Close the Session ```bash CLOSE_RESPONSE=$(api -X DELETE "$API_BASE/browser_sessions/$SESSION_ID") jq '.data.status' <<< "$CLOSE_RESPONSE" ``` Closing a ready session normally returns `closed` and releases its resources. An already terminal session is returned unchanged. If an earlier step stopped, inspect the printed session ID and close the session when appropriate; otherwise it expires according to its lifetime or idle timeout. --- ## Features ### Sessions > Source: https://developers.telnyx.com/docs/agent-browser/sessions.md A browser session is an isolated, short-lived Chromium instance with network access restricted to the domains you allow. ## Create a Session ```bash curl -X POST https://api.telnyx.com/v2/browser_sessions \ -H "Authorization: Bearer ***" \ -H "Content-Type: application/json" \ -d '{ "policy": { "allowed_domains": ["example.com", "*.example.com"] }, "limits": { "lifetime_s": 600, "idle_timeout_s": 120 } }' ``` ### Policy | Field | Type | Required | Description | | --- | --- | --- | --- | | `allowed_domains` | string[] | Yes | 1–50 domain patterns the browser can navigate to. | ### allowed_domains Matching Matching is exact-only — no implicit subdomain matching. | Pattern | Matches | Does NOT match | | --- | --- | --- | | `example.com` | `example.com` | `www.example.com`, `api.example.com` | | `*.example.com` | `www.example.com`, `api.example.com` | `example.com` (the apex) | | `wikipedia.org` | `wikipedia.org` | `en.wikipedia.org`, `www.wikipedia.org` | | `*.wikipedia.org` | `en.wikipedia.org`, `www.wikipedia.org` | `wikipedia.org` (the apex) | To allow a domain **and** all its subdomains, list both: ```json { "policy": { "allowed_domains": ["wikipedia.org", "*.wikipedia.org"] } } ``` - Wildcard patterns use `*.` prefix — `*.example.com` matches any subdomain but **not** the apex itself. - Exact patterns (`example.com`) match only that exact hostname. - IP literals (e.g. `127.0.0.1`) are not allowed. ### Limits | Field | Type | Default | Min | Max | Description | | --- | --- | --- | --- | --- | --- | | `lifetime_s` | int | 900 | 60 | 1800 | Max session duration in seconds. Values above 1800 are rejected (400). | | `idle_timeout_s` | int | 300 | 30 | — (≤ `lifetime_s`) | Idle timeout in seconds. Must not exceed `lifetime_s`. | ### Idempotency and Concurrent-Session Quota Pass an optional `idempotency_key` (1–255 characters) in the create request body. Within the same organization, the same key and identical normalized policy, limits, and metadata return the existing session with HTTP 201. Defaults are applied before comparison. A different request with that key returns `409 idempotency_conflict`. A replay does not restart a closed, failed, or expired session. Creating a new session can return `429 quota_exceeded` with `retryable: true` when the organization's concurrent-session quota is reached. Close unneeded active sessions or wait for capacity before trying again. This is a session quota, not a per-key request-rate limit. ## Session Lifecycle | Status | Description | | --- | --- | | `provisioning` | Session is starting up. | | `ready` | Browser is up and accepting actions. | | `closing` | Session is being shut down. | | `closed` | Session closed, resources released. | | `failed` | Session failed (see `failure_reason`, e.g. `provision_timeout` when the session could not start). | | `expired` | Session exceeded its lifetime or idle timeout. | ## List Sessions ```bash curl -s https://api.telnyx.com/v2/browser_sessions?status=ready \ -H "Authorization: Bearer ***" ``` Filter by status: `provisioning`, `ready`, `closing`, `closed`, `failed`, `expired`. ## Get Session ```bash curl -s https://api.telnyx.com/v2/browser_sessions/$SESSION_ID \ -H "Authorization: Bearer ***" ``` ## Close Session ```bash curl -X DELETE https://api.telnyx.com/v2/browser_sessions/$SESSION_ID \ -H "Authorization: Bearer ***" ``` Closing a ready session normally returns `status: "closed"`. An already closed, failed, or expired session is returned unchanged. A provisioning session returns `409 session_not_ready`; poll its state before closing again. A request that cannot be completed reliably can return `503 execution_lost` with `retryable: true`; retrieve the session state before retrying the close. --- ### Actions > Source: https://developers.telnyx.com/docs/agent-browser/actions.md Actions are executed against a browser session via `POST /v2/browser_sessions/:id/actions`. Each session executes one action at a time. ## Action Types | Type | Requires `observation_id` | Key Fields | | --- | --- | --- | | `navigate` | No | `url` (max 2048), `wait_until?` (`load` \| `dom_stable` \| `none`, default `load`) | | `observe` | — | (returns `observation_id` + `refs`) | | `click` | **Yes** | `observation_id`, `ref`, `wait?` (`no_wait` \| `dom_stable` \| `url_change`, default `dom_stable`), `timeout_ms?` (100–15000, default 5000) | | `fill` | **Yes** | `observation_id`, `ref`, `value` (max 4096 chars) | | `select` | **Yes** | `observation_id`, `ref`, `value` (max 1024 chars) | | `press` | No | `key` (`Enter` \| `Tab` \| `Escape` \| `Backspace` \| `ArrowUp` \| `ArrowDown` \| `ArrowLeft` \| `ArrowRight` \| `PageUp` \| `PageDown` \| `Home` \| `End`) | | `scroll` | No | `delta_x?` (−5000–5000, default 0), `delta_y?` (−5000–5000, default 0) | | `wait_for` | No | `condition` (object: `{kind: "url_pattern", pattern}`, `{kind: "ref", observation_id, ref}`, `{kind: "text", text}`, `{kind: "dom_stable"}`), `timeout_ms?` (100–15000, default 5000) | | `screenshot` | No | (returns artifact) | | `batch` | Per sub-action | `actions[]` (1–50, non-recursive) | All actions accept optional `include_observation` (bool, default false) and `idempotency_key` (string). ## Common Fields | Field | Type | Default | Description | | --- | --- | --- | --- | | `include_observation` | bool | false | Return a fresh observation in the response (saves a separate observe call). | | `idempotency_key` | string | — | Dedup key. Reusing the key with an **identical** request replays the original resource. Reusing it with a **different** request returns `409 idempotency_conflict`. | ## Navigation ```bash curl -X POST https://api.telnyx.com/v2/browser_sessions/$SESSION_ID/actions \ -H "Authorization: Bearer ***" \ -H "Content-Type: application/json" \ -d '{ "type": "navigate", "url": "https://example.com/", "wait_until": "load" }' ``` `wait_until` controls when the action is considered complete: - `load` (default) — wait for the page `load` event. - `dom_stable` — wait until the DOM stops changing. - `none` — return immediately after navigation is initiated. Navigation to domains not in the session's `allowed_domains` returns HTTP 200 with the action in `status: "failed"` and `data.error.code: "policy_denied"` — execution failures like this are reported on the action resource, not as HTTP error statuses. ## Press ```bash curl -X POST https://api.telnyx.com/v2/browser_sessions/$SESSION_ID/actions \ -H "Authorization: Bearer ***" \ -H "Content-Type: application/json" \ -d '{ "type": "press", "key": "Enter" }' ``` ## Scroll ```bash curl -X POST https://api.telnyx.com/v2/browser_sessions/$SESSION_ID/actions \ -H "Authorization: Bearer ***" \ -H "Content-Type: application/json" \ -d '{ "type": "scroll", "delta_y": 500 }' ``` ## Wait For Wait for a condition to be met on the page: ```bash curl -X POST https://api.telnyx.com/v2/browser_sessions/$SESSION_ID/actions \ -H "Authorization: Bearer ***" \ -H "Content-Type: application/json" \ -d '{ "type": "wait_for", "condition": { "kind": "dom_stable" }, "timeout_ms": 5000 }' ``` Condition kinds: - `{ "kind": "url_pattern", "pattern": "*/login" }` — wait until the URL matches a pattern. - `{ "kind": "ref", "observation_id": "obs_...", "ref": "e1" }` — wait for an element to appear. - `{ "kind": "text", "text": "Welcome" }` — wait for text to appear on the page. - `{ "kind": "dom_stable" }` — wait until the DOM stops changing. ## Screenshot ```bash curl -X POST https://api.telnyx.com/v2/browser_sessions/$SESSION_ID/actions \ -H "Authorization: Bearer ***" \ -H "Content-Type: application/json" \ -d '{ "type": "screenshot" }' ``` Returns an artifact with `artifact_id`, `content_type`, and `size_bytes`. Download via: ```bash curl -s -X GET "https://api.telnyx.com/v2/browser_sessions/$SESSION_ID/artifacts/$ARTIFACT_ID" \ -H "Authorization: Bearer ***" | jq -r '.data.download_url' ``` ## Batch Actions Execute multiple actions in a single request. Sub-actions run sequentially. A failed sub-action stops the batch (non-atomic — prior mutations persist). ```bash curl -X POST https://api.telnyx.com/v2/browser_sessions/$SESSION_ID/actions \ -H "Authorization: Bearer ***" \ -H "Content-Type: application/json" \ -d '{ "type": "batch", "actions": [ { "type": "navigate", "url": "https://example.com/" }, { "type": "observe" } ] }' ``` - `actions[]` — 1 to 50 sub-actions. An empty array is rejected (400), and the array is non-recursive (batch inside batch → 400). - `include_observation` on a batch applies to the **last** sub-action only. - A failed sub-action stops the batch with `status: "failed"`. Earlier sub-actions have already mutated the browser (they are not rolled back), but partial sub-action results are **not** returned — `results[]` is present only when every sub-action completes. ## include_observation Add `include_observation: true` to any action to get a fresh observation in the response, saving a separate `observe` round-trip: ```bash curl -X POST https://api.telnyx.com/v2/browser_sessions/$SESSION_ID/actions \ -H "Authorization: Bearer ***" \ -H "Content-Type: application/json" \ -d '{ "type": "click", "observation_id": "obs_...", "ref": "e2", "include_observation": true }' ``` The response will include a new `observation_id` and `refs` for the resulting page. ## Action Failures vs HTTP Errors There are two distinct error surfaces: **Request errors** use HTTP error statuses and a top-level `error` object. The Code column is `error.code`: | HTTP | Code | Meaning | | --- | --- | --- | | 400 | `validation_error` | Invalid request body or parameters (unknown fields, missing required fields, out-of-range values). | | 401 | `10009` | Missing or invalid API key. Authentication failures use the standard Telnyx `errors[]` envelope, unlike action errors. | | 404 | `not_found` | Session, action, or artifact does not exist (or belongs to another organization). | | 409 | `session_not_ready` | New actions require a ready session. Poll while provisioning; closing, closed, failed, and expired sessions cannot accept new actions. | | 409 | `concurrent_action` | Another action is in flight. Wait for it to finish before submitting another. | | 409 | `idempotency_conflict` | Same `idempotency_key` submitted with a different normalized request. | | 503 | `execution_lost` | The request could not be completed reliably. The response has `retryable: true`, but does not prove that the action had no effect. Follow the recovery guidance below. | Session creation, not action submission, returns the session quota error below. See [Sessions](/docs/agent-browser/sessions). | Code | HTTP | Meaning | Retryable | | --- | --- | --- | --- | | `quota_exceeded` | 429 | Session creation rejected because the organization's concurrent-session quota is full. Close unneeded active sessions, or wait for the reconciler to release fenced slots, then retry. This is a session quota, not a per-key request-rate limit. | Yes | **Execution failures** are returned on the action resource inside HTTP 200 as `data.status: "failed"` (or `unknown`) with `data.error`: | Code | HTTP | Meaning | Retryable | | --- | --- | --- | --- | | `policy_denied` | 200 | URL not in `allowed_domains`. | No | | `stale_observation` | 200 | `observation_id` is no longer current; re-observe first. | No | | `stale_ref` | 200 | `ref` no longer resolves in the current observation. | No | | `navigation_blocked` | 200 | The browser refused the navigation. | No | | `timeout` | 200 | An execution deadline was exceeded, such as `timeout_ms` on `click` or `wait_for`; earlier effects are not rolled back. | Yes | | `execution_lost` | 200 | The execution outcome could not be determined; the action is `unknown`. The session may also be `failed` or otherwise terminal. | No | | `result_too_large` | 200 | Result exceeded the 256 KiB limit; reduce the result size. This is an action failure, not HTTP 413. | No | These codes travel in `data.error.code` inside an HTTP 200 response — the `HTTP` column records that carrier status, not a request failure. A `failed` or `unknown` action is terminal. Inspect the cause and any effects before deciding whether a new action is safe. For staleness, obtain a fresh observation and select a current ref. ### Recovering from execution_lost Do not blindly resubmit a mutation: a lost response or an `unknown` outcome may mean the action already took effect. A new idempotency key or a new session does not protect against duplicating those effects. 1. If you have an action ID, retrieve that action and inspect its status. Also retrieve the session. 2. If the original submission included `idempotency_key`, repeating the **same normalized request with the same key on the same session** retrieves an existing record when one exists, even after the session closes. It does not re-execute a terminal action. If no record exists, that submission can start a new action; only attempt it when safe. 3. Without a known action ID or idempotency key, verify the outcome in the target application before repeating a mutation. 4. Poll a `provisioning` session until ready. A `closing`, `closed`, `failed`, or `expired` session will not become ready again; use a new session for further work only after reconciling the original outcome. `session_not_ready` carries `retryable: true`, but that flag does not make a terminal session reusable. ## Polling Actions `wait_seconds` (0–25, default 10) limits only how long the submission request waits, not execution time. If the action is still `queued` or `running`, the response is `202 Accepted`; execution continues. Poll the returned action ID rather than submitting it again. GET returns HTTP 200 even while the action is still running, so inspect `data.status`: Full observation `tree` and `refs` are delivered only in the original successful submission response when it completes within the wait. Polling and idempotent replays return observation metadata with an empty tree and refs. If you need element refs after polling, submit a new `observe` with `wait_seconds=25`; see [Get Started](/docs/agent-browser/getting-started). ```bash curl -s https://api.telnyx.com/v2/browser_sessions/$SESSION_ID/actions/$ACTION_ID \ -H "Authorization: Bearer ***" ``` --- ### Observations > Source: https://developers.telnyx.com/docs/agent-browser/observations.md The API uses a **semantic observation model**: instead of clicking on pixel coordinates, you observe the DOM to get element references (`refs`), then use those refs to interact with elements. ## The Interaction Loop ``` navigate → observe → click / fill / select ▲ │ │ │ │ │ uses observation_id │ │ │ + ref from observe └───────────┘ ▼ (navigation invalidates observation) ``` 1. **Navigate** to a URL within the session's `allowed_domains`. 2. **Observe** to capture a snapshot of the page — returns `observation_id` and `refs`. 3. **Interact** using the `observation_id` and a `ref` from step 2. ## Observe ```bash curl -X POST https://api.telnyx.com/v2/browser_sessions/$SESSION_ID/actions \ -H "Authorization: Bearer ***" \ -H "Content-Type: application/json" \ -d '{ "type": "observe" }' ``` ```json { "data": { "status": "succeeded", "result": { "observation": { "observation_id": "obs_d9e5ab99-adf6-421e-b495-33f0ee727a52", "url": "https://example.com/", "title": "Example Domain", "refs": { "e1": { "role": "unknown", "name": "" }, "e13": { "role": "link", "name": "Learn more" } }, "tree": "- generic [active] [ref=e1]:\n - link \"Learn more\" [ref=e13] [cursor=pointer]:\n - /url: https://iana.org/help/example-domains", "truncated": false } } } } ``` Full `tree` and `refs` are available in the original successful submission response when the action completes within `wait_seconds`. GET polling and idempotent replays return observation metadata with `tree: ""`, `refs: {}`, and `ref_count` instead of the full snapshot. After a 202, wait for the action to finish, then submit a fresh `observe` with `wait_seconds=25` to obtain usable refs. Do not reuse sample refs from this page. ### Response Fields | Field | Description | | --- | --- | | `observation_id` | A unique identifier for this observation. Use it with `ref` in click/fill/select. | | `refs` | A map of element references (e.g. `e1`, `e13`) with `role` and `name`. | | `tree` | A human-readable text rendering of the DOM for inspection. | | `truncated` | Whether the tree was truncated due to size limits. | ## Why observation_id Expires The `observation_id` is invalidated when the page navigates. After any `navigate` action (including a `click` that triggers a navigation), you must call `observe` again to get a fresh `observation_id` and `refs`. Attempting to use a stale `observation_id` fails the action. The response is still HTTP 200 — the failure is on the action resource: ```json { "data": { "status": "failed", "error": { "code": "stale_observation", "retryable": false } } } ``` ## Interact by Ref Once you have an `observation_id` and `refs`, interact with elements: ### Click ```bash curl -X POST https://api.telnyx.com/v2/browser_sessions/$SESSION_ID/actions \ -H "Authorization: Bearer ***" \ -H "Content-Type: application/json" \ -d '{ "type": "click", "observation_id": "obs_d9e5ab99-...", "ref": "e13" }' ``` ### Fill (text input) ```bash curl -X POST https://api.telnyx.com/v2/browser_sessions/$SESSION_ID/actions \ -H "Authorization: Bearer ***" \ -H "Content-Type: application/json" \ -d '{ "type": "fill", "observation_id": "obs_...", "ref": "e5", "value": "user@example.com" }' ``` ### Select (dropdown) ```bash curl -X POST https://api.telnyx.com/v2/browser_sessions/$SESSION_ID/actions \ -H "Authorization: Bearer ***" \ -H "Content-Type: application/json" \ -d '{ "type": "select", "observation_id": "obs_...", "ref": "e8", "value": "pro" }' ``` ## include_observation Shortcut Use `include_observation: true` on a `click` or `navigate` action to get a fresh observation in the same response — saving a separate `observe` round-trip: ```bash curl -X POST https://api.telnyx.com/v2/browser_sessions/$SESSION_ID/actions \ -H "Authorization: Bearer ***" \ -H "Content-Type: application/json" \ -d '{ "type": "click", "observation_id": "obs_...", "ref": "e2", "include_observation": true }' ``` The response will include a new `observation_id` and `refs` for the page that resulted from the click. --- ## API Reference (Agent Browser) ### Browser Sessions - [Create browser session](https://developers.telnyx.com/api-reference/browser-sessions/create-browser-session.md): Creates an isolated browser session with network access restricted to the domains you allow. - [List browser sessions](https://developers.telnyx.com/api-reference/browser-sessions/list-browser-sessions.md): Lists sessions for the authenticated org. Optional status filter. - [Get browser session](https://developers.telnyx.com/api-reference/browser-sessions/get-browser-session.md): Returns the current status of a browser session. - [Close browser session](https://developers.telnyx.com/api-reference/browser-sessions/close-browser-session.md): Closes a ready session and releases its resources. An already closed, failed, or expired session is returned unchanged; a provisioning session returns 409 sess… ### Actions - [Execute browser action](https://developers.telnyx.com/api-reference/actions/execute-browser-action.md): Executes a browser action on the session. Returns 200 if completed within wait_seconds, 202 if still in-flight. - [Get action result](https://developers.telnyx.com/api-reference/actions/get-action-result.md): Returns the stored status and result of an action. Use this to poll actions that returned 202; HTTP 200 can contain any action status. Stored observations cont… ### Artifacts - [Get artifact metadata](https://developers.telnyx.com/api-reference/artifacts/get-artifact-metadata.md): Returns artifact metadata and a signed download URL. The download URL requires Bearer auth. - [Download artifact](https://developers.telnyx.com/api-reference/artifacts/download-artifact.md): Downloads the artifact content. The signed URL (with expires and sig query params) is obtained from the artifact metadata endpoint.