curl -X POST 'https://api.anyformat.ai/v3/workflows/0686bb97-8c30-70f0-8000-97669e000eb8/upload/from-url/' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"urls": [
"https://example.com/invoices/april.pdf",
"https://example.com/invoices/april-annex.pdf"
],
"metadata": {"customer_reference": "CR-2026-99001-ZTX"}
}'
import requests
workflow_id = "0686bb97-8c30-70f0-8000-97669e000eb8"
url = f"https://api.anyformat.ai/v3/workflows/{workflow_id}/upload/from-url/"
headers = {"Authorization": "Bearer YOUR_API_KEY"}
body = {
"urls": [
"https://example.com/invoices/april.pdf",
"https://example.com/invoices/april-annex.pdf",
]
}
packet = requests.post(url, headers=headers, json=body).json()
print(packet["document_packet_id"])
{
"document_packet_id": "069dcc2c-e14c-7606-8000-2ee4fb17b4e1",
"workflow_id": "0686bb97-8c30-70f0-8000-97669e000eb8",
"files": [
{ "id": "069dcc2c-e14c-7606-8000-2ee4fb17b4e2", "name": "april.pdf", "original_name": null },
{ "id": "069dcc2c-e14c-7606-8000-2ee4fb17b4e3", "name": "april-annex.pdf", "original_name": null }
]
}
{
"error": "Remote fetch failed",
"detail": "Remote server returned 404",
"error_code": "VALIDATION_ERROR",
"retryable": false,
"request_id": "a1b2c3d4e5f67890abcdef1234567890"
}
Upload from URL
Create a document packet by importing 1–100 HTTPS URLs server-side, all-or-nothing
curl -X POST 'https://api.anyformat.ai/v3/workflows/0686bb97-8c30-70f0-8000-97669e000eb8/upload/from-url/' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"urls": [
"https://example.com/invoices/april.pdf",
"https://example.com/invoices/april-annex.pdf"
],
"metadata": {"customer_reference": "CR-2026-99001-ZTX"}
}'
import requests
workflow_id = "0686bb97-8c30-70f0-8000-97669e000eb8"
url = f"https://api.anyformat.ai/v3/workflows/{workflow_id}/upload/from-url/"
headers = {"Authorization": "Bearer YOUR_API_KEY"}
body = {
"urls": [
"https://example.com/invoices/april.pdf",
"https://example.com/invoices/april-annex.pdf",
]
}
packet = requests.post(url, headers=headers, json=body).json()
print(packet["document_packet_id"])
{
"document_packet_id": "069dcc2c-e14c-7606-8000-2ee4fb17b4e1",
"workflow_id": "0686bb97-8c30-70f0-8000-97669e000eb8",
"files": [
{ "id": "069dcc2c-e14c-7606-8000-2ee4fb17b4e2", "name": "april.pdf", "original_name": null },
{ "id": "069dcc2c-e14c-7606-8000-2ee4fb17b4e3", "name": "april-annex.pdf", "original_name": null }
]
}
{
"error": "Remote fetch failed",
"detail": "Remote server returned 404",
"error_code": "VALIDATION_ERROR",
"retryable": false,
"request_id": "a1b2c3d4e5f67890abcdef1234567890"
}
Content-Disposition names each file, and the URL’s path names it otherwise. See File names.
Each fetch has a 10-second timeout and a 20 MB per-file cap. A failed, non-2xx, or timed-out fetch returns 422, with the distinct failure reasons in detail. The API refuses a URL that resolves to a non-globally-routable address before it opens any connection. Loopback, private ranges, link-local and cloud-metadata addresses all qualify.
The response is final: a 201 means the packet is fully imported. An import that runs past the gateway’s 6-minute polling ceiling fails with 504 and retryable: true. Retrying with the same request body is safe. Trigger extraction with POST /v3/document-packets/{document_packet_id}/run/.
Filenames are unique within a workflow. The on_conflict body field decides what a collision does:
error, the default. The request fails with409once the fetches settle, listing the conflict and its suggested rename.rename. The server renames the file, soapril.pdfbecomesapril (1).pdf. Each returnednameis then the name the file was stored under, andoriginal_nameholds the name it was fetched under.
metadata body field. It takes a JSON object stapled to the packet; free text goes under its __anyformat_free_text__ key. GET /v3/document-packets/{document_packet_id}/ echoes it back. A top-level key whose name matches an extract-schema field reaches the LLM and becomes the extracted value. See Attaching metadata for the full contract.
File names
The response names a from-url file, not the request. The name matters twice. It carries the extension the import requires, and a URL whose path is an opaque key carries none. It is also the name you and your users see wherever the file is listed. The precedence is:- The
Content-Dispositionfilename on the response, per RFC 6266.filename*=UTF-8''…wins overfilename=, and any path is cut to its last segment. - Else the URL path’s last segment:
https://example.com/invoices/april.pdfimports asapril.pdf. - Else the import fails with
422.
urls in length and order. On S3, ResponseContentDisposition signs it in:
import boto3
s3 = boto3.client("s3")
url = s3.generate_presigned_url(
"get_object",
Params={
"Bucket": "my-bucket",
"Key": "uploads/7c1f3e9a",
"ResponseContentDisposition": 'attachment; filename="april-invoice.pdf"',
},
ExpiresIn=900,
)
response-content-disposition on a V4 signed URL, and Azure through rscd on a SAS.
Whichever name applies must end in a supported extension, such as .pdf, .docx or .png. A bare key such as uploads/7c1f3e9a names the file 7c1f3e9a, which has no extension, so the import fails with 422. The on_conflict policy applies to this name. On a rename, original_name in the response holds it.
curl -X POST 'https://api.anyformat.ai/v3/workflows/0686bb97-8c30-70f0-8000-97669e000eb8/upload/from-url/' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"urls": [
"https://example.com/invoices/april.pdf",
"https://example.com/invoices/april-annex.pdf"
],
"metadata": {"customer_reference": "CR-2026-99001-ZTX"}
}'
import requests
workflow_id = "0686bb97-8c30-70f0-8000-97669e000eb8"
url = f"https://api.anyformat.ai/v3/workflows/{workflow_id}/upload/from-url/"
headers = {"Authorization": "Bearer YOUR_API_KEY"}
body = {
"urls": [
"https://example.com/invoices/april.pdf",
"https://example.com/invoices/april-annex.pdf",
]
}
packet = requests.post(url, headers=headers, json=body).json()
print(packet["document_packet_id"])
{
"document_packet_id": "069dcc2c-e14c-7606-8000-2ee4fb17b4e1",
"workflow_id": "0686bb97-8c30-70f0-8000-97669e000eb8",
"files": [
{ "id": "069dcc2c-e14c-7606-8000-2ee4fb17b4e2", "name": "april.pdf", "original_name": null },
{ "id": "069dcc2c-e14c-7606-8000-2ee4fb17b4e3", "name": "april-annex.pdf", "original_name": null }
]
}
{
"error": "Remote fetch failed",
"detail": "Remote server returned 404",
"error_code": "VALIDATION_ERROR",
"retryable": false,
"request_id": "a1b2c3d4e5f67890abcdef1234567890"
}
Authorizations
API key issued from app.anyformat.ai/api-key. Send as Authorization: Bearer <key>.
Path Parameters
Body
Body for POST /v3/workflows/{workflow_id}/upload/from-url/.
Every URL imports into a single packet atomically — any fetch or
validation failure means nothing is persisted. Files arrive as fetchable
HTTPS urls, as staged_files ids from POST /v3/blobs/slots/, or
a mix; 1 to 100 files in total.
HTTPS URLs the backend fetches server-side. Each file is named by the response's Content-Disposition filename when present, else by the last segment of the URL's path.
100["https://example.com/invoices/april.pdf"]
Files staged via POST /v3/blobs/slots/ and uploaded already, referenced by object_id so the long presigned read_url never needs to be passed around. They land after the urls entries.
100Show child attributes
Show child attributes
Free-form JSON to attach to the packet. No schema is enforced; the extract operator may source datapoints from a top-level key whose name matches a schema field, and from free text in natural language under __anyformat_free_text__.
How to handle an uploaded filename that already exists in the workflow (filenames are unique within a workflow). error (the default) rejects the whole request with 409 and lists the conflicting names, so a rename is never silent — the caller must opt in. rename accepts the collision and lets the server auto-rename the file by inserting a (n) counter before the extension (invoice.pdf → invoice (1).pdf).
error, rename Response
Successful Response
Response for the packet-creating uploads (multipart and from-url).
Unique identifier of the newly created document packet (hyphenated UUID).
"069dcc2c-e14c-7606-8000-2ee4fb17b4e1"
The workflow the packet was created under (hyphenated UUID).
"0686bb97-8c30-70f0-8000-97669e000eb8"
Files in the packet, in the order they were provided.
Show child attributes
Show child attributes

