> This documentation belongs to Invofox, an AI-powered document processing
> platform. The API extracts structured data (fields) from unstructured
> documents (invoices, contracts, forms, bank statements, and more).
> Key concepts: Account, Environment, Document Type, Field, File, Import,
> and Document. When answering, prefer the exact terminology defined in the
> Glossary and cite the relevant API Reference endpoint when applicable.

# Upload files by URL

POST https://api.invofox.com/v1/ingest/by-url
Content-Type: application/json

Upload files by providing URLs from which files will be downloaded and processed asynchronously.
Allowed formats are
- images: .jpeg, .jpg, .png, .tiff
- PDFs: .pdf

The API accepts an array of file URLs with optional metadata for processing.

Reference: https://developers.invofox.com/api-reference/ingest-reference/files/upload-by-url-controller-upload-by-url

## Authentication

- `x-api-key` header (required) — API key authentication for programmatic access. Used by server-to-server integrations and API clients.
- `x-access-token` header (required) — Access token authentication for web users. Used by browser-based applications and authenticated user sessions.

## Request

### Body (application/json)

This endpoint expects an UploadByUrlRequestDto.

- `files` (list of FileUrlInfoDto, required) — Array of file URLs to download and process. **Dual-Level Metadata Structure:** Each file can have individual metadata (type, data, clientData) via the 'info' field within each FileUrlInfoDto. However, company can only be set at the batch level via the root 'info' field. **Per-File Metadata:** Each file can specify its own document type, processing data, and client data. **Batch Metadata:** Company applies to ALL files in this request.
- `info` (FileInfo, optional) — Batch-level metadata that applies to ALL files in this request. **Important:** This is where you set company context for the entire batch. Individual files cannot override company - this is a batch-level setting only. **Use this field for:** - company: Company ID (applies to all files) - Global settings that affect all files **Individual file metadata** like document type, processing data, and client data should be set in each file's 'info' field.

## Response

### 201

Files queued for download and processing

- `accountId` (string, required) — Account ID
- `environmentId` (string, required) — Environment ID
- `importId` (string, required) — Import ID for tracking the upload process
- `files` (list of FileUploadInfo, required) — Array of uploaded files information

## Errors

### 400 Bad Request Error

Bad Request - Invalid URLs or validation errors

- `message` (list of string, optional)
- `error` (string, optional)
- `statusCode` (double, optional)

### 404 Not Found Error

Not Found - One or more URLs are unreachable

- `message` (string, optional)
- `error` (string, optional)
- `statusCode` (double, optional)

## Types

### FileUrlInfoDto

- `url` (string, required) — URL from which the file will be downloaded and processed
- `filename` (string, optional) — Optional filename override
- `info` (FileSpecificMetadataDto, optional) — Specific metadata for this file (excludes environment/company/importConfig which must be set at root level)

### FileInfo

- `useSplitter` (boolean, optional) — Flag to determine if splitter should be used to process this file. This will be ignored if splitter is not enabled for the environment
- `useClassifier` (boolean, optional) — Flag to determine if classifier should be used to detect this file's document type. This will be ignored if classifier is not enabled for the environment
- `type` (string, optional) — Document type ID or alias (e.g., "invoice", "receipt", or a custom type ID from your environment). This field is optional if the classifier is enabled for the environment or if a defaultType is configured in your ImportConfig; otherwise, it is required.
- `data` (map from string to any, optional) — Data known for the file. This data will be associated to the file itself.
- `clientData` (map from string to any, optional) — Custom metadata object for your application's use (not processed by Invofox). Useful for storing external IDs, tracking information, or application-specific context.
- `company` (string, optional) — Company ID (MongoDB ObjectId)

### FileUploadInfo

- `filename` (string, required) — Filename of the file
- `id` (string, required) — File ID associated with the uploaded file
- `documentId` (string, optional, deprecated) — Pre-assigned Document ID, only available if file is imported as a single document. DEPRECATED: This field will be removed. Instead, use webhooks to receive processing notifications, then retrieve documentIds from the file details endpoint.

