Skip to main content
POST
/
v1
/
files
/
upload
from retab import Retab
from pathlib import Path

client = Retab()

# Create an upload session for a local file.
invoice_path = Path("invoice.pdf")
session = client.files.create_upload(
    filename=invoice_path.name,
    size_bytes=invoice_path.stat().st_size,
    content_type="application/pdf",
)
mime_data = session.mime_data
print(f"Filename: {mime_data.filename}")
print(f"URL: {mime_data.url}")
import { Retab } from "@retab/node";

const client = new Retab({ apiKey: process.env.RETAB_API_KEY });

const mimeData = await client.files.complete_upload((await client.files.create_upload("invoice.pdf", 1024, "application/pdf")).fileId);

console.log(`Filename: ${mimeData.filename}`);
console.log(`URL: ${mimeData.url}`);
package main

import (
	"context"
	"fmt"
	"log"

	retab "github.com/retab-dev/retab/clients/go"
)

func ptr[T any](v T) *T { return &v }

func main() {
	ctx := context.Background()

	client, err := retab.NewClient("")
	if err != nil {
		log.Fatal(err)
	}

	session, err := client.Files.CreateUpload(ctx, &retab.FilesCreateUploadParams{
		Filename:    "invoice.pdf",
		ContentType: ptr("application/pdf"),
		SizeBytes:   1024,
	})
	if err != nil {
		log.Fatal(err)
	}
	mimeData := session.MIMEData

	fmt.Printf("Filename: %s\n", mimeData.Filename)
	fmt.Printf("URL: %s\n", mimeData.URL)
}
require 'retab'

client = Retab::Client.new(api_key: ENV['RETAB_API_KEY'])

bytes = File.binread('invoice.pdf')
session = client.files.create_upload(
  filename: 'invoice.pdf',
  size_bytes: bytes.bytesize,
  content_type: 'application/pdf',
)

puts "Filename: #{session.mime_data.filename}"
puts "URL: #{session.mime_data.url}"
use retab::models::UploadFileRequest;
use retab::resources::files::CreateUploadParams;
use retab::Retab;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Retab::new(std::env::var("RETAB_API_KEY")?);

    let bytes = std::fs::read("invoice.pdf")?;
    let session = client
        .files()
        .create_upload(CreateUploadParams::new(UploadFileRequest {
            filename: "invoice.pdf".into(),
            content_type: Some("application/pdf".into()),
            size_bytes: bytes.len() as i64,
            sha_256: None,
        }))
        .await?;

    let mime_data = session.mime_data.expect("upload session should include mime data");
    println!("Filename: {}", mime_data.filename);
    println!("URL: {}", mime_data.url);
    Ok(())
}
<?php
require 'vendor/autoload.php';

use Retab\Client;

$client = new Client(apiKey: getenv('RETAB_API_KEY'));

$result = $client->files()->createUpload(
    filename: 'value',
    sizeBytes: 10,
);
print_r($result);
using Retab;
using RetabClient = Retab.Retab;

var apiKey = Environment.GetEnvironmentVariable("RETAB_API_KEY")!;
var client = new RetabClient(apiKey);

var result = await client.Files.CreateUploadAsync(
    new FilesCreateUploadOptions
    {
        Filename = "invoice.pdf",
        ContentType = "application/pdf",
        SizeBytes = 12345,
    }
);
Console.WriteLine(result);
import com.retab.RetabClient;

public final class Example {
  public static void main(String[] args) throws Exception {
    RetabClient client = new RetabClient(System.getenv("RETAB_API_KEY"));

    var result = client.files().createUpload("invoice.pdf", "application/pdf", 10L, "abc123");
    System.out.println(result);
  }
}
SESSION=$(curl -s -X POST \
  'https://api.retab.com/v1/files/upload' \
  -H "Authorization: Bearer $RETAB_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "filename": "invoice.pdf",
    "content_type": "application/pdf",
    "size_bytes": 12345
  }')

UPLOAD_URL=$(echo "$SESSION" | jq -r '.uploadUrl')
FILE_ID=$(echo "$SESSION" | jq -r '.fileId')

curl -X PUT "$UPLOAD_URL" \
  -H 'Content-Type: application/pdf' \
  --data-binary '@invoice.pdf'

curl -X POST \
  "https://api.retab.com/v1/files/upload/$FILE_ID/complete" \
  -H "Authorization: Bearer $RETAB_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{}'
{
  "fileId": "file_a1b2c3d4e5f6",
  "uploadUrl": "https://storage.googleapis.com/...",
  "uploadMethod": "PUT",
  "uploadHeaders": {
    "Content-Type": "application/pdf"
  },
  "mimeData": {
    "filename": "invoice.pdf",
    "url": "https://storage.retab.com/file_a1b2c3d4e5f6"
  },
  "expiresAt": "2026-04-24T12:00:00Z"
}
Create a direct-to-storage upload session. Upload the file bytes to the returned signed uploadUrl, then call POST /v1/files/upload/{file_id}/complete. The completed file is returned as MIMEData and can be passed directly to extractions, workflows, and other operations.
from retab import Retab
from pathlib import Path

