Official SDK
C# / .NET
.NET 6+ with async/await patterns. Designed for ASP.NET Core with built-in dependency injection support and proper error handling.
Rename PDFs, split multi-page documents, and extract structured data using the official C# SDK for Renamed.to.
- 1Install Renamed.Sdk via dotnet add package or NuGet Package Manager
- 2Call RenameAsync(), PdfSplitAsync(), or ExtractAsync() with byte arrays
- 3Use dependency injection in ASP.NET Core with CancellationToken support
On this page
Installation
dotnet add package Renamed.SdkQuickstart
Initialize the client and start making API calls.
using Renamed;// Initialize the clientvar client = new RenamedClient( apiKey: Environment.GetEnvironmentVariable("RENAMED_API_KEY"));// Rename a PDFvar pdfBytes = await File.ReadAllBytesAsync("invoice.pdf");var result = await client.RenameAsync(pdfBytes);Console.WriteLine(result.SuggestedFilename);// -> "2024-01-15_AcmeCorp_INV-1234.pdf"// Split a multi-page PDFvar docBytes = await File.ReadAllBytesAsync("documents.pdf");var job = await client.PdfSplitAsync(docBytes, new SplitOptions{ Mode = "smart"});Console.WriteLine(job.Documents);// Extract structured datavar receiptBytes = await File.ReadAllBytesAsync("receipt.pdf");var data = await client.ExtractAsync(receiptBytes);Console.WriteLine(data);Rename a PDF
Pass a byte array to get an AI-generated filename. Use custom instructions to control the naming format.
using Renamed;using Renamed.Models;// Initialize the clientvar client = new RenamedClient( apiKey: Environment.GetEnvironmentVariable("RENAMED_API_KEY"));// Read the PDF filevar pdfBytes = await File.ReadAllBytesAsync("./documents/invoice.pdf");// Rename the PDFvar result = await client.RenameAsync(pdfBytes);Console.WriteLine($"Suggested filename: {result.SuggestedFilename}");Console.WriteLine($"Confidence: {result.Confidence}");// Output:// Suggested filename: 2024-01-15_AcmeCorp_INV-1234.pdf// Confidence: 0.95// Access extracted metadataConsole.WriteLine($"Vendor: {result.Metadata["vendor"]}");Console.WriteLine($"Date: {result.Metadata["date"]}");Console.WriteLine($"Type: {result.Metadata["type"]}");// Use custom naming instructionsvar customResult = await client.RenameAsync(pdfBytes, new RenameOptions{ Instructions = "Format: YYYY-MM-DD_VendorName_Amount"});Console.WriteLine(customResult.SuggestedFilename);// -> "2024-01-15_AcmeCorp_$1250.pdf"// With cancellation token supportusing var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));var timedResult = await client.RenameAsync(pdfBytes, cancellationToken: cts.Token);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.
using Renamed;using Renamed.Models;var client = new RenamedClient( apiKey: Environment.GetEnvironmentVariable("RENAMED_API_KEY"));// Read a multi-page PDFvar pdfBytes = await File.ReadAllBytesAsync("./documents/combined.pdf");// Submit the split job with smart mode (AI detects document boundaries)var job = await client.PdfSplitAsync(pdfBytes, new SplitOptions{ Mode = "smart"});Console.WriteLine($"Job ID: {job.JobId}");Console.WriteLine($"Status: {job.State}");// Option 1: Wait for completion (built-in polling)var completed = await job.WaitForCompletionAsync();// Option 2: Manual polling for progress updates// while (job.State == "processing")// {// Console.WriteLine($"Progress: {job.Progress}%");// await Task.Delay(1000);// job = await client.GetJobAsync(job.JobId);// }// Process the split documentsConsole.WriteLine($"Split into {completed.Documents.Count} documents:");for (int i = 0; i < completed.Documents.Count; i++){ var doc = completed.Documents[i]; Console.WriteLine($" [{i + 1}] {doc.Filename} (pages {string.Join(", ", doc.Pages)})"); // Output: // [1] invoice_1.pdf (pages 1, 2) // [2] invoice_2.pdf (pages 3, 4) // Download each split document var docBytes = await client.DownloadFileAsync(doc.DownloadUrl); // Save to output directory var outputPath = Path.Combine("./output", doc.Filename); Directory.CreateDirectory(Path.GetDirectoryName(outputPath)!); await File.WriteAllBytesAsync(outputPath, docBytes);}Extract Data
Extract structured data from invoices, receipts, and other documents. Use C# records for type-safe extraction.
using System.Text.Json;using Renamed;using Renamed.Models;// Define typed records for invoice extractionpublic record LineItem(string Description, int Quantity, decimal UnitPrice);public record Invoice( string InvoiceNumber, string Vendor, string Date, List<LineItem> LineItems, decimal Subtotal, decimal Tax, decimal Total);// Initialize the clientvar client = new RenamedClient( apiKey: Environment.GetEnvironmentVariable("RENAMED_API_KEY"));// Read the PDF filevar pdfBytes = await File.ReadAllBytesAsync("./documents/invoice.pdf");// Basic extraction (returns Dictionary<string, object>)var data = await client.ExtractAsync(pdfBytes);Console.WriteLine($"Vendor: {data["vendor"]}");Console.WriteLine($"Date: {data["date"]}");Console.WriteLine($"Total: {data["total"]}");// Output:// Vendor: Acme Corp// Date: 2024-01-15// Total: 1250.00// Typed extraction: deserialize to a recordvar jsonString = JsonSerializer.Serialize(data);var invoice = JsonSerializer.Deserialize<Invoice>(jsonString, new JsonSerializerOptions{ PropertyNameCaseInsensitive = true});// Now you have fully typed accessConsole.WriteLine($"Invoice #{invoice!.InvoiceNumber} from {invoice.Vendor}");Console.WriteLine($"Line items: {invoice.LineItems.Count}");foreach (var item in invoice.LineItems){ Console.WriteLine($" - {item.Description}: {item.Quantity} x {item.UnitPrice:C}");}Console.WriteLine($"Total: {invoice.Total:C}");// 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.
ASP.NET Core Minimal API
Handle PDF uploads with ASP.NET Core minimal APIs for a lightweight, modern approach.
using Renamed;using Renamed.Models;using Renamed.Exceptions;var builder = WebApplication.CreateBuilder(args);// Register the Renamed client with DIbuilder.Services.AddRenamedClient(options =>{ options.ApiKey = builder.Configuration["Renamed:ApiKey"]!; options.Timeout = TimeSpan.FromSeconds(30); options.MaxRetries = 3;});var app = builder.Build();// Rename endpointapp.MapPost("/api/rename", async ( IFormFile file, IRenamedClient client, CancellationToken ct) =>{ if (file.Length == 0) return Results.BadRequest(new { error = "No file provided" }); if (file.ContentType != "application/pdf") return Results.BadRequest(new { error = "Only PDF files are supported" }); try { using var stream = new MemoryStream(); await file.CopyToAsync(stream, ct); var result = await client.RenameAsync(stream.ToArray(), cancellationToken: ct); return Results.Ok(new { suggestedFilename = result.SuggestedFilename, confidence = result.Confidence, metadata = result.Metadata }); } catch (RenamedApiException e) { return Results.Problem(e.Message, statusCode: 502); }});// Split endpointapp.MapPost("/api/split", async ( IFormFile file, string? mode, IRenamedClient client, CancellationToken ct) =>{ if (file.Length == 0) return Results.BadRequest(new { error = "No file provided" }); try { using var stream = new MemoryStream(); await file.CopyToAsync(stream, ct); var job = await client.PdfSplitAsync(stream.ToArray(), new SplitOptions { Mode = mode ?? "smart" }, ct); var completed = await job.WaitForCompletionAsync(ct); return Results.Ok(new { jobId = completed.JobId, documents = completed.Documents.Select(d => new { filename = d.Filename, pages = d.Pages, downloadUrl = d.DownloadUrl }) }); } catch (RenamedApiException e) { return Results.Problem(e.Message, statusCode: 502); }});// Extract endpointapp.MapPost("/api/extract", async ( IFormFile file, IRenamedClient client, CancellationToken ct) =>{ if (file.Length == 0) return Results.BadRequest(new { error = "No file provided" }); try { using var stream = new MemoryStream(); await file.CopyToAsync(stream, ct); var data = await client.ExtractAsync(stream.ToArray(), cancellationToken: ct); return Results.Ok(data); } catch (RenamedApiException e) { return Results.Problem(e.Message, statusCode: 502); }});app.Run();ASP.NET Core Controller
Use traditional MVC controllers with dependency injection and proper validation.
using Microsoft.AspNetCore.Mvc;using Renamed;using Renamed.Models;using Renamed.Exceptions;namespace MyApp.Controllers;[ApiController][Route("api/[controller]")]public class DocumentsController : ControllerBase{ private readonly IRenamedClient _client; private readonly ILogger<DocumentsController> _logger; public DocumentsController(IRenamedClient client, ILogger<DocumentsController> logger) { _client = client; _logger = logger; } [HttpPost("rename")] [RequestSizeLimit(10 * 1024 * 1024)] // 10MB limit public async Task<IActionResult> Rename( IFormFile file, [FromQuery] string? instructions, CancellationToken ct) { if (file.Length == 0) return BadRequest(new { error = "No file provided" }); if (file.ContentType != "application/pdf") return BadRequest(new { error = "Only PDF files are supported" }); try { using var stream = new MemoryStream(); await file.CopyToAsync(stream, ct); var options = instructions != null ? new RenameOptions { Instructions = instructions } : null; var result = await _client.RenameAsync(stream.ToArray(), options, ct); _logger.LogInformation( "Renamed {OriginalName} to {SuggestedName} with confidence {Confidence}", file.FileName, result.SuggestedFilename, result.Confidence); return Ok(new { suggestedFilename = result.SuggestedFilename, confidence = result.Confidence, metadata = result.Metadata }); } catch (RateLimitException e) { _logger.LogWarning("Rate limited, retry after {RetryAfter}s", e.RetryAfter); Response.Headers.Append("Retry-After", e.RetryAfter.ToString()); return StatusCode(429, new { error = "Rate limited", retryAfter = e.RetryAfter }); } catch (RenamedApiException e) { _logger.LogError(e, "API error during rename: {Code}", e.Code); return StatusCode(502, new { error = e.Message, code = e.Code }); } } [HttpPost("split")] [RequestSizeLimit(50 * 1024 * 1024)] // 50MB limit for multi-page PDFs public async Task<IActionResult> Split( IFormFile file, [FromQuery] string mode = "smart", CancellationToken ct = default) { if (file.Length == 0) return BadRequest(new { error = "No file provided" }); try { using var stream = new MemoryStream(); await file.CopyToAsync(stream, ct); var job = await _client.PdfSplitAsync(stream.ToArray(), new SplitOptions { Mode = mode }, ct); var completed = await job.WaitForCompletionAsync(ct); return Ok(new { jobId = completed.JobId, documents = completed.Documents.Select(d => new { filename = d.Filename, pages = d.Pages, downloadUrl = d.DownloadUrl }) }); } catch (RenamedApiException e) { _logger.LogError(e, "API error during split: {Code}", e.Code); return StatusCode(502, new { error = e.Message }); } } [HttpPost("extract")] public async Task<IActionResult> Extract(IFormFile file, CancellationToken ct) { if (file.Length == 0) return BadRequest(new { error = "No file provided" }); try { using var stream = new MemoryStream(); await file.CopyToAsync(stream, ct); var data = await _client.ExtractAsync(stream.ToArray(), cancellationToken: ct); return Ok(data); } catch (RenamedApiException e) { return StatusCode(502, new { error = e.Message }); } }}Dependency Injection Configuration
Configure the Renamed client as a service with options from configuration.
using Renamed;var builder = WebApplication.CreateBuilder(args);// Option 1: Use AddRenamedClient extension methodbuilder.Services.AddRenamedClient(options =>{ options.ApiKey = builder.Configuration["Renamed:ApiKey"]!; options.Timeout = TimeSpan.FromSeconds(30); options.MaxRetries = 3;});// Option 2: Register manually with custom HttpClientbuilder.Services.AddHttpClient<IRenamedClient, RenamedClient>(client =>{ client.Timeout = TimeSpan.FromMinutes(5);}).ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler{ AutomaticDecompression = System.Net.DecompressionMethods.All});builder.Services.Configure<RenamedClientOptions>( builder.Configuration.GetSection("Renamed"));// Option 3: Use IOptions pattern for configurationbuilder.Services.AddSingleton<IRenamedClient>(sp =>{ var options = sp.GetRequiredService<IOptions<RenamedClientOptions>>().Value; var httpClient = sp.GetRequiredService<IHttpClientFactory>().CreateClient("Renamed"); return new RenamedClient(options, httpClient);});var app = builder.Build();// appsettings.json:// {// "Renamed": {// "ApiKey": "your-api-key",// "Timeout": 30,// "MaxRetries": 3// }// }Error Handling
The SDK throws typed exceptions that you can catch and handle appropriately. All async methods support CancellationToken.
using Renamed;using Renamed.Exceptions;var client = new RenamedClient( apiKey: Environment.GetEnvironmentVariable("RENAMED_API_KEY"));try{ var pdfBytes = await File.ReadAllBytesAsync("invoice.pdf"); var result = await client.RenameAsync(pdfBytes); Console.WriteLine($"Renamed to: {result.SuggestedFilename}");}catch (RateLimitException e){ // Rate limited - wait and retry Console.WriteLine($"Rate limited. Retry after {e.RetryAfter} seconds"); await Task.Delay(TimeSpan.FromSeconds(e.RetryAfter)); // Retry the request...}catch (InvalidFileException e){ // File is not a valid PDF or is corrupted Console.WriteLine($"Invalid file: {e.Message}");}catch (AuthenticationException e){ // API key is invalid or expired Console.WriteLine($"Authentication failed: {e.Message}");}catch (RenamedApiException e){ // Other API errors Console.WriteLine($"API Error [{e.Code}]: {e.Message}"); if (e.Details != null) { Console.WriteLine($"Details: {e.Details}"); }}catch (OperationCanceledException){ // Request was cancelled Console.WriteLine("Request was cancelled");}catch (HttpRequestException e){ // Network errors Console.WriteLine($"Network error: {e.Message}");}// Using CancellationToken for timeoutusing var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));try{ var pdfBytes = await File.ReadAllBytesAsync("large-document.pdf"); var result = await client.RenameAsync(pdfBytes, cancellationToken: cts.Token);}catch (OperationCanceledException) when (cts.IsCancellationRequested){ Console.WriteLine("Request timed out after 30 seconds");}Full documentation on GitHub
For more examples, advanced usage patterns, and detailed API documentation, see the full C# / .NET SDK README on GitHub.
Read the C# / .NET SDK docsFrequently asked questions
- What .NET versions are supported?
- The C# SDK supports .NET 6 and above, including .NET 7, .NET 8, and future versions. It also works with .NET Standard 2.1 compatible frameworks.
- Does it support dependency injection?
- Yes, the SDK provides extension methods for IServiceCollection to easily register the client in ASP.NET Core applications.
- How do I handle cancellation?
- All async methods accept a CancellationToken parameter. Pass your token to support graceful cancellation of API calls.
- Is the client thread-safe?
- Yes, the RenamedClient is thread-safe and designed to be used as a singleton. Register it with AddSingleton or use the AddRenamedClient extension.
- How do I configure retries?
- Set the MaxRetries option when configuring the client. The SDK uses exponential backoff for transient errors automatically.