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.