leadtext
leadtext
leadtext
Invoices, receipts, statements
Auto-title papers
Matter-ready naming
Field, onboarding, reporting ops
Shot logs, call sheets, deliverables
Configs, audit logs, incidents
Transcripts, lesson plans, records
Invoices, product sheets, shipping
Leases, inspections, work orders
Receipts, reports, reimbursements
BOLs, PODs, carrier invoices
Official SDK
Java
Java 11+ with CompletableFuture async support. Designed for enterprise applications with Spring Boot integration and automatic retries.
Rename PDFs, split multi-page documents, and extract structured data using the official Java SDK for Renamed.to.
- 1Add to.renamed:renamed-sdk via Maven or Gradle and build the client
- 2Call rename(), pdfSplit(), or extract() with byte arrays or use async variants
- 3Integrate with Spring Boot or use CompletableFuture for non-blocking operations
MIT licensed, open source on GitHub, published on Maven Central.
On this page
Installation
<dependency> <groupId>to.renamed</groupId> <artifactId>renamed-sdk</artifactId> <version>0.1.0</version></dependency>implementation 'to.renamed:renamed-sdk:0.1.0'Quickstart
Initialize the client and start making API calls.
import to.renamed.RenamedClient;import to.renamed.model.*;import java.nio.file.Files;import java.nio.file.Path;public class Main { public static void main(String[] args) throws Exception { // Initialize the client var client = RenamedClient.builder() .apiKey(System.getenv("RENAMED_API_KEY")) .build(); // Rename a PDF byte[] pdfBytes = Files.readAllBytes(Path.of("invoice.pdf")); RenameResult result = client.rename(pdfBytes); System.out.println(result.getSuggestedFilename()); // -> "2024-01-15_AcmeCorp_INV-1234.pdf" // Split a multi-page PDF byte[] docBytes = Files.readAllBytes(Path.of("documents.pdf")); SplitJob job = client.pdfSplit(docBytes, SplitOptions.builder() .mode("smart") .build()); System.out.println(job.getDocuments()); // Extract structured data byte[] receiptBytes = Files.readAllBytes(Path.of("receipt.pdf")); var data = client.extract(receiptBytes); System.out.println(data); }}Rename a PDF
Pass a byte array to get an AI-generated filename. Use custom instructions to control the naming format.
import to.renamed.RenamedClient;import to.renamed.model.RenameOptions;import to.renamed.model.RenameResult;import to.renamed.exception.RenamedApiException;import java.nio.file.Files;import java.nio.file.Path;public class RenameExample { public static void main(String[] args) { // Initialize the client var client = RenamedClient.builder() .apiKey(System.getenv("RENAMED_API_KEY")) .build(); try { // Read the PDF file byte[] pdfBytes = Files.readAllBytes( Path.of("./documents/invoice.pdf") ); // Rename the PDF RenameResult result = client.rename(pdfBytes); System.out.println("Suggested filename: " + result.getSuggestedFilename()); System.out.println("Confidence: " + result.getConfidence()); // Output: // Suggested filename: 2024-01-15_AcmeCorp_INV-1234.pdf // Confidence: 0.95 // Access extracted metadata var metadata = result.getMetadata(); System.out.println("Vendor: " + metadata.get("vendor")); System.out.println("Date: " + metadata.get("date")); System.out.println("Type: " + metadata.get("type")); // Use custom naming instructions RenameResult customResult = client.rename(pdfBytes, RenameOptions.builder() .instructions("Format: YYYY-MM-DD_VendorName_Amount") .build()); System.out.println(customResult.getSuggestedFilename()); // -> "2024-01-15_AcmeCorp_$1250.pdf" } catch (RenamedApiException e) { System.err.println("API Error: " + e.getCode() + " - " + e.getMessage()); } catch (Exception e) { System.err.println("Error: " + e.getMessage()); } }}Split a PDF
Split multi-page PDFs into separate documents. The API uses async jobs for large files—poll for completion or use the built-in wait helper.
import to.renamed.RenamedClient;import to.renamed.model.SplitOptions;import to.renamed.model.SplitJob;import to.renamed.model.SplitDocument;import to.renamed.exception.RenamedApiException;import java.nio.file.Files;import java.nio.file.Path;import java.time.Duration;import java.util.concurrent.TimeUnit;public class SplitExample { public static void main(String[] args) { var client = RenamedClient.builder() .apiKey(System.getenv("RENAMED_API_KEY")) .timeout(Duration.ofMinutes(5)) .build(); try { // Read a multi-page PDF byte[] pdfBytes = Files.readAllBytes( Path.of("./documents/combined.pdf") ); // Submit the split job with smart mode (AI detects document boundaries) SplitJob job = client.pdfSplit(pdfBytes, SplitOptions.builder() .mode("smart") .build()); System.out.println("Job ID: " + job.getJobId()); System.out.println("Status: " + job.getState()); // Option 1: Wait for completion (built-in polling) SplitJob completed = job.waitForCompletion(); // Option 2: Manual polling for progress updates // while (job.getState().equals("processing")) { // System.out.println("Progress: " + job.getProgress() + "%"); // TimeUnit.SECONDS.sleep(1); // job = client.getJob(job.getJobId()); // } // Process the split documents System.out.println("Split into " + completed.getDocuments().size() + " documents:"); for (int i = 0; i < completed.getDocuments().size(); i++) { SplitDocument doc = completed.getDocuments().get(i); System.out.printf(" [%d] %s (pages %s)%n", i + 1, doc.getFilename(), doc.getPages()); // Output: // [1] invoice_1.pdf (pages [1, 2]) // [2] invoice_2.pdf (pages [3, 4]) // Download each split document byte[] docBytes = client.downloadFile(doc.getDownloadUrl()); // Save to output directory Path outputPath = Path.of("./output", doc.getFilename()); Files.createDirectories(outputPath.getParent()); Files.write(outputPath, docBytes); } } catch (RenamedApiException e) { System.err.println("API Error: " + e.getCode() + " - " + e.getMessage()); } catch (Exception e) { System.err.println("Error: " + e.getMessage()); } }}Extract Data
Extract structured data from invoices, receipts, and other documents. Define Java records for type-safe extraction.
import to.renamed.RenamedClient;import to.renamed.model.ExtractOptions;import to.renamed.exception.RenamedApiException;import com.fasterxml.jackson.databind.ObjectMapper;import java.nio.file.Files;import java.nio.file.Path;import java.util.List;import java.util.Map;public class ExtractExample { // Define typed records for invoice extraction public record LineItem( String description, int quantity, double unitPrice ) {} public record Invoice( String invoiceNumber, String vendor, String date, List<LineItem> lineItems, double subtotal, double tax, double total ) {} public static void main(String[] args) { var client = RenamedClient.builder() .apiKey(System.getenv("RENAMED_API_KEY")) .build(); var objectMapper = new ObjectMapper(); try { // Read the PDF file byte[] pdfBytes = Files.readAllBytes( Path.of("./documents/invoice.pdf") ); // Basic extraction (returns Map<String, Object>) Map<String, Object> data = client.extract(pdfBytes); System.out.println("Vendor: " + data.get("vendor")); System.out.println("Date: " + data.get("date")); System.out.println("Total: " + data.get("total")); // Output: // Vendor: Acme Corp // Date: 2024-01-15 // Total: 1250.00 // Typed extraction: convert to a record Invoice invoice = objectMapper.convertValue(data, Invoice.class); // Now you have fully typed access System.out.printf("Invoice #%s from %s%n", invoice.invoiceNumber(), invoice.vendor()); System.out.println("Line items: " + invoice.lineItems().size()); for (LineItem item : invoice.lineItems()) { System.out.printf(" - %s: %d x $%.2f%n", item.description(), item.quantity(), item.unitPrice()); } System.out.printf("Total: $%.2f%n", invoice.total()); // Output: // Invoice #INV-2024-1234 from Acme Corp // Line items: 2 // - Widget Pro: 5 x $199.00 // - Support Plan: 1 x $342.50 // Total: $1337.50 } catch (RenamedApiException e) { System.err.println("API Error: " + e.getCode() + " - " + e.getMessage()); } catch (Exception e) { System.err.println("Error: " + e.getMessage()); } }}Framework Integrations
Common integration patterns for popular frameworks.
Spring Boot RestController
Handle PDF uploads in a Spring Boot application with proper validation and error handling.
package com.example.demo.controller;import org.springframework.http.ResponseEntity;import org.springframework.web.bind.annotation.*;import org.springframework.web.multipart.MultipartFile;import to.renamed.RenamedClient;import to.renamed.model.RenameResult;import to.renamed.model.SplitJob;import to.renamed.model.SplitOptions;import to.renamed.exception.RenamedApiException;import java.io.IOException;import java.util.List;import java.util.Map;@RestController@RequestMapping("/api/documents")public class DocumentController { private final RenamedClient renamedClient; public DocumentController(RenamedClient renamedClient) { this.renamedClient = renamedClient; } @PostMapping("/rename") public ResponseEntity<?> renameDocument(@RequestParam("file") MultipartFile file) { // Validate file type if (file.isEmpty()) { return ResponseEntity.badRequest() .body(Map.of("error", "No file provided")); } String contentType = file.getContentType(); if (contentType == null || !contentType.equals("application/pdf")) { return ResponseEntity.badRequest() .body(Map.of("error", "Only PDF files are supported")); } try { byte[] pdfBytes = file.getBytes(); RenameResult result = renamedClient.rename(pdfBytes); return ResponseEntity.ok(Map.of( "suggestedFilename", result.getSuggestedFilename(), "confidence", result.getConfidence(), "metadata", result.getMetadata() )); } catch (RenamedApiException e) { return ResponseEntity.status(502) .body(Map.of("error", e.getMessage(), "code", e.getCode())); } catch (IOException e) { return ResponseEntity.status(500) .body(Map.of("error", "Failed to read file")); } } @PostMapping("/split") public ResponseEntity<?> splitDocument( @RequestParam("file") MultipartFile file, @RequestParam(value = "mode", defaultValue = "smart") String mode) { if (file.isEmpty()) { return ResponseEntity.badRequest() .body(Map.of("error", "No file provided")); } try { byte[] pdfBytes = file.getBytes(); SplitJob job = renamedClient.pdfSplit(pdfBytes, SplitOptions.builder() .mode(mode) .build()); // Wait for completion SplitJob completed = job.waitForCompletion(); return ResponseEntity.ok(Map.of( "jobId", completed.getJobId(), "documents", completed.getDocuments().stream() .map(doc -> Map.of( "filename", doc.getFilename(), "pages", doc.getPages(), "downloadUrl", doc.getDownloadUrl() )) .toList() )); } catch (RenamedApiException e) { return ResponseEntity.status(502) .body(Map.of("error", e.getMessage())); } catch (IOException e) { return ResponseEntity.status(500) .body(Map.of("error", "Failed to read file")); } } @PostMapping("/extract") public ResponseEntity<?> extractData(@RequestParam("file") MultipartFile file) { if (file.isEmpty()) { return ResponseEntity.badRequest() .body(Map.of("error", "No file provided")); } try { byte[] pdfBytes = file.getBytes(); Map<String, Object> data = renamedClient.extract(pdfBytes); return ResponseEntity.ok(data); } catch (RenamedApiException e) { return ResponseEntity.status(502) .body(Map.of("error", e.getMessage())); } catch (IOException e) { return ResponseEntity.status(500) .body(Map.of("error", "Failed to read file")); } }}Spring Boot Configuration
Configure the Renamed client as a Spring Bean with properties-based configuration.
package com.example.demo.config;import org.springframework.beans.factory.annotation.Value;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import to.renamed.RenamedClient;import java.time.Duration;@Configurationpublic class RenamedConfig { @Bean public RenamedClient renamedClient( @Value("${renamed.api-key}") String apiKey, @Value("${renamed.timeout:30}") int timeoutSeconds, @Value("${renamed.max-retries:3}") int maxRetries) { return RenamedClient.builder() .apiKey(apiKey) .timeout(Duration.ofSeconds(timeoutSeconds)) .maxRetries(maxRetries) .build(); }}// application.properties or application.yml:// renamed.api-key=${RENAMED_API_KEY}// renamed.timeout=30// renamed.max-retries=3Async with CompletableFuture
Use CompletableFuture for non-blocking operations and parallel processing.
import to.renamed.RenamedClient;import to.renamed.model.RenameResult;import to.renamed.model.SplitJob;import to.renamed.model.SplitOptions;import java.nio.file.Files;import java.nio.file.Path;import java.util.List;import java.util.concurrent.CompletableFuture;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class AsyncExample { public static void main(String[] args) throws Exception { var client = RenamedClient.builder() .apiKey(System.getenv("RENAMED_API_KEY")) .build(); // Single async operation byte[] pdfBytes = Files.readAllBytes(Path.of("invoice.pdf")); CompletableFuture<RenameResult> future = client.renameAsync(pdfBytes); future .thenAccept(result -> { System.out.println("Renamed to: " + result.getSuggestedFilename()); System.out.println("Confidence: " + result.getConfidence()); }) .exceptionally(e -> { System.err.println("Error: " + e.getMessage()); return null; }); // Process multiple files in parallel List<Path> files = List.of( Path.of("doc1.pdf"), Path.of("doc2.pdf"), Path.of("doc3.pdf") ); List<CompletableFuture<RenameResult>> futures = files.stream() .map(path -> { try { byte[] bytes = Files.readAllBytes(path); return client.renameAsync(bytes); } catch (Exception e) { return CompletableFuture.<RenameResult>failedFuture(e); } }) .toList(); // Wait for all to complete CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) .thenRun(() -> { futures.forEach(f -> { try { RenameResult result = f.join(); System.out.println("Result: " + result.getSuggestedFilename()); } catch (Exception e) { System.err.println("Failed: " + e.getMessage()); } }); }) .join(); // Async PDF split with progress monitoring byte[] combinedPdf = Files.readAllBytes(Path.of("combined.pdf")); client.pdfSplitAsync(combinedPdf, SplitOptions.builder().mode("smart").build()) .thenCompose(job -> { System.out.println("Job started: " + job.getJobId()); return job.waitForCompletionAsync(); }) .thenAccept(completed -> { System.out.println("Split into " + completed.getDocuments().size() + " documents"); completed.getDocuments().forEach(doc -> System.out.println(" - " + doc.getFilename()) ); }) .exceptionally(e -> { System.err.println("Split failed: " + e.getMessage()); return null; }) .join(); }}Error Handling
The SDK throws typed exceptions that you can catch and handle appropriately. Use try-catch for synchronous calls or handle CompletableFuture exceptions for async.
import to.renamed.RenamedClient;import to.renamed.model.RenameResult;import to.renamed.exception.RateLimitException;import to.renamed.exception.RenamedApiException;import to.renamed.exception.InvalidFileException;import to.renamed.exception.AuthenticationException;import java.nio.file.Files;import java.nio.file.Path;import java.util.concurrent.CompletableFuture;import java.util.concurrent.TimeUnit;public class ErrorHandling { public static void main(String[] args) { var client = RenamedClient.builder() .apiKey(System.getenv("RENAMED_API_KEY")) .build(); try { byte[] pdfBytes = Files.readAllBytes(Path.of("invoice.pdf")); RenameResult result = client.rename(pdfBytes); System.out.println("Renamed to: " + result.getSuggestedFilename()); } catch (RateLimitException e) { // Rate limited - wait and retry System.out.printf("Rate limited. Retry after %d seconds%n", e.getRetryAfter()); try { TimeUnit.SECONDS.sleep(e.getRetryAfter()); // Retry the request... } catch (InterruptedException ie) { Thread.currentThread().interrupt(); } } catch (InvalidFileException e) { // File is not a valid PDF or is corrupted System.out.println("Invalid file: " + e.getMessage()); } catch (AuthenticationException e) { // API key is invalid or expired System.out.println("Authentication failed: " + e.getMessage()); } catch (RenamedApiException e) { // Other API errors System.out.printf("API Error [%s]: %s%n", e.getCode(), e.getMessage()); if (e.getDetails() != null) { System.out.println("Details: " + e.getDetails()); } } catch (Exception e) { // Network errors, file I/O errors, etc. System.out.println("Unexpected error: " + e.getMessage()); } // Async error handling with CompletableFuture CompletableFuture<RenameResult> future = client.renameAsync(new byte[0]); future.handle((result, throwable) -> { if (throwable != null) { Throwable cause = throwable.getCause(); if (cause instanceof RateLimitException rle) { System.out.println("Async rate limited: " + rle.getRetryAfter()); } else if (cause instanceof RenamedApiException rae) { System.out.println("Async API error: " + rae.getMessage()); } else { System.out.println("Async error: " + throwable.getMessage()); } return null; } System.out.println("Async success: " + result.getSuggestedFilename()); return result; }); }}Full documentation on GitHub
For more examples, advanced usage patterns, and detailed API documentation, see the full Java SDK README on GitHub.
Read the Java SDK docsFrequently asked questions
- What Java versions are supported?
- The Java SDK supports Java 11 and above. It uses modern Java features like records and CompletableFuture for async operations.
- Does it work with Spring Boot?
- Yes, the SDK integrates seamlessly with Spring Boot. You can configure it as a Bean and inject it where needed.
- Which build tools are supported?
- The SDK is available on Maven Central and works with Maven, Gradle, and any other build tool that supports Maven repositories.
- How do I handle async operations?
- All methods have async variants that return CompletableFuture. Use thenAccept(), thenCompose(), or handle() for chaining operations.
- Is the client thread-safe?
- Yes, the RenamedClient is thread-safe and can be shared across threads. Use a single instance per application.