Search by

Official PHP SDK for the Twill Docs document generation API.

v0.1.0 2026-07-22 11:53 UTC

This package is auto-updated.

Last update: 2026-09-22 12:47:40 UTC


README

The official PHP SDK for Twill Docs, the document infrastructure API. Turn structured data into production-ready PDFs — invoices, receipts, payslips, and more.

  • Zero dependencies — needs only ext-curl and ext-json.
  • Typed errors — catch RateLimitException, ValidationException, and friends.
  • PSR-4, PHP 8.1+.

Install

composer require twilldocs/sdk

Quickstart

<?php
require 'vendor/autoload.php';

use TwillDocs\Client;

$twill = new Client('twdc_...');

// Create an invoice, wait for it to render, then download the PDF.
$doc = $twill->documents->generate('invoice', [
    'invoice_number' => 'INV-1001',
    'issue_date' => '2026-07-22',
    'due_date' => '2026-08-21',
    'currency' => 'USD',
    'seller' => ['name' => 'Northwind Studio', 'address' => '500 Market St', 'tax_id' => 'US123456789'],
    'buyer' => ['name' => 'Acme Corp', 'address' => '1 Infinite Loop'],
    'line_items' => [
        ['description' => 'Consulting', 'quantity' => 3, 'unit_price' => 1200],
        ['description' => 'Travel expenses', 'quantity' => 1, 'unit_price' => 340],
    ],
    'tax_rate' => 0.085,
]);

$pdf = $twill->documents->download($doc['id']);
file_put_contents("invoice-{$doc['id']}.pdf", $pdf);

You supply line items and the tax rate; Twill computes the totals and renders the document.

Configuration

$twill = new Client(
    apiKey: 'twdc_...',                    // required
    baseUrl: 'https://api.twilldocs.com',  // default; use http://localhost:8080 for local dev
    timeout: 30,                           // per-request timeout in seconds
);

Documents

$doc = $twill->documents->create('invoice', [...]); // returns immediately, status "pending"
$twill->documents->retrieve($doc['id']);            // check status
$twill->documents->waitUntilReady($doc['id']);      // poll until succeeded / failed
$pdf = $twill->documents->download($doc['id']);      // string (bytes)
$twill->documents->generate('invoice', [...]);      // create + wait, in one call

Every create/generate sends an idempotency key automatically (override with the $idempotencyKey argument), so a retried request never produces a duplicate.

Templates

Pass a template name (or a TwillDocs\Template constant) as the first argument:

use TwillDocs\Template;

$twill->documents->generate(Template::RECEIPT, [...]);

Available: invoice, quote, receipt, purchase_order, delivery_note, payslip, offer_letter, nda, service_agreement. Each template's input shape is documented at twilldocs.com/docs.

API keys

$keys = $twill->apiKeys->list();
$twill->apiKeys->revoke($keys[0]['id']);

Brand

$twill->brand->retrieve();
$twill->brand->update(theme: 'modern');
$twill->brand->update(logo: [
    'filename' => 'logo.png',
    'contents' => file_get_contents('logo.png'),
    'contentType' => 'image/png',
]);
$twill->brand->deleteLogo();

Errors

Every failure throws a subclass of TwillDocs\Exceptions\TwillException:

use TwillDocs\Exceptions\ValidationException;
use TwillDocs\Exceptions\RateLimitException;
use TwillDocs\Exceptions\TwillException;

try {
    $twill->documents->generate('invoice', $data);
} catch (ValidationException $e) {
    print_r($e->errors);          // per-field messages
} catch (RateLimitException $e) {
    sleep($e->retryAfter ?? 1);
} catch (TwillException $e) {
    echo "{$e->status} {$e->type} {$e->getMessage()}";
}
Class When
ValidationException 400 / 422 (->errors)
AuthenticationException 401
PermissionException 403
NotFoundException 404
ConflictException 409
RateLimitException 429 (->retryAfter)
ServerException 5xx
ConnectionException network failure before a response
TimeoutException request exceeded timeout

Health

$twill->health(); // ['status' => 'ok' | 'degraded', 'checks' => [...]]

License

MIT