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
PHP
PHP 8.0+ with PSR-18 HTTP client support. Works with Guzzle, Symfony HTTP Client, or any PSR-18 compatible client.
Rename PDFs, split multi-page documents, and extract structured data using the official PHP SDK for Renamed.to.
- 1Install with composer require renamed/sdk and autoload
- 2Call rename(), pdfSplit(), or extract() with file contents
- 3Integrate with Laravel service container or any PSR-18 HTTP client
MIT licensed, open source on GitHub, published on Packagist.
On this page
Installation
composer require renamed/sdkQuickstart
Initialize the client and start making API calls.
<?phprequire_once 'vendor/autoload.php';use Renamed\Client;// Initialize the client$client = new Client(apiKey: getenv('RENAMED_API_KEY'));// Rename a PDF$result = $client->rename(file_get_contents('invoice.pdf'));echo $result->suggestedFilename;// -> "2024-01-15_AcmeCorp_INV-1234.pdf"// Split a multi-page PDF$job = $client->pdfSplit( file_get_contents('documents.pdf'), mode: 'smart');print_r($job->documents);// -> [["filename" => "...", "downloadUrl" => "..."], ...]// Extract structured data$data = $client->extract(file_get_contents('receipt.pdf'));print_r($data);// -> ["vendor" => "...", "date" => "...", "amount" => "..."]Rename a PDF
Pass PDF bytes to get an AI-generated filename. Use custom instructions to control the naming format.
<?phpdeclare(strict_types=1);require_once 'vendor/autoload.php';use Renamed\Client;use Renamed\Options\RenameOptions;// Initialize the client$client = new Client(apiKey: getenv('RENAMED_API_KEY'));// Read the PDF file$pdfBytes = file_get_contents('./documents/invoice.pdf');// Rename the PDF$result = $client->rename($pdfBytes);echo "Suggested filename: {$result->suggestedFilename}\n";echo "Confidence: {$result->confidence}\n";// Output:// Suggested filename: 2024-01-15_AcmeCorp_INV-1234.pdf// Confidence: 0.95// Access extracted metadataecho "Vendor: {$result->metadata['vendor']}\n";echo "Date: {$result->metadata['date']}\n";echo "Type: {$result->metadata['type']}\n";// Use custom naming instructions$customResult = $client->rename($pdfBytes, new RenameOptions( instructions: 'Format: YYYY-MM-DD_VendorName_Amount'));echo $customResult->suggestedFilename;// -> "2024-01-15_AcmeCorp_$1250.pdf"// Rename from a URL$urlResult = $client->renameFromUrl('https://example.com/document.pdf');// Using a stream instead of loading entire file into memory$stream = fopen('./documents/large-invoice.pdf', 'rb');$streamResult = $client->rename($stream);fclose($stream);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.
<?phpdeclare(strict_types=1);require_once 'vendor/autoload.php';use Renamed\Client;use Renamed\Options\SplitOptions;$client = new Client(apiKey: getenv('RENAMED_API_KEY'));// Read a multi-page PDF$pdfBytes = file_get_contents('./documents/combined.pdf');// Submit the split job with smart mode (AI detects document boundaries)$job = $client->pdfSplit($pdfBytes, new SplitOptions(mode: 'smart'));echo "Job ID: {$job->jobId}\n";echo "Status: {$job->state}\n";// Option 1: Wait for completion (built-in polling)$completed = $job->waitForCompletion();// Option 2: Manual polling for progress updates// while ($job->state === 'processing') {// echo "Progress: {$job->progress}%\n";// sleep(1);// $job = $client->getJob($job->jobId);// }// Process the split documentsecho "Split into " . count($completed->documents) . " documents:\n";foreach ($completed->documents as $i => $doc) { $num = $i + 1; $pages = implode(', ', $doc->pages); echo " [{$num}] {$doc->filename} (pages {$pages})\n"; // Output: // [1] invoice_1.pdf (pages 1, 2) // [2] invoice_2.pdf (pages 3, 4) // Download each split document $docBytes = $client->downloadFile($doc->downloadUrl); // Save to output directory $outputPath = "./output/{$doc->filename}"; if (!is_dir('./output')) { mkdir('./output', 0755, true); } file_put_contents($outputPath, $docBytes); echo " Saved: {$outputPath}\n";}// With a timeout (in seconds)$completed = $job->waitForCompletion(timeout: 300); // 5 minutesExtract Data
Extract structured data from invoices, receipts, and other documents. Use PHP classes for type-safe extraction.
<?phpdeclare(strict_types=1);require_once 'vendor/autoload.php';use Renamed\Client;// Define typed classes for invoice extractionreadonly class LineItem{ public function __construct( public string $description, public int $quantity, public float $unitPrice, ) {} public static function fromArray(array $data): self { return new self( description: $data['description'], quantity: $data['quantity'], unitPrice: $data['unitPrice'], ); }}readonly class Invoice{ /** * @param LineItem[] $lineItems */ public function __construct( public string $invoiceNumber, public string $vendor, public string $date, public array $lineItems, public float $subtotal, public float $tax, public float $total, ) {} public static function fromArray(array $data): self { return new self( invoiceNumber: $data['invoiceNumber'], vendor: $data['vendor'], date: $data['date'], lineItems: array_map( fn($item) => LineItem::fromArray($item), $data['lineItems'] ?? [] ), subtotal: $data['subtotal'], tax: $data['tax'], total: $data['total'], ); }}// Initialize the client$client = new Client(apiKey: getenv('RENAMED_API_KEY'));// Read the PDF file$pdfBytes = file_get_contents('./documents/invoice.pdf');// Basic extraction (returns associative array)$data = $client->extract($pdfBytes);echo "Vendor: {$data['vendor']}\n";echo "Date: {$data['date']}\n";echo "Total: {$data['total']}\n";// Output:// Vendor: Acme Corp// Date: 2024-01-15// Total: 1250.00// Typed extraction: convert to a class$invoice = Invoice::fromArray($data);// Now you have typed accessecho "Invoice #{$invoice->invoiceNumber} from {$invoice->vendor}\n";echo "Line items: " . count($invoice->lineItems) . "\n";foreach ($invoice->lineItems as $item) { $price = number_format($item->unitPrice, 2); echo " - {$item->description}: {$item->quantity} x ${$price}\n";}echo "Total: $" . number_format($invoice->total, 2) . "\n";// Output:// Invoice #INV-2024-1234 from Acme Corp// Line items: 2// - Widget Pro: 5 x $199.00// - Support Plan: 1 x $342.50// Total: $1,337.50Framework Integrations
Common integration patterns for popular frameworks.
Laravel Controller
Handle PDF uploads in a Laravel controller with proper validation and error handling.
<?phpdeclare(strict_types=1);namespace App\Http\Controllers\Api;use App\Http\Controllers\Controller;use Illuminate\Http\JsonResponse;use Illuminate\Http\Request;use Renamed\Client;use Renamed\Options\SplitOptions;use Renamed\Exception\RateLimitException;use Renamed\Exception\ApiException;class DocumentController extends Controller{ public function __construct( private readonly Client $renamedClient, ) {} public function rename(Request $request): JsonResponse { $request->validate([ 'file' => 'required|file|mimes:pdf|max:10240', // 10MB max 'instructions' => 'nullable|string|max:500', ]); try { $pdfBytes = $request->file('file')->getContent(); $options = null; if ($request->has('instructions')) { $options = new \Renamed\Options\RenameOptions( instructions: $request->input('instructions') ); } $result = $this->renamedClient->rename($pdfBytes, $options); return response()->json([ 'suggested_filename' => $result->suggestedFilename, 'confidence' => $result->confidence, 'metadata' => $result->metadata, ]); } catch (RateLimitException $e) { return response()->json( ['error' => 'Rate limited', 'retry_after' => $e->getRetryAfter()], 429, ['Retry-After' => $e->getRetryAfter()] ); } catch (ApiException $e) { return response()->json( ['error' => $e->getMessage(), 'code' => $e->getCode()], 502 ); } } public function split(Request $request): JsonResponse { $request->validate([ 'file' => 'required|file|mimes:pdf|max:51200', // 50MB max 'mode' => 'nullable|string|in:smart,fixed,page', ]); try { $pdfBytes = $request->file('file')->getContent(); $mode = $request->input('mode', 'smart'); $job = $this->renamedClient->pdfSplit( $pdfBytes, new SplitOptions(mode: $mode) ); $completed = $job->waitForCompletion(); return response()->json([ 'job_id' => $completed->jobId, 'documents' => array_map(fn($doc) => [ 'filename' => $doc->filename, 'pages' => $doc->pages, 'download_url' => $doc->downloadUrl, ], $completed->documents), ]); } catch (ApiException $e) { return response()->json(['error' => $e->getMessage()], 502); } } public function extract(Request $request): JsonResponse { $request->validate([ 'file' => 'required|file|mimes:pdf|max:10240', ]); try { $pdfBytes = $request->file('file')->getContent(); $data = $this->renamedClient->extract($pdfBytes); return response()->json($data); } catch (ApiException $e) { return response()->json(['error' => $e->getMessage()], 502); } }}Laravel Service Provider
Register the SDK client in Laravel service container with configuration from environment.
<?phpdeclare(strict_types=1);namespace App\Providers;use Illuminate\Support\ServiceProvider;use Renamed\Client;use Renamed\ClientOptions;class RenamedServiceProvider extends ServiceProvider{ public function register(): void { $this->app->singleton(Client::class, function ($app) { return new Client( apiKey: config('services.renamed.api_key'), options: new ClientOptions( timeout: config('services.renamed.timeout', 30), maxRetries: config('services.renamed.max_retries', 3), ) ); }); } public function boot(): void { // Verify configuration on boot (optional) if (empty(config('services.renamed.api_key'))) { logger()->warning('[Renamed] API key not configured!'); } }}// config/services.php// 'renamed' => [// 'api_key' => env('RENAMED_API_KEY'),// 'timeout' => env('RENAMED_TIMEOUT', 30),// 'max_retries' => env('RENAMED_MAX_RETRIES', 3),// ],Laravel Queue Job
Process PDF files asynchronously using Laravel queues for background processing.
<?phpdeclare(strict_types=1);namespace App\Jobs;use App\Models\Document;use App\Notifications\DocumentProcessed;use Illuminate\Bus\Queueable;use Illuminate\Contracts\Queue\ShouldQueue;use Illuminate\Foundation\Bus\Dispatchable;use Illuminate\Queue\InteractsWithQueue;use Illuminate\Queue\SerializesModels;use Renamed\Client;use Renamed\Options\RenameOptions;use Renamed\Exception\RateLimitException;use Renamed\Exception\ApiException;class RenameDocumentJob implements ShouldQueue{ use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; public int $tries = 5; public int $backoff = 60; public function __construct( public readonly Document $document, public readonly ?string $instructions = null, ) {} public function handle(Client $client): void { // Download the file from storage $pdfBytes = Storage::get($this->document->file_path); // Rename via the API $options = $this->instructions ? new RenameOptions(instructions: $this->instructions) : null; $result = $client->rename($pdfBytes, $options); // Update the document record $this->document->update([ 'suggested_filename' => $result->suggestedFilename, 'confidence' => $result->confidence, 'metadata' => $result->metadata, 'processed_at' => now(), ]); // Notify the user $this->document->user->notify( new DocumentProcessed($this->document) ); } public function failed(\Throwable $exception): void { $this->document->update([ 'processing_error' => $exception->getMessage(), 'processed_at' => now(), ]); } public function retryUntil(): \DateTime { return now()->addMinutes(30); }}// Dispatching the job// RenameDocumentJob::dispatch($document, 'Format: YYYY-MM-DD_VendorName');Error Handling
The SDK throws typed exceptions that you can catch and handle appropriately. Use try-catch blocks for error handling.
<?phpdeclare(strict_types=1);require_once 'vendor/autoload.php';use Renamed\Client;use Renamed\Exception\RateLimitException;use Renamed\Exception\InvalidFileException;use Renamed\Exception\AuthenticationException;use Renamed\Exception\ApiException;use Renamed\Exception\NetworkException;$client = new Client(apiKey: getenv('RENAMED_API_KEY'));try { $pdfBytes = file_get_contents('invoice.pdf'); $result = $client->rename($pdfBytes); echo "Renamed to: {$result->suggestedFilename}\n";} catch (RateLimitException $e) { // Rate limited - wait and retry echo "Rate limited. Retry after {$e->getRetryAfter()} seconds\n"; sleep($e->getRetryAfter()); // Retry the request...} catch (InvalidFileException $e) { // File is not a valid PDF or is corrupted echo "Invalid file: {$e->getMessage()}\n";} catch (AuthenticationException $e) { // API key is invalid or expired echo "Authentication failed: {$e->getMessage()}\n";} catch (ApiException $e) { // Other API errors echo "API Error [{$e->getCode()}]: {$e->getMessage()}\n"; if ($e->getDetails()) { echo "Details: " . json_encode($e->getDetails()) . "\n"; }} catch (NetworkException $e) { // Network/connection errors echo "Network error: {$e->getMessage()}\n";} catch (\Exception $e) { // Other errors (file I/O, etc.) echo "Unexpected error: {$e->getMessage()}\n";}// Helper function with retry logicfunction renameWithRetry(Client $client, string $pdfBytes, int $maxRetries = 3): ?object{ $retries = 0; while (true) { try { return $client->rename($pdfBytes); } catch (RateLimitException $e) { $retries++; if ($retries > $maxRetries) { throw $e; } $sleepTime = $e->getRetryAfter() ?? (2 ** $retries); echo "Rate limited, retrying in {$sleepTime}s (attempt {$retries}/{$maxRetries})\n"; sleep($sleepTime); } catch (ApiException $e) { $retries++; if ($retries > $maxRetries || !$e->isRetryable()) { throw $e; } $sleepTime = 2 ** $retries; echo "API error, retrying in {$sleepTime}s (attempt {$retries}/{$maxRetries})\n"; sleep($sleepTime); } }}Full documentation on GitHub
For more examples, advanced usage patterns, and detailed API documentation, see the full PHP SDK README on GitHub.
Read the PHP SDK docsFrequently asked questions
- What PHP versions are supported?
- The PHP SDK supports PHP 8.0 and above. It uses modern PHP features including named arguments and constructor property promotion.
- What HTTP client does it use?
- The SDK uses PSR-18 HTTP client interface, so it works with any compatible client like Guzzle, Symfony HTTP Client, or HTTPlug.
- Does it work with Laravel?
- Yes, the SDK works with Laravel and any PHP framework. We recommend using the configuration facade or service container for initialization.
- Can I use streams instead of loading files into memory?
- Yes, the SDK accepts both strings and stream resources. Use streams for large files to reduce memory usage.
- How do I handle async processing?
- For async processing in PHP, use queue systems like Laravel Queues, Symfony Messenger, or any job queue. The SDK provides polling helpers for long-running operations.