.NET SDK
Paperwright.Sdk is the first-party .NET client for the Paperwright render API.
It wraps the HTTP calls, the X-Api-Key header, and error handling so a render
stays one line in your code.
Paperwright.Sdk 0.2.0 is published. Every API and signature on this page is
taken from the shipped package.
Install
dotnet add package Paperwright.Sdk
Authenticate
The SDK uses the machine lane: a workspace API key sent as X-Api-Key. Create
one at /api-keys in the app. Keep it server-side — never ship it in a browser or
mobile app.
The default base URL is https://api.paperwright.dev, so you only pass a base URL
when pointing at a local API.
Render a stored template
The common case: you designed a template in the app, and now you feed it data.
using Paperwright.Sdk;
var client = new PaperwrightClient(apiKey);
byte[] pdf = await client.RenderTemplateAsync(
templateId, // Guid
new { customerName = "Acme", total = 1240.50 });
await File.WriteAllBytesAsync("invoice.pdf", pdf);
RenderTemplateAsync(Guid templateId, object? data, CancellationToken ct = default)
returns the PDF as a byte[]. The object you pass as data is serialised and
matched against your template's schema fields.
Render inline content
For one-off or dynamically composed documents, skip the stored template and pass the designer's JSON document directly:
byte[] pdf = await client.RenderInlineAsync(templateContent, new { name = "World" });
Render in a tenant's brand colours
If your product serves several tenants, render one template in each tenant's
colours by passing a PaperwrightTheme. Each colour is #rgb or #rrggbb; leave
one null to keep the template's own. A template that doesn't use brand colours
ignores the theme. See Rendering → Brand colours
for the rules.
var theme = new PaperwrightTheme(Primary: "#E11D48", Accent: "#0EA5E9");
byte[] pdf = await client.RenderTemplateAsync(templateId, data, theme);
// or, for inline content:
byte[] inline = await client.RenderInlineAsync(templateContent, data, theme);
The overloads are RenderTemplateAsync(Guid templateId, object? data, PaperwrightTheme? theme, CancellationToken ct = default)
and RenderInlineAsync(string content, object? data, PaperwrightTheme? theme, CancellationToken ct = default).
The overloads without a theme are unchanged. A malformed colour or an unknown key
comes back as a PaperwrightException with status 400.
Use it with dependency injection
In a long-running app, register the client so it rides a pooled,
factory-managed HttpClient instead of constructing its own:
// Program.cs
builder.Services.AddPaperwright(o =>
{
o.ApiKey = builder.Configuration["Paperwright:ApiKey"]!;
// o.BaseUrl = "http://localhost:5110"; // optional; defaults to production
});
Then inject it wherever you need it:
public class InvoiceService(PaperwrightClient paperwright)
{
public Task<byte[]> GenerateAsync(Invoice invoice, CancellationToken ct) =>
paperwright.RenderTemplateAsync(
invoice.TemplateId,
new { invoiceNumber = invoice.Number, total = invoice.Total },
ct);
}
AddPaperwright throws at startup if ApiKey is unset, so a misconfigured
deployment fails fast rather than at the first render.
Error handling
Failed renders throw PaperwrightException:
try
{
var pdf = await client.RenderTemplateAsync(templateId, data, ct);
}
catch (PaperwrightException ex)
{
logger.LogError("Render failed: {Message}", ex.Message);
}
See the API reference overview for what each
status code means — in particular 402 (quota exceeded) and 409 (a concurrent
edit changed the template).
Not using .NET?
The API is plain HTTPS and the OpenAPI document is public, so any language works.
- curl
- TypeScript
- Python
- Java / Go / PHP / Ruby
curl -X POST https://api.paperwright.dev/api/templates/<TEMPLATE_ID>/render \
-H "X-Api-Key: <YOUR_KEY>" \
-H "Content-Type: application/json" \
-d '{ "data": { "customerName": "Acme", "total": 1240.50 } }' \
--output invoice.pdf
npx @hey-api/openapi-ts \
-i https://api.paperwright.dev/openapi/v1.json -o ./paperwright-client
pip install openapi-python-client
openapi-python-client generate --url https://api.paperwright.dev/openapi/v1.json
npx @openapitools/openapi-generator-cli generate \
-i https://api.paperwright.dev/openapi/v1.json -g <language> -o ./client
Set the generated client's base URL to https://api.paperwright.dev and send
X-Api-Key on every request.
Token grammar
Tokens in template content resolve at render time. The full grammar lives in API Reference → Rendering; the common forms are:
| Token | Resolves to |
|---|---|
{{field}} | Value from data.field |
{{field | number:"#,##0.00"}} | Formatted number (pattern or preset) |
{{field | date:"medium"}} | Formatted date (preset) |
{{field | date:"dd/MM/yyyy"}} | Formatted date (custom format string) |
{{$today | date:"long"}} | Server date at render time |
{{$now | datetime:"24h"}} | Server datetime at render time |
{{$page}} / {{$pages}} | Page number / total pages |
Feedback
Found a rough edge in the SDK? Come tell us in Discord.