### FileSpecificMetadataDto

- `useSplitter` (boolean, optional) — Flag to determine if splitter should be used to process this file. This will be ignored if splitter is not enabled for the environment
- `useClassifier` (boolean, optional) — Flag to determine if classifier should be used to detect this file's document type. This will be ignored if classifier is not enabled for the environment
- `type` (string, optional) — Document type ID or alias (e.g., "invoice", "receipt", or a custom type ID from your environment). This field is optional if the classifier is enabled for the environment or if a defaultType is configured in your ImportConfig; otherwise, it is required.
- `data` (map from string to any, optional) — Data known for the file. This data will be associated to the file itself.
- `clientData` (map from string to any, optional) — Custom metadata object for your application's use (not processed by Invofox). Useful for storing external IDs, tracking information, or application-specific context.

## Examples

**Request**

```json
{
  "files": [
    {
      "url": "https://example.com/invoice.pdf",
      "filename": "invoice-001.pdf",
      "info": {
        "type": "invoice",
        "data": {
          "companyActsLike": "issuer"
        },
        "clientData": {
          "externalId": "INV-001"
        }
      }
    },
    {
      "url": "https://example.com/receipt.pdf",
      "filename": "receipt-001.pdf",
      "info": {
        "type": "receipt",
        "data": {
          "currency": "EUR"
        },
        "clientData": {
          "externalId": "REC-001"
        }
      }
    }
  ]
}
```

**Response**

```json
{
  "accountId": "000000000000000000000007",
  "environmentId": "000000000000000000000008",
  "importId": "000000000000000000000009",
  "files": [
    {
      "filename": "file.pdf",
      "id": "00000000000000000000000f",
      "documentId": "00000000000000000000000d"
    }
  ]
}
```

**SDK Code**

