Skip to main content
POST
/
v2
/
workflows
/
{workflow_id}
/
files
/
from-url
/
curl -X POST 'https://api.anyformat.ai/v2/workflows/550e8400-e29b-41d4-a716-446655440000/files/from-url/' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "url": "https://my-bucket.s3.amazonaws.com/invoices/april.pdf?X-Amz-Signature=...",
    "filename": "april.pdf",
    "content_type": "application/pdf"
  }'
import requests

workflow_id = "550e8400-e29b-41d4-a716-446655440000"
url = f"https://api.anyformat.ai/v2/workflows/{workflow_id}/files/from-url/"
headers = {
    "Authorization": "Bearer YOUR_API_KEY",
    "Content-Type": "application/json",
}

response = requests.post(url, headers=headers, json={
    "url": "https://my-bucket.s3.amazonaws.com/invoices/april.pdf?X-Amz-Signature=...",
    "filename": "april.pdf",
    "content_type": "application/pdf",
})
print(response.json())
const workflowId = '550e8400-e29b-41d4-a716-446655440000';

const response = await fetch(`https://api.anyformat.ai/v2/workflows/${workflowId}/files/from-url/`, {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    url: 'https://my-bucket.s3.amazonaws.com/invoices/april.pdf?X-Amz-Signature=...',
    filename: 'april.pdf',
    content_type: 'application/pdf',
  }),
});

const data = await response.json();
console.log(data);
interface FileItem {
  filename: string;
  status: string;
}

interface CreateCollectionResponse {
  id: string;
  name: string | null;
  files: FileItem[];
  workflow_id: string;
}

const workflowId = '550e8400-e29b-41d4-a716-446655440000';

const response = await fetch(`https://api.anyformat.ai/v2/workflows/${workflowId}/files/from-url/`, {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    url: 'https://my-bucket.s3.amazonaws.com/invoices/april.pdf?X-Amz-Signature=...',
    filename: 'april.pdf',
    content_type: 'application/pdf',
  }),
});

if (!response.ok) {
  throw new Error(`API error: ${response.status}`);
}

const data: CreateCollectionResponse = await response.json();
console.log(data.id);
{
  "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
  "name": null,
  "files": [
    {
      "filename": "april.pdf",
      "status": "pending"
    }
  ],
  "workflow_id": "550e8400-e29b-41d4-a716-446655440000"
}
Use this endpoint when the source document already lives at an HTTPS URL — for example, a presigned S3 link or a hosted asset. anyformat fetches the bytes server-side; you do not stream the file yourself. To upload bytes directly, use Upload File instead.

When to use this

  • The document is in a bucket you can presign (S3, GCS, R2, etc.) and you’d rather hand anyformat the link than route the bytes through your own backend.
  • The document lives at a public HTTPS URL.
  • You want one round-trip instead of a multipart upload.

Constraints

Schemehttps:// only — http:// is rejected at the gateway with 400.
Fetch timeout10 seconds per network phase (connect, read, write, pool).
Size cap20 MB (mirrors the multipart upload cap).
RedirectsNot followed. A 3xx from the supplied URL is treated as a guard rejection and surfaces as a 400 — your URL must serve the bytes directly (no CDN redirects, no URL shorteners).
SSRF guardURLs whose hostname resolves to a non-globally-routable IP (per IANA is_global: loopback, RFC1918, link-local incl. cloud-metadata 169.254.169.254, IPv6 ULA, multicast, reserved, IPv4-mapped IPv6) are rejected before any fetch attempt.

What happens after the 201

The URL endpoint returns immediately with "status": "pending" and fetches the bytes asynchronously, server-side. The status field on the file listing reflects extraction state, not upload state — a subsequent GET /v2/workflows/{workflow_id}/files/ will continue to report pending until a workflow run is triggered against the returned collection_id, even after the asynchronous fetch has finished and the bytes are in storage. Polling the file listing for an “upload-complete” transition will not work. The intended next step is to start a run on the returned collection_id straight away (see Run Workflow). The file’s status then moves through queued, in_progress, and processed as the extraction progresses, and the standard polling pattern on GET .../files/ reports those transitions.

Request body

