# Upload a public URL

Store the original bytes of a publicly accessible HTTPS file for review or extraction.

Documentation index: https://webcite.co/llms.txt
Canonical page: https://webcite.co/api-docs/upload-url
API origin: https://api.webcite.co
Authentication: x-api-key header. Keep keys on your server.

## URL and file limits

Send a public HTTPS URL, not a local file path or a private chat attachment. The fetch forwards no caller credentials or headers and checks every redirect for unsafe addresses. Private, loopback, link-local, metadata and reserved addresses are refused. The streamed body is limited to 100 MB and the fetch deadline is 30 seconds.

Supported bytes: PDF, PNG, JPEG, WebP, DOCX, PPTX, XLSX, XLSM, XLSB, XLS, ODS, CSV, TSV, TXT and MD. An optional display `filename` must have an extension matching the fetched bytes. Hosted MCP `upload_url` uses this workflow; hosted base64 `upload_file` retains its separate 20 MB limit.

## Request

POST /api/v1/upload/url

1 credit, charged only when the file is stored.

### curl

```curl
curl --fail-with-body -X POST 'https://api.webcite.co/api/v1/upload/url' \
  -H "x-api-key: $WEBCITE_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
  "url": "https://example.com/report.pdf"
}'
```

### Node.js

```javascript
const response = await fetch("https://api.webcite.co/api/v1/upload/url", {
  method: "POST",
  headers: {
    "x-api-key": process.env.WEBCITE_API_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
  "url": "https://example.com/report.pdf"
}),
});
if (!response.ok) throw new Error(`HTTP ${response.status}: ${await response.text()}`);
console.log(await response.json());
```

### python

```python
import os
import json
import requests

payload = json.loads("{\n  \"url\": \"https://example.com/report.pdf\"\n}")
response = requests.post(
    "https://api.webcite.co/api/v1/upload/url",
    headers={"x-api-key": os.environ["WEBCITE_API_KEY"]},
    json=payload,
    timeout=(10, 300),
)
response.raise_for_status()
print(response.json())
```

## Response

HTTP 200 returns asset_id and source_version_id. Keep these owned identifiers for later review and extraction. The public OpenAPI does not define the complete response schema.

## Errors

400: unsafe or invalid URL or redirect. 413: more than 100 MB. 415: unsupported bytes or filename mismatch. 422: upstream non-2xx or empty body. 504: fetch timeout. An uncertain outcome is not proof that no upload occurred; retain any operation receipt before retrying.

## OpenAPI operation

```json
{
  "path": "/api/v1/upload/url",
  "method": "POST",
  "operation": {
    "description": "Fetches the file server-side and stores it exactly like a multipart upload, returning asset_id and source_version_id for review and extraction.\n\nThe URL must be public HTTPS. Every redirect hop is re-checked; private, loopback, link-local, metadata, multicast and reserved addresses (IPv4 and IPv6) are refused, no caller credentials or headers are forwarded, the body is capped at 100 MB while streaming and the fetch times out after 30 s. The bytes must be one of: PDF, PNG, JPEG, WebP, DOCX, PPTX, XLSX, XLSM, XLSB, XLS, ODS, CSV, TSV, TXT, MD.\n\n**Cost: 1 credit**, charged only when the file is stored.",
    "operationId": "ApiV1Controller_uploadFromUrl",
    "parameters": [],
    "requestBody": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/UploadUrlDto"
          }
        }
      },
      "required": true
    },
    "responses": {
      "200": {
        "description": "File fetched and stored"
      },
      "400": {
        "description": "URL not allowed (non-https, private address, credentials, bad redirect)"
      },
      "413": {
        "description": "File larger than 100 MB"
      },
      "415": {
        "description": "Bytes are not a supported format"
      },
      "422": {
        "description": "URL returned a non-2xx status or an empty body"
      },
      "504": {
        "description": "Fetch timed out"
      }
    },
    "security": [
      {
        "x-api-key": []
      },
      {
        "bearer": []
      }
    ],
    "summary": "Upload a file from a public HTTPS URL",
    "tags": [
      "Public API"
    ]
  },
  "schemas": {
    "UploadUrlDto": {
      "properties": {
        "filename": {
          "description": "Display filename. Its extension must match the fetched bytes.",
          "type": "string"
        },
        "url": {
          "description": "Public HTTPS URL of the file. Fetched server-side with no caller credentials or headers; private, loopback, link-local and metadata addresses are refused on every redirect.",
          "example": "https://example.com/report.pdf",
          "type": "string"
        }
      },
      "required": [
        "url"
      ],
      "type": "object"
    }
  }
}
```