client = Retab()

# Create an upload session for a local file.
invoice_path = Path("invoice.pdf")
session = client.files.create_upload(
    filename=invoice_path.name,
    size_bytes=invoice_path.stat().st_size,
    content_type="application/pdf",
)
mime_data = session.mime_data
print(f"Filename: {mime_data.filename}")
print(f"URL: {mime_data.url}")
import { Retab } from "@retab/node";

const client = new Retab({ apiKey: process.env.RETAB_API_KEY });

const mimeData = await client.files.complete_upload((await client.files.create_upload("invoice.pdf", 1024, "application/pdf")).fileId);

console.log(`Filename: ${mimeData.filename}`);
console.log(`URL: ${mimeData.url}`);
package main

import (
	"context"
	"fmt"
	"log"

	retab "github.com/retab-dev/retab/clients/go"
)

func ptr[T any](v T) *T { return &v }

func main() {
	ctx := context.Background()

	client, err := retab.NewClient("")
	if err != nil {
		log.Fatal(err)
	}

	session, err := client.Files.CreateUpload(ctx, &retab.FilesCreateUploadParams{
		Filename:    "invoice.pdf",
		ContentType: ptr("application/pdf"),
		SizeBytes:   1024,
	})
	if err != nil {
		log.Fatal(err)
	}
	mimeData := session.MIMEData

	fmt.Printf("Filename: %s\n", mimeData.Filename)
	fmt.Printf("URL: %s\n", mimeData.URL)
}
require 'retab'

client = Retab::Client.new(api_key: ENV['RETAB_API_KEY'])

bytes = File.binread('invoice.pdf')
session = client.files.create_upload(
  filename: 'invoice.pdf',
  size_bytes: bytes.bytesize,
  content_type: 'application/pdf',
)

puts "Filename: #{session.mime_data.filename}"
puts "URL: #{session.mime_data.url}"
use retab::models::UploadFileRequest;
use retab::resources::files::CreateUploadParams;
use retab::Retab;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Retab::new(std::env::var("RETAB_API_KEY")?);

    let bytes = std::fs::read("invoice.pdf")?;
    let session = client
        .files()
        .create_upload(CreateUploadParams::new(UploadFileRequest {
            filename: "invoice.pdf".into(),
            content_type: Some("application/pdf".into()),
            size_bytes: bytes.len() as i64,
            sha_256: None,
        }))
        .await?;

    let mime_data = session.mime_data.expect("upload session should include mime data");
    println!("Filename: {}", mime_data.filename);
    println!("URL: {}", mime_data.url);
    Ok(())
}
<?php
require 'vendor/autoload.php';

use Retab\Client;

$client = new Client(apiKey: getenv('RETAB_API_KEY'));

$result = $client->files()->createUpload(
    filename: 'value',
    sizeBytes: 10,
);
print_r($result);
using Retab;
using RetabClient = Retab.Retab;

var apiKey = Environment.GetEnvironmentVariable("RETAB_API_KEY")!;
var client = new RetabClient(apiKey);

var result = await client.Files.CreateUploadAsync(
    new FilesCreateUploadOptions
    {
        Filename = "invoice.pdf",
        ContentType = "application/pdf",
        SizeBytes = 12345,
    }
);
Console.WriteLine(result);
import com.retab.RetabClient;

public final class Example {
  public static void main(String[] args) throws Exception {
    RetabClient client = new RetabClient(System.getenv("RETAB_API_KEY"));

    var result = client.files().createUpload("invoice.pdf", "application/pdf", 10L, "abc123");
    System.out.println(result);
  }
}
SESSION=$(curl -s -X POST \
  'https://api.retab.com/v1/files/upload' \
  -H "Authorization: Bearer $RETAB_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "filename": "invoice.pdf",
    "content_type": "application/pdf",
    "size_bytes": 12345
  }')

UPLOAD_URL=$(echo "$SESSION" | jq -r '.uploadUrl')
FILE_ID=$(echo "$SESSION" | jq -r '.fileId')

curl -X PUT "$UPLOAD_URL" \
  -H 'Content-Type: application/pdf' \
  --data-binary '@invoice.pdf'

