Skip to content

Dart SDK

Official Dart SDK for thelawin.dev.

Requires Dart 3.0+ / Flutter 3.10+

Installation

Beta-Phase

Während der Beta sind die SDKs über GitHub verfügbar. pub.dev-Veröffentlichung folgt mit dem stabilen Release.

In deiner pubspec.yaml:

yaml
dependencies:
  thelawin:
    git:
      url: https://github.com/steviee/thelawin-clients.git
      path: dart

Dann:

bash
dart pub get
# oder für Flutter
flutter pub get

Quick Start

dart
import 'package:thelawin/thelawin.dart';

final client = ThelawinClient(apiKey: 'env_sandbox_xxx');

final result = await client.invoice()
    .number('2026-001')
    .date('2026-01-15')
    .seller(name: 'Acme GmbH', vatId: 'DE123456789', city: 'Berlin', country: 'DE')
    .buyer(name: 'Customer AG', city: 'München', country: 'DE')
    .addItem(description: 'Consulting Services', quantity: 8, unit: 'HUR', unitPrice: 150, vatRate: 19)
    .template('minimal')
    .generate();

if (result.isSuccess) {
  await result.savePdf('./invoice.pdf');
  print('Generated: ${result.filename}');
} else {
  for (final error in result.errors) {
    print('${error.path}: ${error.message}');
  }
}

Client Options

dart
final client = ThelawinClient(
  apiKey: 'env_sandbox_xxx',
  baseUrl: 'https://api.thelawin.dev',  // optional
  timeout: Duration(seconds: 30),       // optional
);

Builder API

Invoice Details

dart
client.invoice()
    .number('2026-001')           // Required
    .date('2026-01-15')           // Required
    .dueDate('2026-02-15')        // Optional
    .currency('EUR')              // Default: 'EUR'

Parties

dart
.seller(
  name: 'Acme GmbH',            // Required
  vatId: 'DE123456789',         // Required
  street: 'Hauptstraße 1',
  city: 'Berlin',               // Required
  postalCode: '10115',
  country: 'DE',                // Required
)
.buyer(
  name: 'Customer AG',          // Required
  vatId: 'DE987654321',
  city: 'München',              // Required
  country: 'DE',                // Required
)

Line Items

dart
.addItem(
  description: 'Consulting',    // Required
  quantity: 8,                  // Required
  unit: 'HUR',                  // Required
  unitPrice: 150.00,            // Required
  vatRate: 19.0,                // Required
)

Customization

dart
.template('minimal')            // 'minimal', 'classic', 'compact'
.locale('de')                   // 'en', 'de', 'fr', 'es', 'it'
.accentColor('#8b5cf6')
.footerText('Thank you!')
dart
// From file (auto Base64)
.logoFile('./logo.png')
.logoFile('./logo.png', widthMm: 30)

// From bytes
.logoBytes(imageBytes, widthMm: 30)

// From Base64
.logoBase64('iVBORw0KGgo...', widthMm: 30)

Result Handling

dart
final result = await builder.generate();

if (result.isSuccess) {
  print(result.filename);       // 'invoice-2026-001.pdf'
  print(result.validation);     // ValidationResult(status: valid, ...)

  // Save to file
  await result.savePdf('./invoice.pdf');

  // Get bytes
  final bytes = result.toBytes();

  // Get data URL
  final dataUrl = result.toDataUrl();
} else {
  for (final error in result.errors) {
    print('${error.path}: ${error.message}');
  }
}

Pattern Matching (Dart 3.0+)

dart
switch (result) {
  case InvoiceSuccess(:final filename, :final validation):
    print('Generated: $filename');
    print('Validation: ${validation.status}');
  case InvoiceFailure(:final errors):
    for (final error in errors) {
      print('${error.path}: ${error.message}');
    }
}

Error Handling

dart
try {
  final result = await client.invoice().generate();
} on ThelawinQuotaExceededException {
  print('Quota exceeded, upgrade your plan');
} on ThelawinNetworkException catch (e) {
  print('Network error: ${e.message}');
} on ThelawinApiException catch (e) {
  print('API error ${e.statusCode}: ${e.message}');
}

Flutter Example

dart
import 'package:flutter/material.dart';
import 'package:thelawin/thelawin.dart';
import 'package:printing/printing.dart';

class InvoiceScreen extends StatefulWidget {
  @override
  _InvoiceScreenState createState() => _InvoiceScreenState();
}

class _InvoiceScreenState extends State<InvoiceScreen> {
  final client = ThelawinClient(apiKey: 'env_sandbox_xxx');
  Uint8List? pdfBytes;
  bool isLoading = false;

  Future<void> generateInvoice() async {
    setState(() => isLoading = true);

    final result = await client.invoice()
        .number('2026-001')
        .seller(name: 'Acme GmbH', vatId: 'DE123456789', city: 'Berlin', country: 'DE')
        .buyer(name: 'Customer AG', city: 'München', country: 'DE')
        .addItem(description: 'Consulting', quantity: 8, unit: 'HUR', unitPrice: 150, vatRate: 19)
        .generate();

    setState(() {
      isLoading = false;
      if (result.isSuccess) {
        pdfBytes = result.toBytes();
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Invoice Generator')),
      body: Column(
        children: [
          if (pdfBytes != null)
            Expanded(child: PdfPreview(build: (format) => pdfBytes!)),
          ElevatedButton(
            onPressed: isLoading ? null : generateInvoice,
            child: Text(isLoading ? 'Generating...' : 'Generate Invoice'),
          ),
        ],
      ),
    );
  }
}

Source Code

github.com/steviee/thelawin-clients/tree/main/dart

ZUGFeRD 2.3 & Factur-X 1.0 compliant