```python
import requests

url = "https://api.invofox.com/v1/ingest/by-url"

payload = { "files": [
        {
            "url": "https://example.com/invoice.pdf",
            "filename": "invoice-001.pdf",
            "info": {
                "type": "invoice",
                "data": { "companyActsLike": "issuer" },
                "clientData": { "externalId": "INV-001" }
            }
        },
        {
            "url": "https://example.com/receipt.pdf",
            "filename": "receipt-001.pdf",
            "info": {
                "type": "receipt",
                "data": { "currency": "EUR" },
                "clientData": { "externalId": "REC-001" }
            }
        }
    ] }
headers = {
    "x-api-key": "<apiKey>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript
const url = 'https://api.invofox.com/v1/ingest/by-url';
const options = {
  method: 'POST',
  headers: {'x-api-key': '<apiKey>', 'Content-Type': 'application/json'},
  body: '{"files":[{"url":"https://example.com/invoice.pdf","filename":"invoice-001.pdf","info":{"type":"invoice","data":{"companyActsLike":"issuer"},"clientData":{"externalId":"INV-001"}}},{"url":"https://example.com/receipt.pdf","filename":"receipt-001.pdf","info":{"type":"receipt","data":{"currency":"EUR"},"clientData":{"externalId":"REC-001"}}}]}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.invofox.com/v1/ingest/by-url"

	payload := strings.NewReader("{\n  \"files\": [\n    {\n      \"url\": \"https://example.com/invoice.pdf\",\n      \"filename\": \"invoice-001.pdf\",\n      \"info\": {\n        \"type\": \"invoice\",\n        \"data\": {\n          \"companyActsLike\": \"issuer\"\n        },\n        \"clientData\": {\n          \"externalId\": \"INV-001\"\n        }\n      }\n    },\n    {\n      \"url\": \"https://example.com/receipt.pdf\",\n      \"filename\": \"receipt-001.pdf\",\n      \"info\": {\n        \"type\": \"receipt\",\n        \"data\": {\n          \"currency\": \"EUR\"\n        },\n        \"clientData\": {\n          \"externalId\": \"REC-001\"\n        }\n      }\n    }\n  ]\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("x-api-key", "<apiKey>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://api.invofox.com/v1/ingest/by-url")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<apiKey>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"files\": [\n    {\n      \"url\": \"https://example.com/invoice.pdf\",\n      \"filename\": \"invoice-001.pdf\",\n      \"info\": {\n        \"type\": \"invoice\",\n        \"data\": {\n          \"companyActsLike\": \"issuer\"\n        },\n        \"clientData\": {\n          \"externalId\": \"INV-001\"\n        }\n      }\n    },\n    {\n      \"url\": \"https://example.com/receipt.pdf\",\n      \"filename\": \"receipt-001.pdf\",\n      \"info\": {\n        \"type\": \"receipt\",\n        \"data\": {\n          \"currency\": \"EUR\"\n        },\n        \"clientData\": {\n          \"externalId\": \"REC-001\"\n        }\n      }\n    }\n  ]\n}"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.invofox.com/v1/ingest/by-url")
  .header("x-api-key", "<apiKey>")
  .header("Content-Type", "application/json")
  .body("{\n  \"files\": [\n    {\n      \"url\": \"https://example.com/invoice.pdf\",\n      \"filename\": \"invoice-001.pdf\",\n      \"info\": {\n        \"type\": \"invoice\",\n        \"data\": {\n          \"companyActsLike\": \"issuer\"\n        },\n        \"clientData\": {\n          \"externalId\": \"INV-001\"\n        }\n      }\n    },\n    {\n      \"url\": \"https://example.com/receipt.pdf\",\n      \"filename\": \"receipt-001.pdf\",\n      \"info\": {\n        \"type\": \"receipt\",\n        \"data\": {\n          \"currency\": \"EUR\"\n        },\n        \"clientData\": {\n          \"externalId\": \"REC-001\"\n        }\n      }\n    }\n  ]\n}")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.invofox.com/v1/ingest/by-url', [
  'body' => '{
  "files": [
    {
      "url": "https://example.com/invoice.pdf",
      "filename": "invoice-001.pdf",
      "info": {
        "type": "invoice",
        "data": {
          "companyActsLike": "issuer"
        },
        "clientData": {
          "externalId": "INV-001"
        }
      }
    },
    {
      "url": "https://example.com/receipt.pdf",
      "filename": "receipt-001.pdf",
      "info": {
        "type": "receipt",
        "data": {
          "currency": "EUR"
        },
        "clientData": {
          "externalId": "REC-001"
        }
      }
    }
  ]
}',
  'headers' => [
    'Content-Type' => 'application/json',
    'x-api-key' => '<apiKey>',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://api.invofox.com/v1/ingest/by-url");
var request = new RestRequest(Method.POST);
request.AddHeader("x-api-key", "<apiKey>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"files\": [\n    {\n      \"url\": \"https://example.com/invoice.pdf\",\n      \"filename\": \"invoice-001.pdf\",\n      \"info\": {\n        \"type\": \"invoice\",\n        \"data\": {\n          \"companyActsLike\": \"issuer\"\n        },\n        \"clientData\": {\n          \"externalId\": \"INV-001\"\n        }\n      }\n    },\n    {\n      \"url\": \"https://example.com/receipt.pdf\",\n      \"filename\": \"receipt-001.pdf\",\n      \"info\": {\n        \"type\": \"receipt\",\n        \"data\": {\n          \"currency\": \"EUR\"\n        },\n        \"clientData\": {\n          \"externalId\": \"REC-001\"\n        }\n      }\n    }\n  ]\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "x-api-key": "<apiKey>",
  "Content-Type": "application/json"
]
let parameters = ["files": [
    [
      "url": "https://example.com/invoice.pdf",
      "filename": "invoice-001.pdf",
      "info": [
        "type": "invoice",
        "data": ["companyActsLike": "issuer"],
        "clientData": ["externalId": "INV-001"]
      ]
    ],
    [
      "url": "https://example.com/receipt.pdf",
      "filename": "receipt-001.pdf",
      "info": [
        "type": "receipt",
        "data": ["currency": "EUR"],
        "clientData": ["externalId": "REC-001"]
      ]
    ]
  ]] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.invofox.com/v1/ingest/by-url")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```