FieldTypeRequiredDescription
urlstringYesHTTPS URL anyformat will fetch the file bytes from.
filenamestringYesFilename to record on the uploaded file.
content_typestringNoMIME type of the file. Leave empty (or omit) to use the URL’s response Content-Type header.
curl -X POST 'https://api.anyformat.ai/v2/workflows/550e8400-e29b-41d4-a716-446655440000/files/from-url/' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "url": "https://my-bucket.s3.amazonaws.com/invoices/april.pdf?X-Amz-Signature=...",
    "filename": "april.pdf",
    "content_type": "application/pdf"
  }'
import requests

workflow_id = "550e8400-e29b-41d4-a716-446655440000"
url = f"https://api.anyformat.ai/v2/workflows/{workflow_id}/files/from-url/"
headers = {
    "Authorization": "Bearer YOUR_API_KEY",
    "Content-Type": "application/json",
}

response = requests.post(url, headers=headers, json={
    "url": "https://my-bucket.s3.amazonaws.com/invoices/april.pdf?X-Amz-Signature=...",
    "filename": "april.pdf",
    "content_type": "application/pdf",
})
print(response.json())
const workflowId = '550e8400-e29b-41d4-a716-446655440000';

const response = await fetch(`https://api.anyformat.ai/v2/workflows/${workflowId}/files/from-url/`, {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    url: 'https://my-bucket.s3.amazonaws.com/invoices/april.pdf?X-Amz-Signature=...',
    filename: 'april.pdf',
    content_type: 'application/pdf',
  }),
});

const data = await response.json();
console.log(data);
interface FileItem {
  filename: string;
  status: string;
}

interface CreateCollectionResponse {
  id: string;
  name: string | null;
  files: FileItem[];
  workflow_id: string;
}

const workflowId = '550e8400-e29b-41d4-a716-446655440000';

const response = await fetch(`https://api.anyformat.ai/v2/workflows/${workflowId}/files/from-url/`, {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    url: 'https://my-bucket.s3.amazonaws.com/invoices/april.pdf?X-Amz-Signature=...',
    filename: 'april.pdf',
    content_type: 'application/pdf',
  }),
});

if (!response.ok) {
  throw new Error(`API error: ${response.status}`);
}

const data: CreateCollectionResponse = await response.json();
console.log(data.id);
{
  "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
  "name": null,
  "files": [
    {
      "filename": "april.pdf",
      "status": "pending"
    }
  ],
  "workflow_id": "550e8400-e29b-41d4-a716-446655440000"
}

Error responses

StatusWhen
400URL uses a disallowed scheme (http://, file://, …), resolves to a non-public IP, returns a 3xx redirect, or returns a body larger than the 20 MB cap — anything the SSRF guard or fetcher treats as structurally unacceptable input.
422The upstream URL prevented processing — connection timed out, hostname did not resolve, or the target returned a 4xx/5xx response.

Authorizations

Authorization
string
header
required

API key issued from app.anyformat.ai/api-key. Send as Authorization: Bearer <key>.

Path Parameters

workflow_id
string
required

Body

application/json

Payload for creating a file collection from a single remote URL.

Single URL per request keeps the wire shape predictable; SDKs that need batches wrap the call. content_type may be empty — the backend falls back to the response's Content-Type header in that case.

Only HTTPS URLs are accepted. The backend additionally runs a DNS+IP SSRF guard before the fetch — URLs whose hostname resolves to a non-globally-routable IP (per IANA is_global: loopback, RFC1918, link-local incl. cloud-metadata 169.254.169.254, IPv6 ULA, multicast, reserved, IPv4-mapped IPv6) are refused. Enforcing the scheme at the gateway means malformed requests fail fast without traversing the backend.

url
string
required

HTTPS URL the backend will fetch the file bytes from.

Example:

"https://example.com/invoices/april.pdf"

filename
string
required

Filename to record on the uploaded file.

Example:

"april.pdf"

content_type
string
default:""

MIME type of the file. Leave empty to use the URL's response Content-Type header.

Example:

"application/pdf"

Response

Successful Response

Response from creating a file collection. Contains the collection ID and the status of each uploaded file.

id
string
required

Unique identifier of the newly created file collection.

Example:

"069dcc2c-e14c-7606-8000-2ee4fb17b4e1"

files
FileItem · object[]
required

List of files included in the collection, with their upload status.

workflow_id
string
required

The UUID of the workflow this collection belongs to.

Example:

"0686bb97-8c30-70f0-8000-97669e000eb8"

name
string | null

Human-readable name for the collection.

rejected
RejectedFileItem · object[]

Files the backend refused to accept — unsupported extension at slot-time or disguised bytes at register-time. Empty when every file uploaded cleanly.