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

# Download File from URL

> Tool that resolves a public document **link** — typically found in an email body instead of an attachment — into a registered `files` row and returns a `storage_url` consumable…

This document covers `download_file_from_url` (display name **"Download File from URL"**), the tool that resolves a public document **link** — typically found in an email body instead of an attachment — into a registered `files` row and returns a `storage_url` consumable by downstream tools (`structured_data_extraction`, `document_parser`, `csv`, …). It complements the connector-specific importers (`import_from_onedrive`, `search_and_download_google_drive_file`), which need an authenticated integration; this tool handles arbitrary public/tokenized links.

## When to use — and when not

Use it when a task's document is referenced by a **URL** rather than uploaded — e.g. an order email whose body links to a vendor portal ("download the PO from this link and extract it").

Do **not** use it for links that require an interactive **login** (username/password). Capability links that carry their own token (Encompass `QuickLink`, S3 presigned URLs, shared-file links) are the target.

Off by default — enable it in the agent's Tools panel.

## How it resolves a link (three-tier ladder)

The tool escalates only as far as needed; the agent sees one call and a `capture_method` in the result telling it which tier produced the file.

1. **`direct_file`** — the URL already returns a document (PDF/CSV/Office/image). Cheapest.
2. **`extracted_link`** — the URL returns an HTML page; the tool parses it for a real download link (`<a>` with a file extension / `download` attribute / download-ish text, `<meta http-equiv=refresh>`, `<iframe>`/`<embed>` source) and follows the best candidate one hop (capped at 3 candidates).
3. **`embedded_pdf` / `rendered_pdf`** — the page is JS-driven (e.g. an Encompass "Purchase Print" view). The worker hands the URL (+ the fetch's cookies) to the sandboxed **browser-use service**'s LLM-free `POST /render` endpoint (see below), which headless-renders it and returns the document URLs the page's viewer loads plus a page-print fallback. The worker then fetches the embedded document **server-side** (`embedded_pdf`) — vendor viewers frequently serve the PDF from a **different origin** (e.g. `cdn.e8.co`), which an in-page fetch can't reach (CORS) but a server-side fetch can. If the page has no embedded document, the render's PrintToPDF is used (`rendered_pdf`).

### Why render runs in the browser-use service, not the worker

Tier-3 renders **attacker-controlled** third-party HTML. Doing that in the worker process (which holds the DB pool and S3 credentials) with an unsandboxed browser is the exact risk we avoid. Instead it goes to the existing `browser-use` service — a separate, **sandboxed** pod (setuid `chromium-sandbox`, non-root, `tini` reaping). Crucially, this uses a dedicated `POST /render` endpoint that runs **no Agent/LLM** (no Gemini, no cost — just headless-Chrome CPU), *not* the expensive agent path that backs `browser_automation`. The endpoint is configured via `BROWSER_USE_BASE_URL` / `BROWSER_USE_API_KEY` (shared with `browser_automation`); when unset, tiers 1–2 still work and tier-3 reports "render service not configured".

## Inputs

* `url` (required): the HTTP(S) link, exactly as found in the message.
* `filename_hint` (optional): filename to use when the server provides none (e.g. `invoice-madvines.pdf`).

## Content typing

The **sniffed** content type (`http.DetectContentType` + magic bytes) wins over the declared `Content-Type` header, which vendors frequently get wrong (Encompass labels a PDF endpoint `text/html`; some servers serve HTML as `application/octet-stream`). Only a `2xx` response with a non-empty body is treated as a document — a 403/404/500 error page is a failure, never escalated or stored as a bogus file.

## Output

Structured result with `file_id`, `file_name`, `storage_url` (pass this to a data-extraction tool), `mime_type`, `file_size`, `capture_method`, and `final_url_host` (host only). Storage goes through `FileStorageService.UploadFile`, so the filename is sanitized into a tenant-scoped key (`agents/{agent}/tasks/{task}/{file-id}-{name}`), the size cap is enforced, and an `ActionStorageS3Put` audit event is emitted. A `files` row is registered (task/agent/workspace from execution context) so the download appears in the file lookup API like a manual upload.

## Security

* **SSRF**: every fetch the worker makes is validated so it cannot reach internal or private networks (loopback, RFC1918, link-local, cloud-metadata hosts).
* **Audit**: outbound fetches are audited. Full URLs are never logged or surfaced (they can carry bearer-equivalent tokens); logs and results are host-only.
* **Cookies**: a fresh cookie jar per call (the redirect chain to a capability link often sets a session cookie mid-redirect); cookies never cross tasks or tenants.

## Resource bounds

* Download size capped well below the platform max (order documents are kilobytes).
* Concurrent headless renders are bounded in the render service, so a burst of inbound-email tasks can't overload the worker — the worker only makes an HTTP call.
* One overall deadline bounds the whole ladder for a single call.

## Errors

* Empty/invalid URL, or a non-`http(s)` scheme → validation error before any network call.
* No task context, or file storage unavailable → error result.
* Non-`2xx`, empty body, oversized download, or SSRF-blocked destination → error result (host-only, no full URL).
* Tier-3 render fails/times out → error result explaining what was tried.