curl -X POST \
  "https://api.retab.com/v1/files/upload/$FILE_ID/complete" \
  -H "Authorization: Bearer $RETAB_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{}'
{
  "fileId": "file_a1b2c3d4e5f6",
  "uploadUrl": "https://storage.googleapis.com/...",
  "uploadMethod": "PUT",
  "uploadHeaders": {
    "Content-Type": "application/pdf"
  },
  "mimeData": {
    "filename": "invoice.pdf",
    "url": "https://storage.retab.com/file_a1b2c3d4e5f6"
  },
  "expiresAt": "2026-04-24T12:00:00Z"
}

Use the uploaded file in later requests

For large documents, prefer an object-storage URL first. Retab fetches the file server-side, avoiding inline/base64 request bodies that can trigger 413 Request Entity Too Large. Use a time-limited signed URL when the object is private. Supported remote URL hosts include Azure Blob Storage (*.blob.core.windows.net), Google Cloud Storage (storage.googleapis.com), Amazon S3 (amazonaws.com), and Cloudflare R2 (*.r2.cloudflarestorage.com and *.r2.dev). Custom domains are not fetched by default; contact support if you need one allowlisted. If you do not have an object-storage URL available, upload the file to Retab first. The SDK returns a durable MIMEData reference. You can pass that object directly, or pass its Retab storage URL.
from retab import Retab

client = Retab(api_key="YOUR_RETAB_API_KEY")

schema = {
    "type": "object",
    "properties": {
        "invoice_number": {"type": "string"},
        "total_amount": {"type": "number"},
    },
}

# Option 1: object-storage URL
azure_blob_url = "https://<account>.blob.core.windows.net/<container>/large_document.pdf?<sas_token>"

extraction = client.extractions.create(
    document=azure_blob_url,
    model="retab-small",
    json_schema=schema,
)

# Option 2: Retab upload session, then reuse the returned URL
session = client.files.create_upload(
    filename="large_document.pdf",
    size_bytes=12345,
    content_type="application/pdf",
)
mime_ref = session.mime_data

extraction = client.extractions.create(
    document=mime_ref.url,
    model="retab-small",
    json_schema=schema,
)

# This also works:
extraction = client.extractions.create(
    document=mime_ref,
    model="retab-small",
    json_schema=schema,
)
import { Retab } from "@retab/node";

const client = new Retab({ apiKey: process.env.RETAB_API_KEY });

const schema = {
  type: "object",
  properties: {
    invoice_number: { type: "string" },
    total_amount: { type: "number" },
  },
};

// Option 1: object-storage URL
const cloudflareR2Url = "https://<public-id>.r2.dev/large_document.pdf";

const extractionFromR2 = await client.extractions.create(cloudflareR2Url, schema, "retab-small");

// Option 2: Retab upload, then reuse the returned URL
const mimeRef = await client.files.complete_upload((await client.files.create_upload("large_document.pdf", 1024, "application/pdf")).fileId);

const extraction = await client.extractions.create(mimeRef.url, schema, "retab-small");

// This also works:
const sameExtraction = await client.extractions.create(mimeRef, schema, "retab-small");
package main

import (
	"context"
	"fmt"
	"log"

	retab "github.com/retab-dev/retab/clients/go"
)

func ptr[T any](v T) *T { return &v }

func main() {
	ctx := context.Background()

	client, err := retab.NewClient("YOUR_RETAB_API_KEY")
	if err != nil {
		log.Fatal(err)
	}

	schema := map[string]any{
		"type": "object",
		"properties": map[string]any{
			"invoice_number": map[string]any{"type": "string"},
			"total_amount":   map[string]any{"type": "number"},
		},
	}

	// Option 1: object-storage URL
	cloudflareR2URL := "https://<public-id>.r2.dev/large_document.pdf"

	extractionFromR2, err := client.Extractions.Create(ctx, &retab.ExtractionsCreateParams{
		Document:   cloudflareR2URL,
		Model:      ptr("retab-small"),
		JSONSchema: schema,
	})
	if err != nil {
		log.Fatal(err)
	}
	_ = extractionFromR2

	// Option 2: Retab upload, then reuse the returned URL
	session, err := client.Files.CreateUpload(ctx, &retab.FilesCreateUploadParams{
		Filename:    "large_document.pdf",
		ContentType: ptr("application/pdf"),
		SizeBytes:   1024,
	})
	if err != nil {
		log.Fatal(err)
	}
	mimeRef := session.MIMEData

	extraction, err := client.Extractions.Create(ctx, &retab.ExtractionsCreateParams{
		Document:   mimeRef.URL,
		Model:      ptr("retab-small"),
		JSONSchema: schema,
	})
	if err != nil {
		log.Fatal(err)
	}

	// This also works:
	sameExtraction, err := client.Extractions.Create(ctx, &retab.ExtractionsCreateParams{
		Document:   mimeRef,
		Model:      ptr("retab-small"),
		JSONSchema: schema,
	})
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(extraction.ID, sameExtraction.ID)
}
require 'retab'

