/api/v1_2/documentsTo create a new Document send POST request with body containing a JSON hash of the required fields. The file content must be encoded as URL-safe base64 string (Base64URL in validator https://base64.guru/tools/validator). Online Base64 encoder https://www.base64encode.org/
Only one file per document is allowed, but you can create multiple documents in one request or post files in compressed archive.
In case of multipage file with enabled split max 200 pages are allowed.
For each new created document is returned document id. All created documents are automatically queued for processing.
Big files (big request bodies) can lead to timeouts or unreasonable response times. Rule of thumb is to keep the size of uploaded data under 20MB.
Supported file formats
| Format | Description |
|---|---|
| Containing text or scanned documents | |
| * | single page PDF document, multipage PDF document, multiple documents in PDF |
| TIFF, JPEG, PNG | image, color/grayscale/b&w |
| ZIP | containing file formats see above |
| RAR | containing file formats see above |
| 7ZIP | containing file formats see above |
File content types
Set each file’s content_type to the matching MIME type. The enclosing JSON request uses Content-Type: application/json.
| File format | Content type |
|---|---|
| application/pdf | |
| JPEG | image/jpeg |
| PNG | image/png |
| TIFF | image/tiff |
| ZIP | application/zip |
| RAR | application/x-rar |
| 7ZIP | application/x-7z-compressed |
Request attributes
Use the request example below to see the nesting of documents and files.
Request attributes include both required and optional fields:
| Attribute | Required | Type, Example | Description |
|---|---|---|---|
filename |
true | String invoice.pdf |
File name |
content_type |
true | String, application/pdf |
MIME type of document |
agenda_id |
true | String, 143 |
Agenda ID where document belongs to |
type |
true | String, PurchaseInvoice |
Type of document. Allowed values: PurchaseInvoice, SalesInvoice |
content |
true | String, JVBERi0xLjQgZGVt..(omitted)) |
URL-safe base64 encoded string of file content. File content needs to use URL-safe variant of base64 encoding/decoding (common pitfall). |
file_split |
false | Boolean,true |
true,false. In case of false automatic splitting is disabled. One file = one document. Number of pages for split is limited to 200. |
Optional duplicate check
If you add additional parameter check_file_duplicates=1 to create document url you will get response message “File duplicate” with additional meta data in case the check is positive.
You can use the provided metadata either to let you user know that the file is duplicate or to obtain extracted data from original. Just be aware that there can be multiple processed docs from single upload (archives, multi page scans).
Query parameters
| Name | Example | Description |
|---|---|---|
check_file_duplicates |
1 | You will get response message “File duplicate” with additional meta data in case the check is positive. |
Headers
| Name | Example | Description |
|---|---|---|
Accept |
application/json | - |
Content-Type |
application/json | - |
Request body
{
"documents": [
{
"files": [
{
"filename": "demo-supplier-invoice.pdf",
"content_type": "application/pdf",
"content": "JVBERi0xLjQgZGF0YW1vbGluby1kZW1v"
}
],
"agenda_id": 12345,
"file_split": false,
"type": "PurchaseInvoice"
}
]
}Code examples
cURL
curl --request POST 'https://app.datamolino.com/api/v1_2/documents?check_file_duplicates=1' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer demo_access_token' \
--data '{
"documents": [
{
"files": [
{
"filename": "demo-supplier-invoice.pdf",
"content_type": "application/pdf",
"content": "JVBERi0xLjQgZGF0YW1vbGluby1kZW1v"
}
],
"agenda_id": 12345,
"file_split": false,
"type": "PurchaseInvoice"
}
]
}'HTTP
POST /api/v1_2/documents?check_file_duplicates=1 HTTP/1.1
Host: app.datamolino.com
Accept: application/json
Content-Type: application/json
Authorization: Bearer demo_access_token
{
"documents": [
{
"files": [
{
"filename": "demo-supplier-invoice.pdf",
"content_type": "application/pdf",
"content": "JVBERi0xLjQgZGF0YW1vbGluby1kZW1v"
}
],
"agenda_id": 12345,
"file_split": false,
"type": "PurchaseInvoice"
}
]
}JavaScript Fetch
const response = await fetch("https://app.datamolino.com/api/v1_2/documents?check_file_duplicates=1", {
method: "POST",
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": "Bearer demo_access_token"
},
body: JSON.stringify({
"documents": [
{
"files": [
{
"filename": "demo-supplier-invoice.pdf",
"content_type": "application/pdf",
"content": "JVBERi0xLjQgZGF0YW1vbGluby1kZW1v"
}
],
"agenda_id": 12345,
"file_split": false,
"type": "PurchaseInvoice"
}
]
}),
});
const data = await response.json();Node.js Axios
import axios from "axios";
const response = await axios({
method: "post",
url: "https://app.datamolino.com/api/v1_2/documents?check_file_duplicates=1",
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": "Bearer demo_access_token"
},
data: {
"documents": [
{
"files": [
{
"filename": "demo-supplier-invoice.pdf",
"content_type": "application/pdf",
"content": "JVBERi0xLjQgZGF0YW1vbGluby1kZW1v"
}
],
"agenda_id": 12345,
"file_split": false,
"type": "PurchaseInvoice"
}
]
}
});
console.log(response.data);Python Requests
import requests
url = "https://app.datamolino.com/api/v1_2/documents?check_file_duplicates=1"
headers = {
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": "Bearer demo_access_token"
}
payload = {
"documents": [
{
"files": [
{
"filename": "demo-supplier-invoice.pdf",
"content_type": "application/pdf",
"content": "JVBERi0xLjQgZGF0YW1vbGluby1kZW1v"
}
],
"agenda_id": 12345,
"file_split": False,
"type": "PurchaseInvoice"
}
]
}
response = requests.request("POST", url, headers=headers, json=payload)
response.raise_for_status()
print(response.json())Ruby Net::HTTP
require 'json'
require 'net/http'
uri = URI("https://app.datamolino.com/api/v1_2/documents?check_file_duplicates=1")
request = Net::HTTP::Post.new(uri)
request["Accept"] = "application/json"
request["Content-Type"] = "application/json"
request["Authorization"] = "Bearer demo_access_token"
request.body = <<~JSON
{
"documents": [
{
"files": [
{
"filename": "demo-supplier-invoice.pdf",
"content_type": "application/pdf",
"content": "JVBERi0xLjQgZGF0YW1vbGluby1kZW1v"
}
],
"agenda_id": 12345,
"file_split": false,
"type": "PurchaseInvoice"
}
]
}
JSON
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
http.request(request)
end
puts JSON.parse(response.body)Ruby on Rails
# app/services/datamolino_client.rb
require 'json'
require 'net/http'
class DatamolinoClient
BASE_URL = "https://app.datamolino.com"
def initialize(access_token: Rails.application.credentials.dig(:datamolino, :access_token))
@access_token = access_token
end
def request_create_document
uri = URI("#{BASE_URL}/api/v1_2/documents?check_file_duplicates=1")
request = Net::HTTP::Post.new(uri)
request["Accept"] = "application/json"
request["Content-Type"] = "application/json"
request["Authorization"] = "Bearer #{@access_token}"
request.body = <<~JSON
{
"documents": [
{
"files": [
{
"filename": "demo-supplier-invoice.pdf",
"content_type": "application/pdf",
"content": "JVBERi0xLjQgZGF0YW1vbGluby1kZW1v"
}
],
"agenda_id": 12345,
"file_split": false,
"type": "PurchaseInvoice"
}
]
}
JSON
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
JSON.parse(response.body)
end
endPHP Guzzle
<?php
use GuzzleHttp\Client;
$client = new Client();
$response = $client->request('POST', 'https://app.datamolino.com/api/v1_2/documents?check_file_duplicates=1', [
'headers' => json_decode('{"Accept":"application/json","Content-Type":"application/json","Authorization":"Bearer demo_access_token"}', true),
'json' => json_decode('{"documents":[{"files":[{"filename":"demo-supplier-invoice.pdf","content_type":"application/pdf","content":"JVBERi0xLjQgZGF0YW1vbGluby1kZW1v"}],"agenda_id":12345,"file_split":false,"type":"PurchaseInvoice"}]}', true)
]);
echo $response->getBody();Java OkHttp
OkHttpClient client = new OkHttpClient();
RequestBody body = RequestBody.create("{\n \"documents\": [\n {\n \"files\": [\n {\n \"filename\": \"demo-supplier-invoice.pdf\",\n \"content_type\": \"application/pdf\",\n \"content\": \"JVBERi0xLjQgZGF0YW1vbGluby1kZW1v\"\n }\n ],\n \"agenda_id\": 12345,\n \"file_split\": false,\n \"type\": \"PurchaseInvoice\"\n }\n ]\n}", MediaType.parse("application/json"));
Request request = new Request.Builder()
.url("https://app.datamolino.com/api/v1_2/documents?check_file_duplicates=1")
.addHeader("Accept", "application/json")
.addHeader("Content-Type", "application/json")
.addHeader("Authorization", "Bearer demo_access_token")
.method("POST", body)
.build();
Response response = client.newCall(request).execute();C# HttpClient
using var client = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Post, "https://app.datamolino.com/api/v1_2/documents?check_file_duplicates=1");
request.Headers.Add("Accept", "application/json");
request.Headers.Add("Authorization", "Bearer demo_access_token");
request.Content = new StringContent("{\n \"documents\": [\n {\n \"files\": [\n {\n \"filename\": \"demo-supplier-invoice.pdf\",\n \"content_type\": \"application/pdf\",\n \"content\": \"JVBERi0xLjQgZGF0YW1vbGluby1kZW1v\"\n }\n ],\n \"agenda_id\": 12345,\n \"file_split\": false,\n \"type\": \"PurchaseInvoice\"\n }\n ]\n}", Encoding.UTF8, "application/json");
using var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
Console.WriteLine(await response.Content.ReadAsStringAsync());Go Native
client := &http.Client{}
req, err := http.NewRequest("POST", "https://app.datamolino.com/api/v1_2/documents?check_file_duplicates=1", strings.NewReader("{\n \"documents\": [\n {\n \"files\": [\n {\n \"filename\": \"demo-supplier-invoice.pdf\",\n \"content_type\": \"application/pdf\",\n \"content\": \"JVBERi0xLjQgZGF0YW1vbGluby1kZW1v\"\n }\n ],\n \"agenda_id\": 12345,\n \"file_split\": false,\n \"type\": \"PurchaseInvoice\"\n }\n ]\n}"))
if err != nil { panic(err) }
req.Header.Add("Accept", "application/json")
req.Header.Add("Content-Type", "application/json")
req.Header.Add("Authorization", "Bearer demo_access_token")
res, err := client.Do(req)
if err != nil { panic(err) }
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
if err != nil { panic(err) }
fmt.Println(string(body))Swift URLSession
import Foundation
var request = URLRequest(url: URL(string: "https://app.datamolino.com/api/v1_2/documents?check_file_duplicates=1")!)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Bearer demo_access_token", forHTTPHeaderField: "Authorization")
request.httpBody = "{\n \"documents\": [\n {\n \"files\": [\n {\n \"filename\": \"demo-supplier-invoice.pdf\",\n \"content_type\": \"application/pdf\",\n \"content\": \"JVBERi0xLjQgZGF0YW1vbGluby1kZW1v\"\n }\n ],\n \"agenda_id\": 12345,\n \"file_split\": false,\n \"type\": \"PurchaseInvoice\"\n }\n ]\n}".data(using: .utf8)
let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)Responses
201 Created
Synthetic example of a successful upload:
{
"documents": [
{
"upload_file_name": "demo-supplier-invoice.pdf",
"id": 24680
}
]
}
201 Created (duplicate detected)
When check_file_duplicates=1, inspect each result for a message. A duplicate result uses the same HTTP status as a successful upload and includes the original upload and document references.
{
"documents": [
{
"upload_file_name": "demo-supplier-invoice.pdf",
"message": "File duplicate",
"original_upload_uuid": "00000000-0000-4000-8000-000000000001",
"original_upload_doc_ids": [24680]
}
]
}