client = Retab::Client.new(api_key: ENV['RETAB_API_KEY'])

schema = {
  'type' => 'object',
  'properties' => {
    'invoice_number' => { 'type' => 'string' },
    'total_amount' => { 'type' => 'number' },
  },
}

# Option 1: object-storage URL
azure_blob_url = 'https://<account>.blob.core.windows.net/<container>/large_document.pdf?<sas_token>'

extraction = client.extractions.create(
  document: azure_blob_url,
  model: 'retab-small',
  json_schema: schema,
)

# Option 2: Retab upload, then reuse the returned MimeData
file_bytes = File.binread('large_document.pdf')
upload = client.files.create_upload(
  filename: 'large_document.pdf',
  size_bytes: file_bytes.bytesize,
  content_type: 'application/pdf',
)
# PUT the file bytes to upload.upload_url, then finalize:
mime_ref = client.files.complete_upload(file_id: upload.id)

extraction = client.extractions.create(
  document: mime_ref,
  model: 'retab-small',
  json_schema: schema,
)
use retab::resources::extractions::CreateParams;
use retab::Retab;
use serde_json::json;
use std::collections::HashMap;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Retab::new(std::env::var("RETAB_API_KEY")?);

    let schema = HashMap::from([
        ("type".to_string(), json!("object")),
        ("properties".to_string(), json!({
            "invoice_number": { "type": "string" },
            "total_amount": { "type": "number" }
        })),
    ]);

    let url = "https://<public-id>.r2.dev/large_document.pdf";
    let mut params = CreateParams::new(url, schema);
    params.body.model = Some("retab-small".into());

    let extraction = client.extractions().create(params).await?;
    println!("{:?}", extraction.id);
    Ok(())
}
<?php
require 'vendor/autoload.php';

use Retab\Client;

$client = new Client(apiKey: getenv('RETAB_API_KEY'));

$schema = [
    'type' => 'object',
    'properties' => [
        'invoice_number' => ['type' => 'string'],
        'total_amount' => ['type' => 'number'],
    ],
];

$extraction = $client->extractions()->create(
    document: 'https://<public-id>.r2.dev/large_document.pdf',
    jsonSchema: $schema,
    model: 'retab-small',
);

print_r($extraction);
using Retab;
using RetabClient = Retab.Retab;

var apiKey = Environment.GetEnvironmentVariable("RETAB_API_KEY")!;
var client = new RetabClient(apiKey);

var extraction = await client.Extractions.CreateAsync(
    new ExtractionsCreateOptions
    {
        Document = MimeData.FromUrl(new Uri("https://<public-id>.r2.dev/large_document.pdf")),
        JsonSchema = new Dictionary<string, object>
        {
            ["type"] = "object",
            ["properties"] = new Dictionary<string, object>
            {
                ["invoice_number"] = new Dictionary<string, object> { ["type"] = "string" },
                ["total_amount"] = new Dictionary<string, object> { ["type"] = "number" },
            },
        },
        Model = "retab-small",
    }
);

Console.WriteLine(extraction.Id);
import com.retab.RetabClient;

public final class Example {
  public static void main(String[] args) throws Exception {
    RetabClient client = new RetabClient(System.getenv("RETAB_API_KEY"));

    var result = client.files().createUpload("invoice.pdf", "application/pdf", 10L, "abc123");
    System.out.println(result);
  }
}
Signed object-storage URLs are bearer URLs controlled by you; keep them time-limited and scoped to the single document being processed. https://storage.retab.com/file_... URLs are opaque Retab references, not public download links. Retab resolves them against the authenticated caller’s organization before processing.

Authorizations

Authorization
string
header
required

Bearer authentication header of the form Bearer <token>, where <token> is your auth token.

Body

application/json

Body to start a file upload: the filename, expected size_bytes, and optional content type and checksum.

filename
string
required

Filename to store

Minimum string length: 1
size_bytes
integer
required

Expected upload size in bytes

Required range: x >= 0
content_type
string | null

MIME type the client will upload

sha256
string | null

Optional SHA-256 checksum

Pattern: ^[a-fA-F0-9]{64}$

Response

Successful Response

Instructions for uploading file content to a reserved file record.

Returned when starting a file upload. Carries the new file_id, a short-lived signed upload_url with the HTTP method and headers to use, a durable reference to the file, and the URL's expires_at time.

fileId
string
required

Underlying file ID

uploadUrl
string
required

Short-lived signed upload URL

expiresAt
string<date-time>
required

Upload URL expiration

uploadMethod
string
default:PUT

HTTP method for upload

uploadHeaders
Uploadheaders · object

Headers required by the signed upload URL

mimeData
MIMEData · object | null

Durable Retab MIMEData reference