xingen

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 14, 2026 License: MIT Imports: 18 Imported by: 0

README

xingen-go-sdk

Go client SDK for the Xingen e-invoice validation API — submit UBL, CII, ZUGFeRD, and SAP IDoc/OData invoices for validation against EN16931, XRechnung, and Peppol.

Requires Go 1.23+ (for iter.Seq2-based pagination — see List and retrieve invoices). Zero third-party dependencies — built entirely on the standard library (net/http, mime/multipart, encoding/json).

Status: v1, covering invoice submission/validation and API key management. Contacts and dashboard/user endpoints are not exposed (they're Firebase-auth-only on the backend).

Install

go get github.com/nko-technologies/xingen-go-sdk
import "github.com/nko-technologies/xingen-go-sdk"

Authentication

Every request needs an API key (xgn_live_... for production, xgn_test_... for sandbox — sandbox requests never count toward quota). Create one from the Xingen dashboard or via client.APIKeys.

client, err := xingen.New(os.Getenv("XINGEN_API_KEY"))
if err != nil {
    log.Fatal(err)
}

Client holds one connection-pooled *http.Client — construct it once and reuse it, don't rebuild it per request. xingen.WithBaseURL(...) overrides the default https://app.xingen.de/api, useful for self-hosted or local (./gradlew bootRun, port 10001) testing.

Every method takes a context.Context as its first argument — use it for request cancellation and deadlines the way you would with any other Go client. xingen.WithRequestTimeout sets a per-request fallback timeout (30s by default) that applies on top of whatever your context does.

Validate a file

Every validate/submit endpoint is asynchronous — the backend queues the invoice and returns immediately. Use a *AndWait helper to submit and poll for the result in one call:

record, err := client.Invoices.ValidateFileAndWait(ctx, "invoice.xml", xingen.ProfileXRechnung, xingen.DefaultPollOptions())
if err != nil {
    log.Fatal(err)
}

if record.Status == xingen.StatusValidated && record.ValidationResult.Valid {
    fmt.Println("Valid!")
} else {
    for _, e := range record.ValidationResult.Errors {
        fmt.Printf("%s: %s (%s)\n", *e.Severity, *e.Message, *e.Field)
    }
}

PollOptions controls the backoff (InitialInterval, MaxInterval, BackoffMultiplier) and the overall Timeout. Cancel the poll early by cancelling the context.Context you pass in — there's no separate cancellation-check option like some other language SDKs use, since context.Context is already Go's standard mechanism for this. A failed validation is not an error — it's a completed API call that found the invoice invalid, so *AndWait returns normally with record.ValidationResult.Valid == false. Only a transport failure, context cancellation, or a PollOptions.Timeout elapsing returns an error (*xingen.PollCancelledError / *xingen.PollTimeoutError, the latter carrying PartialResult with the last known state).

opts := xingen.PollOptions{
    InitialInterval:   300 * time.Millisecond,
    MaxInterval:       3 * time.Second,
    BackoffMultiplier: 1.5,
    Timeout:           30 * time.Second,
}

If you'd rather manage polling yourself, use the low-level pair:

submitted, err := client.Invoices.ValidateFile(ctx, "invoice.xml", xingen.ProfileEN16931)
// ... later ...
record, err := client.Invoices.Get(ctx, submitted.ID)

ValidateIdoc / ValidateIdocAndWait work the same way for SAP IDoc XML files. Every ValidateX method also has a ValidateXBytes counterpart if you already hold the file bytes in memory instead of a path.

Submit a structured invoice (JSON)

submission := xingen.InvoiceSubmission{
    InvoiceNumber:     "INV-2024-0042",
    IssueDate:         xingen.NewDate(time.Date(2024, 3, 15, 0, 0, 0, 0, time.UTC)),
    Currency:          "EUR",
    BuyerReference:    "991-12345-06",
    ValidationProfile: xingen.ProfileXRechnung,
    Supplier: xingen.InvoiceSubmissionPartyInput{
        Name: "Acme GmbH", VatID: "DE123456789",
        Address: &xingen.InvoiceSubmissionAddressInput{City: "Berlin", CountryCode: "DE"},
    },
    Buyer: xingen.InvoiceSubmissionPartyInput{
        Name: "Buyer Co", LeitwegID: "991-12345-06",
        Address: &xingen.InvoiceSubmissionAddressInput{CountryCode: "DE"},
    },
    Lines: []xingen.InvoiceSubmissionLineInput{
        {Description: "Software License Q1", Quantity: "5", Unit: "C62", Price: "199.00", TaxRate: "19"},
    },
    PaymentMeans: []xingen.InvoiceSubmissionPaymentMeansInput{
        {TypeCode: "58", CreditTransferAccountID: "DE89370400440532013000"},
    },
}

record, err := client.Invoices.SubmitAndWait(ctx, submission, xingen.DefaultPollOptions())

Quantity/Price/TaxRate are xingen.Number — a type alias for encoding/json.Number (itself just a string), so you can pass any string-shaped numeric literal without losing precision. See Design notes for why.

InvoiceSubmission has full parity with the backend's domain model — every invoice type it can validate, it can also submit, including non-standard VAT categories (exempt/reverse-charge/export via InvoiceSubmissionLineInput.TaxCategoryCode + ExemptionReason/ExemptionReasonCode), Payee/TaxRepresentative, Delivery, InvoicePeriod, PrecedingInvoiceReferences (for credit notes), and the full BT-11..BT-19 document reference fields. See the nested types alongside InvoiceSubmission for the complete set.

SAP S/4HANA OData supplier-invoice payloads are supported as a thin passthrough — pass raw JSON bytes or a map[string]any rather than a fully typed model:

client.Invoices.SubmitOData(ctx, rawODataJSON, xingen.ProfileEN16931)

Extract an invoice from a PDF (AI)

Upload a plain invoice PDF — including scanned/image-based PDFs — and let the backend extract structured fields with Claude. Works exactly like the other submit endpoints: async, so use ExtractInvoiceAndWait or the low-level ExtractInvoice/Get pair.

record, err := client.Invoices.ExtractInvoiceAndWait(ctx, "scanned-invoice.pdf",
    xingen.ProfileEN16931,
    xingen.TierFast, // or xingen.TierAccurate — higher accuracy, Pro subscription required
    xingen.DefaultPollOptions())

If the extraction missed a field or validation flagged something, correct it with a JSON merge-patch (RFC 7386) and re-validate synchronously — only invoices that finished processing (StatusValidated or StatusFailedValidation) can be corrected. Array fields (lines, paymentMeans, allowanceCharges, taxBreakdowns) are replaced wholesale when present in the patch:

corrected, err := client.Invoices.PatchInvoiceMap(ctx, record.ID, map[string]any{
    "currency":       "EUR",
    "buyerReference": "991-12345-06",
})

To find out which fields the backend fills in automatically per profile (so you know what not to prompt the user for):

autoFilled, err := client.Invoices.GetAutoFilledFields(ctx)

List and retrieve invoices

page, err := client.Invoices.List(ctx, 0, 20, "createdAt,desc")

// or, to walk every invoice without managing page indices yourself — ListAll returns an
// iter.Seq2[InvoiceRecord, error], so a plain range loop lazily fetches pages as needed:
for record, err := range client.Invoices.ListAll(ctx, 50) {
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(record.ID, "->", record.Status)
}

one, err := client.Invoices.Get(ctx, "inv_01HXYZ")

Download results

pdf, err := client.Invoices.DownloadPDF(ctx, id)       // ZUGFeRD PDF with embedded XML
idocXML, err := client.Invoices.DownloadIdocXML(ctx, id) // SAP IDoc XML

API keys

created, err := client.APIKeys.Create(ctx, xingen.CreateApiKeyRequest{Name: "Production CI"})
fmt.Println("Store this now, it's shown only once:", created.RawKey)

keys, err := client.APIKeys.List(ctx)
err = client.APIKeys.Revoke(ctx, created.ID)

Error handling

Every non-2xx response maps to a typed error, all of which embed *xingen.APIError (StatusCode / RawBody / ErrorResponseBody). Use errors.As to match the specific type you care about:

Error type Status Notes
*xingen.AuthenticationError 401 Missing or invalid API key
*xingen.PermissionError 403 Resource exists but isn't owned by the caller
*xingen.NotFoundError 404
*xingen.ValidationRequestError 400 FieldErrors has details for request-body validation failures
*xingen.QuotaExceededError 429 Monthly request quota exhausted
*xingen.APIError other 4xx/5xx Fallback
_, err := client.Invoices.Submit(ctx, submission)

var validationErr *xingen.ValidationRequestError
var quotaErr *xingen.QuotaExceededError
switch {
case errors.As(err, &validationErr):
    for field, message := range validationErr.FieldErrors {
        fmt.Println(field, ":", message)
    }
case errors.As(err, &quotaErr):
    fmt.Println("Quota exceeded — upgrade or wait for the next billing period")
case err != nil:
    fmt.Println("Request failed:", err)
}

A network-level failure (no HTTP response at all) surfaces as *xingen.TransportError, which wraps the underlying error via Unwrap()errors.Is(err, context.DeadlineExceeded) works as expected if your context's deadline is what caused it.

Design notes

  • No custom JSON parser needed for monetary precision, unlike this SDK's Python/TypeScript/PHP siblings. Go's encoding/json decodes a json.Number-typed struct field straight from the source-text numeric literal — no float64 intermediate — for free; xingen.Number is just an alias for it. Confirmed empirically against a 30-digit literal in wire_test.go.
  • context.Context instead of a cancellation callback. Every method takes ctx first, and the *AndWait polling helpers respect it directly instead of a separate cancellationCheck option (which the Java/Python/TypeScript/C#/PHP ports use, since none of those languages have a first-class cancellation primitive baked into every stdlib I/O call the way Go does).
  • iter.Seq2 instead of a hand-rolled iterator for ListAll (Go 1.23+'s range-over-func), the same idiom-over-literal-port adaptation the C# SDK made with IAsyncEnumerable.
  • No automatic retries. Retrying a Submit after a client-side timeout is unsafe without idempotency keys, which the API doesn't support yet — a retried submit could create a duplicate invoice. Handle retries at the call site if you need them.

Contributing

go build ./... && go vet ./... && go test ./... -race

Tests run against a real (loopback) net/http/httptest.Server, not a mocking framework — no network calls leave the machine.

License

MIT — see LICENSE.

Documentation

Overview

Package xingen is a client SDK for the Xingen (https://xingen.de) e-invoice validation API — submit UBL, CII, ZUGFeRD, and SAP IDoc/OData invoices for validation against EN16931, XRechnung, and Peppol.

Construct a Client with New, then use its Invoices and APIKeys fields to reach the resource-specific services. A single Client holds one connection-pooled *http.Client and should be reused across calls rather than rebuilt per request.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type APIError

type APIError struct {
	Message string
	// StatusCode is the HTTP status code of the response.
	StatusCode int
	// RawBody is the raw response body, always retained even if it couldn't be parsed as ErrorResponse.
	RawBody string
	// ErrorResponseBody is nil if the response body didn't match the expected shape (e.g. an
	// unexpected 5xx from a proxy in front of the backend).
	ErrorResponseBody *ErrorResponse
}

APIError is any HTTP response the SDK understands as an error (4xx/5xx). Every error type returned by this SDK for a non-2xx response embeds *APIError, so callers can always reach StatusCode/RawBody/ErrorResponse via the interface below regardless of the concrete error type.

func (*APIError) Error

func (e *APIError) Error() string

type APIKeysService

type APIKeysService struct {
	// contains filtered or unexported fields
}

APIKeysService creates, lists, and revokes API keys. Reachable via Client.APIKeys.

func (*APIKeysService) Create

Create makes a new API key. The RawKey on the result is shown only this once — persist it immediately.

func (*APIKeysService) List

func (s *APIKeysService) List(ctx context.Context) ([]ApiKey, error)

List returns every API key belonging to the caller.

func (*APIKeysService) Revoke

func (s *APIKeysService) Revoke(ctx context.Context, id string) error

Revoke permanently deactivates the API key with the given id.

type Address

type Address struct {
	StreetName           *string `json:"streetName"`
	AdditionalStreetName *string `json:"additionalStreetName"`
	AddressLine3         *string `json:"addressLine3"`
	City                 *string `json:"city"`
	PostalZone           *string `json:"postalZone"`
	CountrySubdivision   *string `json:"countrySubdivision"`
	CountryCode          *string `json:"countryCode"`
}

type AllowanceCharge

type AllowanceCharge struct {
	// Charge is true for a charge, false for an allowance.
	Charge          bool    `json:"charge"`
	Amount          *Number `json:"amount"`
	BaseAmount      *Number `json:"baseAmount"`
	Percentage      *Number `json:"percentage"`
	VatCategoryCode *string `json:"vatCategoryCode"`
	VatRate         *Number `json:"vatRate"`
	Reason          *string `json:"reason"`
	ReasonCode      *string `json:"reasonCode"`
}

AllowanceCharge is a document-level allowance/charge (BG-20/BG-21).

type ApiKey

type ApiKey struct {
	ID        string `json:"id"`
	Name      string `json:"name"`
	KeyPrefix string `json:"keyPrefix"`
	Sandbox   bool   `json:"sandbox"`
	Active    bool   `json:"active"`
	// QuotaLimit is nil for unlimited.
	QuotaLimit *int       `json:"quotaLimit"`
	QuotaUsed  int        `json:"quotaUsed"`
	LastUsedAt *time.Time `json:"lastUsedAt"`
	CreatedAt  time.Time  `json:"createdAt"`
	// RevokedAt is nil if the key is still active.
	RevokedAt *time.Time `json:"revokedAt"`
}

ApiKey is API key metadata as returned by List/Create — the raw key value is never included here.

type AuthenticationError

type AuthenticationError struct{ *APIError }

AuthenticationError is a 401 — missing or invalid API key. The backend returns no application-level body for this status.

type AutoFilledField added in v0.2.0

type AutoFilledField struct {
	// Field is the canonical Invoice field path, e.g. "typeCode" or "lines[].lineId".
	Field string `json:"field"`
	// Value is the value that will be set, or a short description when it isn't a fixed value.
	Value string `json:"value"`
	// Reason explains why it's set automatically, in user-facing language.
	Reason string `json:"reason"`
}

AutoFilledField is a field the backend fills in automatically when it isn't supplied, as returned by InvoicesService.GetAutoFilledFields.

type Client

type Client struct {
	// Invoices submits invoices for validation and retrieves results.
	Invoices *InvoicesService
	// APIKeys creates, lists, and revokes API keys.
	APIKeys *APIKeysService
	// contains filtered or unexported fields
}

Client is the entry point for the Xingen API.

func New

func New(apiKey string, opts ...Option) (*Client, error)

New constructs a Client. apiKey is required — an "xgn_live_"/"xgn_test_" prefixed API key.

type Contact

type Contact struct {
	Name      *string `json:"name"`
	Telephone *string `json:"telephone"`
	Email     *string `json:"email"`
}

type CreateApiKeyRequest

type CreateApiKeyRequest struct {
	Name string `json:"name"`
	// Sandbox: if true, requests using this key don't count toward quota. Defaults to false.
	Sandbox bool `json:"sandbox"`
	// QuotaLimit is an optional monthly quota. Nil means unlimited (Pro only) — free-tier keys
	// are capped server-side regardless.
	QuotaLimit *int `json:"quotaLimit,omitempty"`
}

CreateApiKeyRequest is the request body for APIKeysService.Create.

type CreatedApiKey

type CreatedApiKey struct {
	ID         string    `json:"id"`
	RawKey     string    `json:"rawKey"`
	Name       string    `json:"name"`
	Sandbox    bool      `json:"sandbox"`
	QuotaLimit *int      `json:"quotaLimit"`
	CreatedAt  time.Time `json:"createdAt"`
}

CreatedApiKey is the response from APIKeysService.Create. RawKey is shown only this once — the backend never returns it again, so callers must persist it immediately.

type Date

type Date string

Date is a date-only value (no time-of-day or timezone), formatted as "YYYY-MM-DD" on the wire.

It is a defined string type, not a struct — encoding/json marshals/unmarshals any string-kind type as a plain JSON string automatically, so no custom MarshalJSON/UnmarshalJSON is needed here (the same trick Number relies on). Use NewDate to build one from a time.Time and Time to parse one back.

func NewDate

func NewDate(t time.Time) Date

NewDate formats t's date components (ignoring time-of-day and location) as a Date.

func (Date) IsZero

func (d Date) IsZero() bool

IsZero reports whether d is the empty Date, i.e. the field was absent from the source document.

func (Date) String

func (d Date) String() string

func (Date) Time

func (d Date) Time() (time.Time, error)

Time parses d as a UTC time.Time at midnight. Returns an error if d is not a valid "YYYY-MM-DD" date.

type Delivery

type Delivery struct {
	PartyName        *string `json:"partyName"`
	LocationID       *string `json:"locationId"`
	LocationSchemeID *string `json:"locationSchemeId"`
	// Address is the deliver-to address (BG-15); nil iff absent from the source document.
	Address            *Address `json:"address"`
	ActualDeliveryDate *Date    `json:"actualDeliveryDate"`
}

type ErrorResponse

type ErrorResponse struct {
	Message     string            `json:"message"`
	Error       string            `json:"error"`
	Code        int               `json:"code"`
	Timestamp   time.Time         `json:"timestamp"`
	FieldErrors map[string]string `json:"fieldErrors"`
}

ErrorResponse mirrors the backend's standard error body shape. Present on 400/403/404/500 responses. Not present on 429 (see QuotaExceededError) or 401, which use a different or empty body.

type ExtractionModelTier added in v0.2.0

type ExtractionModelTier string

ExtractionModelTier selects the quality/cost tier for AI-based PDF invoice extraction (InvoicesService.ExtractInvoice).

  • TierFast — lower-cost model, good for clean/text-based PDFs (available to all tiers)
  • TierAccurate — highest-accuracy model, recommended for scanned/low-quality PDFs (Pro only)
const (
	TierFast     ExtractionModelTier = "FAST"
	TierAccurate ExtractionModelTier = "ACCURATE"
)

type Invoice

type Invoice struct {
	InvoiceNumber            *string  `json:"invoiceNumber"`
	IssueDate                *Date    `json:"issueDate"`
	DueDate                  *Date    `json:"dueDate"`
	TaxPointDate             *Date    `json:"taxPointDate"`
	Currency                 *string  `json:"currency"`
	BuyerReference           *string  `json:"buyerReference"`
	SpecificationID          *string  `json:"specificationId"`
	ProfileID                *string  `json:"profileId"`
	TypeCode                 *string  `json:"typeCode"`
	OrderReference           *string  `json:"orderReference"`
	SalesOrderReference      *string  `json:"salesOrderReference"`
	ProjectReference         *string  `json:"projectReference"`
	ContractReference        *string  `json:"contractReference"`
	ReceivingAdviceReference *string  `json:"receivingAdviceReference"`
	DespatchAdviceReference  *string  `json:"despatchAdviceReference"`
	TenderOrLotReference     *string  `json:"tenderOrLotReference"`
	InvoicedObjectID         *string  `json:"invoicedObjectId"`
	InvoicedObjectSchemeID   *string  `json:"invoicedObjectSchemeId"`
	BuyerAccountingReference *string  `json:"buyerAccountingReference"`
	Notes                    []string `json:"notes"`
	PaymentTermsNote         *string  `json:"paymentTermsNote"`

	PrecedingInvoiceReferences []PrecedingInvoiceReference `json:"precedingInvoiceReferences"`
	SupportingDocuments        []SupportingDocument        `json:"supportingDocuments"`
	ProjectReferenceCount      int                         `json:"projectReferenceCount"`

	DeliveryPeriodStart *Date `json:"deliveryPeriodStart"`
	DeliveryPeriodEnd   *Date `json:"deliveryPeriodEnd"`

	// InvoicePeriod is nil iff no document-level invoicing period was present in the source document.
	InvoicePeriod *InvoicePeriod `json:"invoicePeriod"`
	// Delivery is nil iff no delivery element was present in the source document.
	Delivery *Delivery `json:"delivery"`

	Supplier *Party `json:"supplier"`
	Buyer    *Party `json:"buyer"`
	// Payee is nil unless the payee differs from the seller.
	Payee *Party `json:"payee"`
	// TaxRepresentative is nil unless a tax representative is present.
	TaxRepresentative *Party `json:"taxRepresentative"`

	Lines            []InvoiceLine     `json:"lines"`
	TaxBreakdowns    []TaxBreakdown    `json:"taxBreakdowns"`
	AllowanceCharges []AllowanceCharge `json:"allowanceCharges"`
	PaymentMeans     []PaymentMeans    `json:"paymentMeans"`

	TaxCurrencyCode               *string `json:"taxCurrencyCode"`
	TaxTotalWithSubtotalsCount    int     `json:"taxTotalWithSubtotalsCount"`
	TaxTotalWithoutSubtotalsCount int     `json:"taxTotalWithoutSubtotalsCount"`

	LineExtensionAmount           *Number `json:"lineExtensionAmount"`
	AllowanceTotalAmount          *Number `json:"allowanceTotalAmount"`
	ChargeTotalAmount             *Number `json:"chargeTotalAmount"`
	TaxExclusiveAmount            *Number `json:"taxExclusiveAmount"`
	TaxAmount                     *Number `json:"taxAmount"`
	TaxAmountInAccountingCurrency *Number `json:"taxAmountInAccountingCurrency"`
	TaxInclusiveAmount            *Number `json:"taxInclusiveAmount"`
	PrepaidAmount                 *Number `json:"prepaidAmount"`
	PayableRoundingAmount         *Number `json:"payableRoundingAmount"`
	PayableAmount                 *Number `json:"payableAmount"`
}

Invoice is the read-only invoice model, as returned inside an InvoiceRecord.

type InvoiceLine

type InvoiceLine struct {
	LineID                 *string `json:"lineId"`
	Note                   *string `json:"note"`
	ObjectID               *string `json:"objectId"`
	ObjectIDSchemeID       *string `json:"objectIdSchemeId"`
	OrderLineReference     *string `json:"orderLineReference"`
	AccountingReference    *string `json:"accountingReference"`
	ItemName               *string `json:"itemName"`
	Description            *string `json:"description"`
	SellerItemID           *string `json:"sellerItemId"`
	BuyerItemID            *string `json:"buyerItemId"`
	StandardItemID         *string `json:"standardItemId"`
	StandardItemIDSchemeID *string `json:"standardItemIdSchemeId"`
	OriginCountryCode      *string `json:"originCountryCode"`

	Classifications []ItemClassification `json:"classifications"`
	Attributes      []ItemAttribute      `json:"attributes"`

	Quantity              *Number `json:"quantity"`
	Unit                  *string `json:"unit"`
	Price                 *Number `json:"price"`
	GrossPrice            *Number `json:"grossPrice"`
	PriceDiscount         *Number `json:"priceDiscount"`
	PriceHasCharge        bool    `json:"priceHasCharge"`
	PriceBaseQuantity     *Number `json:"priceBaseQuantity"`
	PriceBaseQuantityUnit *string `json:"priceBaseQuantityUnit"`
	TaxCategoryCode       *string `json:"taxCategoryCode"`
	TaxRate               *Number `json:"taxRate"`
	LineNetAmount         *Number `json:"lineNetAmount"`

	// Period is nil iff no line-level invoicing period was present in the source document.
	Period                    *InvoicePeriod `json:"period"`
	DocumentReferenceCount    int            `json:"documentReferenceCount"`
	DocumentReferenceTypeCode *string        `json:"documentReferenceTypeCode"`

	AllowanceCharges []LineAllowanceCharge `json:"allowanceCharges"`
}

type InvoicePeriod

type InvoicePeriod struct {
	StartDate *Date `json:"startDate"`
	EndDate   *Date `json:"endDate"`
	// DescriptionCode is document level only (UNTDID 2005 tax point date code).
	DescriptionCode *string `json:"descriptionCode"`
}

InvoicePeriod is an invoicing period, at document level (BG-14) or line level (BG-26).

type InvoiceRecord

type InvoiceRecord struct {
	ID     string        `json:"id"`
	Status InvoiceStatus `json:"status"`

	Invoice *Invoice `json:"canonicalJson"`

	// ValidationResult is nil while Status is StatusProcessing.
	ValidationResult *ValidationResult `json:"validationResult"`

	CreatedAt         time.Time `json:"createdAt"`
	ValidationProfile string    `json:"validationProfile"`
	InvoiceFormat     string    `json:"invoiceFormat"`
	UploadedBy        string    `json:"uploadedBy"`
	Sandbox           bool      `json:"sandbox"`
	APIKeyID          *string   `json:"apiKeyId"`

	// ExtractionTier is the extraction quality tier used ("FAST"/"ACCURATE") — only set for AI PDF
	// extractions (InvoiceFormat == "PDF_AI").
	ExtractionTier *string `json:"extractionTier"`
}

InvoiceRecord is the envelope the backend returns for a submitted invoice: submission metadata plus the parsed Invoice and, once validation has finished, its ValidationResult. Distinct from Invoice itself because GET /v1/invoices/{id} never returns a bare invoice — the backend column backing this field is named canonicalJson, remapped here to Invoice so the SDK's public field name is meaningful rather than leaking an internal storage detail.

type InvoiceStatus

type InvoiceStatus string

InvoiceStatus is the lifecycle state of a submitted invoice.

const (
	StatusProcessing       InvoiceStatus = "processing"
	StatusValidated        InvoiceStatus = "validated"
	StatusFailedValidation InvoiceStatus = "failed_validation"
)

func (InvoiceStatus) IsTerminal

func (s InvoiceStatus) IsTerminal() bool

IsTerminal reports whether s is a terminal status — VALIDATED and FAILED_VALIDATION are both terminal, successful outcomes from the SDK's perspective (a failed validation is still a completed API call).

type InvoiceSubmission

type InvoiceSubmission struct {
	InvoiceNumber string `json:"invoiceNumber,omitempty"`
	IssueDate     Date   `json:"issueDate,omitempty"`
	// DueDate is the payment due date (BT-9). Either this or PaymentTermsNote is required whenever
	// the payable amount is positive.
	DueDate Date `json:"dueDate,omitempty"`
	// TaxPointDate is the value added tax point date (BT-7).
	TaxPointDate Date   `json:"taxPointDate,omitempty"`
	Currency     string `json:"currency,omitempty"`
	// TaxCurrencyCode is the VAT accounting currency code (BT-6), if different from Currency.
	TaxCurrencyCode string `json:"taxCurrencyCode,omitempty"`
	// BuyerReference is optional in general, mandatory in practice for XRechnung (Leitweg-ID).
	BuyerReference string `json:"buyerReference,omitempty"`
	// PaymentTermsNote is payment terms (BT-20). Either this or DueDate is required whenever the
	// payable amount is positive.
	PaymentTermsNote         string `json:"paymentTermsNote,omitempty"`
	OrderReference           string `json:"orderReference,omitempty"`
	SalesOrderReference      string `json:"salesOrderReference,omitempty"`
	ProjectReference         string `json:"projectReference,omitempty"`
	ContractReference        string `json:"contractReference,omitempty"`
	ReceivingAdviceReference string `json:"receivingAdviceReference,omitempty"`
	DespatchAdviceReference  string `json:"despatchAdviceReference,omitempty"`
	TenderOrLotReference     string `json:"tenderOrLotReference,omitempty"`
	InvoicedObjectID         string `json:"invoicedObjectId,omitempty"`
	InvoicedObjectSchemeID   string `json:"invoicedObjectSchemeId,omitempty"`
	BuyerAccountingReference string `json:"buyerAccountingReference,omitempty"`
	// Notes are free-text invoice notes (BT-22).
	Notes []string `json:"notes,omitempty"`
	// PrecedingInvoiceReferences are BG-3 — e.g. the original invoice a credit note corrects.
	PrecedingInvoiceReferences []InvoiceSubmissionPrecedingInvoiceReferenceInput `json:"precedingInvoiceReferences,omitempty"`
	SupportingDocuments        []InvoiceSubmissionSupportingDocumentInput        `json:"supportingDocuments,omitempty"`
	DeliveryPeriodStart        Date                                              `json:"deliveryPeriodStart,omitempty"`
	DeliveryPeriodEnd          Date                                              `json:"deliveryPeriodEnd,omitempty"`
	InvoicePeriod              *InvoiceSubmissionInvoicePeriodInput              `json:"invoicePeriod,omitempty"`
	Delivery                   *InvoiceSubmissionDeliveryInput                   `json:"delivery,omitempty"`
	ValidationProfile          ValidationProfile                                 `json:"validationProfile,omitempty"`
	Supplier                   InvoiceSubmissionPartyInput                       `json:"supplier"`
	Buyer                      InvoiceSubmissionPartyInput                       `json:"buyer"`
	// Payee is the payee, if different from the seller (BG-10).
	Payee *InvoiceSubmissionPartyInput `json:"payee,omitempty"`
	// TaxRepresentative is the seller's tax representative (BG-11).
	TaxRepresentative *InvoiceSubmissionPartyInput            `json:"taxRepresentative,omitempty"`
	Lines             []InvoiceSubmissionLineInput            `json:"lines,omitempty"`
	PaymentMeans      []InvoiceSubmissionPaymentMeansInput    `json:"paymentMeans,omitempty"`
	AllowanceCharges  []InvoiceSubmissionAllowanceChargeInput `json:"allowanceCharges,omitempty"`
}

InvoiceSubmission is the request body for InvoicesService.Submit. Mirrors the backend's flat InvoiceRequest shape — deliberately not the same type as the much richer Invoice read model, since submit and read are genuinely different contracts. It has full parity with the backend's domain model: every invoice type the backend can validate can also be submitted as structured JSON through this type, not just a minimal subset.

type InvoiceSubmissionAddressInput added in v0.2.0

type InvoiceSubmissionAddressInput struct {
	StreetName string `json:"streetName,omitempty"`
	// AdditionalStreetName is BT-36/BT-51.
	AdditionalStreetName string `json:"additionalStreetName,omitempty"`
	// AddressLine3 is BT-162/BT-163.
	AddressLine3 string `json:"addressLine3,omitempty"`
	City         string `json:"city,omitempty"`
	PostalZone   string `json:"postalZone,omitempty"`
	// CountrySubdivision is e.g. a state or region (BT-39/BT-54).
	CountrySubdivision string `json:"countrySubdivision,omitempty"`
	CountryCode        string `json:"countryCode,omitempty"`
}

InvoiceSubmissionAddressInput is the postal address (BG-5/BG-8/BG-15) of an InvoiceSubmissionPartyInput or InvoiceSubmissionDeliveryInput. Only CountryCode is mandatory server-side.

type InvoiceSubmissionAllowanceChargeInput added in v0.2.0

type InvoiceSubmissionAllowanceChargeInput struct {
	// Charge is true for a charge (BG-21), false for an allowance (BG-20).
	Charge          bool   `json:"charge"`
	Amount          Number `json:"amount,omitempty"`
	BaseAmount      Number `json:"baseAmount,omitempty"`
	Percentage      Number `json:"percentage,omitempty"`
	VatCategoryCode string `json:"vatCategoryCode,omitempty"`
	VatRate         Number `json:"vatRate,omitempty"`
	Reason          string `json:"reason,omitempty"`
	ReasonCode      string `json:"reasonCode,omitempty"`
}

InvoiceSubmissionAllowanceChargeInput is a document-level allowance or charge (BG-20/BG-21).

type InvoiceSubmissionContactInput added in v0.2.0

type InvoiceSubmissionContactInput struct {
	Name      string `json:"name,omitempty"`
	Telephone string `json:"telephone,omitempty"`
	Email     string `json:"email,omitempty"`
}

InvoiceSubmissionContactInput is contact details (BG-6/BG-9) of an InvoiceSubmissionPartyInput.

type InvoiceSubmissionDeliveryInput added in v0.2.0

type InvoiceSubmissionDeliveryInput struct {
	PartyName        string `json:"partyName,omitempty"`
	LocationID       string `json:"locationId,omitempty"`
	LocationSchemeID string `json:"locationSchemeId,omitempty"`
	// Address is the deliver-to address (BG-15).
	Address            *InvoiceSubmissionAddressInput `json:"address,omitempty"`
	ActualDeliveryDate Date                           `json:"actualDeliveryDate,omitempty"`
}

InvoiceSubmissionDeliveryInput is delivery information (BG-13).

type InvoiceSubmissionInvoicePeriodInput added in v0.2.0

type InvoiceSubmissionInvoicePeriodInput struct {
	StartDate Date `json:"startDate,omitempty"`
	EndDate   Date `json:"endDate,omitempty"`
	// DescriptionCode is document level only (UNTDID 2005 tax point date code).
	DescriptionCode string `json:"descriptionCode,omitempty"`
}

InvoiceSubmissionInvoicePeriodInput is an invoicing period, at document level (BG-14) or line level (BG-26).

type InvoiceSubmissionItemAttributeInput added in v0.2.0

type InvoiceSubmissionItemAttributeInput struct {
	Name  string `json:"name,omitempty"`
	Value string `json:"value,omitempty"`
}

InvoiceSubmissionItemAttributeInput is an additional item attribute (BG-32).

type InvoiceSubmissionItemClassificationInput added in v0.2.0

type InvoiceSubmissionItemClassificationInput struct {
	Code string `json:"code,omitempty"`
	// ListID is the UNTDID 7143 scheme identifier.
	ListID        string `json:"listId,omitempty"`
	ListVersionID string `json:"listVersionId,omitempty"`
}

InvoiceSubmissionItemClassificationInput is an item classification (BT-158).

type InvoiceSubmissionLineAllowanceChargeInput added in v0.2.0

type InvoiceSubmissionLineAllowanceChargeInput struct {
	// Charge is true for a charge (BG-28), false for an allowance (BG-27).
	Charge     bool   `json:"charge"`
	Amount     Number `json:"amount,omitempty"`
	BaseAmount Number `json:"baseAmount,omitempty"`
	Percentage Number `json:"percentage,omitempty"`
	Reason     string `json:"reason,omitempty"`
	ReasonCode string `json:"reasonCode,omitempty"`
}

InvoiceSubmissionLineAllowanceChargeInput is a line-level allowance or charge (BG-27/BG-28).

type InvoiceSubmissionLineInput

type InvoiceSubmissionLineInput struct {
	Description string `json:"description,omitempty"`
	// ItemName is BT-153, distinct from Description if both are needed.
	ItemName               string                                     `json:"itemName,omitempty"`
	Note                   string                                     `json:"note,omitempty"`
	ObjectID               string                                     `json:"objectId,omitempty"`
	ObjectIDSchemeID       string                                     `json:"objectIdSchemeId,omitempty"`
	OrderLineReference     string                                     `json:"orderLineReference,omitempty"`
	AccountingReference    string                                     `json:"accountingReference,omitempty"`
	SellerItemID           string                                     `json:"sellerItemId,omitempty"`
	BuyerItemID            string                                     `json:"buyerItemId,omitempty"`
	StandardItemID         string                                     `json:"standardItemId,omitempty"`
	StandardItemIDSchemeID string                                     `json:"standardItemIdSchemeId,omitempty"`
	OriginCountryCode      string                                     `json:"originCountryCode,omitempty"`
	Classifications        []InvoiceSubmissionItemClassificationInput `json:"classifications,omitempty"`
	Attributes             []InvoiceSubmissionItemAttributeInput      `json:"attributes,omitempty"`
	Quantity               Number                                     `json:"quantity,omitempty"`
	Unit                   string                                     `json:"unit,omitempty"`
	Price                  Number                                     `json:"price,omitempty"`
	GrossPrice             Number                                     `json:"grossPrice,omitempty"`
	PriceDiscount          Number                                     `json:"priceDiscount,omitempty"`
	PriceBaseQuantity      Number                                     `json:"priceBaseQuantity,omitempty"`
	PriceBaseQuantityUnit  string                                     `json:"priceBaseQuantityUnit,omitempty"`
	// TaxCategoryCode is the VAT category code, UNCL5305 (BT-151). Defaults to Standard rate if
	// omitted.
	TaxCategoryCode string `json:"taxCategoryCode,omitempty"`
	TaxRate         Number `json:"taxRate,omitempty"`
	// ExemptionReason is the VAT exemption reason text (BT-120) — set when TaxCategoryCode is
	// exempt/reverse-charge/out-of-scope.
	ExemptionReason     string `json:"exemptionReason,omitempty"`
	ExemptionReasonCode string `json:"exemptionReasonCode,omitempty"`
	// Period is the line-level invoicing period (BG-26).
	Period           *InvoiceSubmissionInvoicePeriodInput        `json:"period,omitempty"`
	AllowanceCharges []InvoiceSubmissionLineAllowanceChargeInput `json:"allowanceCharges,omitempty"`
}

InvoiceSubmissionLineInput is a single invoice line, as submitted with a new invoice.

type InvoiceSubmissionPartyIdentifierInput added in v0.2.0

type InvoiceSubmissionPartyIdentifierInput struct {
	ID string `json:"id,omitempty"`
	// SchemeID is the ISO 6523 ICD, or "SEPA" for creditor identifiers.
	SchemeID string `json:"schemeId,omitempty"`
}

InvoiceSubmissionPartyIdentifierInput is an additional party identifier (BT-29/BT-46/BT-60), e.g. a SEPA creditor identifier.

type InvoiceSubmissionPartyInput

type InvoiceSubmissionPartyInput struct {
	Name string `json:"name,omitempty"`
	// RegistrationName is the legal registration name, if different from the trading name
	// (BT-27/BT-44).
	RegistrationName string `json:"registrationName,omitempty"`
	VatID            string `json:"vatId,omitempty"`
	// TaxRegistrationID is a tax registration identifier, non-VAT scheme (BT-32).
	TaxRegistrationID string `json:"taxRegistrationId,omitempty"`
	// LegalRegistrationID and LegalRegistrationSchemeID are the legal registration identifier and
	// its scheme (BT-30/BT-47, BT-30-1/BT-47-1).
	LegalRegistrationID       string `json:"legalRegistrationId,omitempty"`
	LegalRegistrationSchemeID string `json:"legalRegistrationSchemeId,omitempty"`
	// AdditionalLegalInfo is e.g. the legal form (BT-33).
	AdditionalLegalInfo string `json:"additionalLegalInfo,omitempty"`
	LeitwegID           string `json:"leitwegId,omitempty"`
	// Address is mandatory (BG-5/BG-8) for supplier/buyer — the backend rejects a party with no
	// postal address, on every validation profile. Only CountryCode is mandatory server-side.
	Address          *InvoiceSubmissionAddressInput `json:"address,omitempty"`
	Contact          *InvoiceSubmissionContactInput `json:"contact,omitempty"`
	EndpointID       string                         `json:"endpointId,omitempty"`
	EndpointSchemeID string                         `json:"endpointSchemeId,omitempty"`
	// Identifiers are additional party identifiers (BT-29/BT-46/BT-60), e.g. a SEPA creditor
	// identifier.
	Identifiers []InvoiceSubmissionPartyIdentifierInput `json:"identifiers,omitempty"`
}

InvoiceSubmissionPartyInput is a seller, buyer, payee, or tax representative, as submitted with a new invoice.

type InvoiceSubmissionPaymentMeansInput added in v0.2.0

type InvoiceSubmissionPaymentMeansInput struct {
	TypeCode                string `json:"typeCode,omitempty"`
	PaymentMeansText        string `json:"paymentMeansText,omitempty"`
	RemittanceInformation   string `json:"remittanceInformation,omitempty"`
	CreditTransferAccountID string `json:"creditTransferAccountId,omitempty"`
	AccountName             string `json:"accountName,omitempty"`
	ServiceProviderID       string `json:"serviceProviderId,omitempty"`
	MandateReferenceID      string `json:"mandateReferenceId,omitempty"`
	CardAccountNumber       string `json:"cardAccountNumber,omitempty"`
	CardHolderName          string `json:"cardHolderName,omitempty"`
	CreditorID              string `json:"creditorId,omitempty"`
	DebitedAccountID        string `json:"debitedAccountId,omitempty"`
}

InvoiceSubmissionPaymentMeansInput is payment means (BG-16).

type InvoiceSubmissionPrecedingInvoiceReferenceInput added in v0.2.0

type InvoiceSubmissionPrecedingInvoiceReferenceInput struct {
	ID        string `json:"id,omitempty"`
	IssueDate Date   `json:"issueDate,omitempty"`
}

InvoiceSubmissionPrecedingInvoiceReferenceInput is a preceding invoice reference (BG-3) — e.g. the original invoice a credit note corrects.

type InvoiceSubmissionResult

type InvoiceSubmissionResult struct {
	ID     string        `json:"id"`
	Status InvoiceStatus `json:"status"`
}

InvoiceSubmissionResult is the 202 Accepted response every submit/validate endpoint returns.

type InvoiceSubmissionSupportingDocumentInput added in v0.2.0

type InvoiceSubmissionSupportingDocumentInput struct {
	ID          string `json:"id,omitempty"`
	SchemeID    string `json:"schemeId,omitempty"`
	TypeCode    string `json:"typeCode,omitempty"`
	Description string `json:"description,omitempty"`
	ExternalURI string `json:"externalUri,omitempty"`
	MimeCode    string `json:"mimeCode,omitempty"`
	Filename    string `json:"filename,omitempty"`
}

InvoiceSubmissionSupportingDocumentInput is an additional supporting document (BG-24).

type InvoicesService

type InvoicesService struct {
	// contains filtered or unexported fields
}

InvoicesService submits invoices for validation and retrieves results. Reachable via Client.Invoices.

func (*InvoicesService) DownloadIdocXML

func (s *InvoicesService) DownloadIdocXML(ctx context.Context, id string) ([]byte, error)

DownloadIdocXML exports a validated invoice as a SAP IDoc XML file.

func (*InvoicesService) DownloadPDF

func (s *InvoicesService) DownloadPDF(ctx context.Context, id string) ([]byte, error)

DownloadPDF exports a validated invoice as a ZUGFeRD-compliant PDF with embedded XML.

func (*InvoicesService) ExtractInvoice added in v0.2.0

ExtractInvoice uploads a plain (non-XRechnung/UBL/CII) invoice PDF — including scanned/image PDFs — for AI-based field extraction. The extracted invoice is validated and converted to a ZUGFeRD/Factur-X hybrid PDF, downloadable via DownloadPDF once processing completes. Processing is asynchronous — poll Get or use ExtractInvoiceAndWait. tier == TierAccurate requires a Pro subscription.

func (*InvoicesService) ExtractInvoiceAndWait added in v0.2.0

func (s *InvoicesService) ExtractInvoiceAndWait(ctx context.Context, path string, profile ValidationProfile, tier ExtractionModelTier, opts PollOptions) (InvoiceRecord, error)

ExtractInvoiceAndWait uploads path for AI extraction and polls Get until validation reaches a terminal status.

func (*InvoicesService) ExtractInvoiceBytes added in v0.2.0

func (s *InvoicesService) ExtractInvoiceBytes(ctx context.Context, filename string, content []byte, profile ValidationProfile, tier ExtractionModelTier) (InvoiceSubmissionResult, error)

ExtractInvoiceBytes is the same as ExtractInvoice, for callers who already hold the file bytes in memory.

func (*InvoicesService) ExtractInvoiceBytesAndWait added in v0.2.0

func (s *InvoicesService) ExtractInvoiceBytesAndWait(ctx context.Context, filename string, content []byte, profile ValidationProfile, tier ExtractionModelTier, opts PollOptions) (InvoiceRecord, error)

ExtractInvoiceBytesAndWait is the same as ExtractInvoiceAndWait, for in-memory file bytes.

func (*InvoicesService) Get

Get retrieves a single invoice by ID.

func (*InvoicesService) GetAutoFilledFields added in v0.2.0

func (s *InvoicesService) GetAutoFilledFields(ctx context.Context) (map[string][]AutoFilledField, error)

GetAutoFilledFields returns, per validation profile, the invoice fields the JSON create/PATCH/AI-extraction endpoints backfill automatically (e.g. invoice type code, specification identifier) — so a caller can tell the user rather than leave the gap unexplained.

func (*InvoicesService) List

func (s *InvoicesService) List(ctx context.Context, page, size int, sort string) (Page[InvoiceRecord], error)

List retrieves one page of invoices. sort matches the backend's default "createdAt,desc" when empty.

func (*InvoicesService) ListAll

func (s *InvoicesService) ListAll(ctx context.Context, pageSize int) iter.Seq2[InvoiceRecord, error]

ListAll lazily iterates every invoice across all pages, fetching the next page only once the current one is exhausted. Stop the range early (break) to avoid fetching further pages.

for record, err := range client.Invoices.ListAll(ctx, 50) {
    if err != nil { ... }
}

func (*InvoicesService) PatchInvoice added in v0.2.0

func (s *InvoicesService) PatchInvoice(ctx context.Context, id string, rawJSONPatch []byte) (InvoiceRecord, error)

PatchInvoice applies a JSON merge-patch (RFC 7386) to the invoice's canonical fields — e.g. to fill in fields an AI extraction missed, or fix a value flagged by validation — and re-validates synchronously, returning the updated record. Array fields (lines, paymentMeans, allowanceCharges, taxBreakdowns) are replaced wholesale when present in the patch; submit the complete corrected array, not a single element. Only invoices with status VALIDATED or FAILED_VALIDATION can be patched.

func (*InvoicesService) PatchInvoiceMap added in v0.2.0

func (s *InvoicesService) PatchInvoiceMap(ctx context.Context, id string, patch map[string]any) (InvoiceRecord, error)

PatchInvoiceMap is the same as PatchInvoice, for callers building the merge-patch as a map instead of raw JSON.

func (*InvoicesService) Submit

Submit queues a structured JSON invoice for async validation. Poll Get or use SubmitAndWait for the result.

func (*InvoicesService) SubmitAndWait

func (s *InvoicesService) SubmitAndWait(ctx context.Context, submission InvoiceSubmission, opts PollOptions) (InvoiceRecord, error)

SubmitAndWait submits submission and polls Get until validation reaches a terminal status.

func (*InvoicesService) SubmitOData

func (s *InvoicesService) SubmitOData(ctx context.Context, rawJSON []byte, profile ValidationProfile) (InvoiceSubmissionResult, error)

SubmitOData submits a raw SAP S/4HANA OData supplier-invoice JSON payload for validation. Ships as a thin passthrough in v1 rather than a fully typed model — the payload is large and SAP-integration specific.

func (*InvoicesService) SubmitODataMap

func (s *InvoicesService) SubmitODataMap(ctx context.Context, payload map[string]any, profile ValidationProfile) (InvoiceSubmissionResult, error)

SubmitODataMap is the same as SubmitOData, for callers building the payload as a map instead of raw JSON.

func (*InvoicesService) ValidateFile

func (s *InvoicesService) ValidateFile(ctx context.Context, path string, profile ValidationProfile) (InvoiceSubmissionResult, error)

ValidateFile uploads a UBL XML, CII XML, or ZUGFeRD PDF file for validation. Processing is asynchronous — poll Get or use ValidateFileAndWait for the result.

func (*InvoicesService) ValidateFileAndWait

func (s *InvoicesService) ValidateFileAndWait(ctx context.Context, path string, profile ValidationProfile, opts PollOptions) (InvoiceRecord, error)

ValidateFileAndWait uploads path and polls Get until validation reaches a terminal status.

func (*InvoicesService) ValidateFileBytes

func (s *InvoicesService) ValidateFileBytes(ctx context.Context, filename string, content []byte, profile ValidationProfile) (InvoiceSubmissionResult, error)

ValidateFileBytes is the same as ValidateFile, for callers who already hold the file bytes in memory.

func (*InvoicesService) ValidateFileBytesAndWait

func (s *InvoicesService) ValidateFileBytesAndWait(ctx context.Context, filename string, content []byte, profile ValidationProfile, opts PollOptions) (InvoiceRecord, error)

ValidateFileBytesAndWait is the same as ValidateFileAndWait, for in-memory file bytes.

func (*InvoicesService) ValidateIdoc

func (s *InvoicesService) ValidateIdoc(ctx context.Context, path string, profile ValidationProfile) (InvoiceSubmissionResult, error)

ValidateIdoc uploads a SAP IDoc XML file for validation. Processing is asynchronous — poll Get or use ValidateIdocAndWait.

func (*InvoicesService) ValidateIdocAndWait

func (s *InvoicesService) ValidateIdocAndWait(ctx context.Context, path string, profile ValidationProfile, opts PollOptions) (InvoiceRecord, error)

ValidateIdocAndWait uploads path as a SAP IDoc and polls Get until validation reaches a terminal status.

func (*InvoicesService) ValidateIdocBytes

func (s *InvoicesService) ValidateIdocBytes(ctx context.Context, filename string, content []byte, profile ValidationProfile) (InvoiceSubmissionResult, error)

ValidateIdocBytes is the same as ValidateIdoc, for callers who already hold the file bytes in memory.

func (*InvoicesService) ValidateIdocBytesAndWait

func (s *InvoicesService) ValidateIdocBytesAndWait(ctx context.Context, filename string, content []byte, profile ValidationProfile, opts PollOptions) (InvoiceRecord, error)

ValidateIdocBytesAndWait is the same as ValidateIdocAndWait, for in-memory file bytes.

type ItemAttribute

type ItemAttribute struct {
	Name  *string `json:"name"`
	Value *string `json:"value"`
}

type ItemClassification

type ItemClassification struct {
	Code *string `json:"code"`
	// ListID is the UNTDID 7143 scheme identifier.
	ListID        *string `json:"listId"`
	ListVersionID *string `json:"listVersionId"`
}

type KositResult

type KositResult struct {
	Valid  bool     `json:"valid"`
	Errors []string `json:"errors"`
}

type LineAllowanceCharge

type LineAllowanceCharge struct {
	Charge     bool    `json:"charge"`
	Amount     *Number `json:"amount"`
	BaseAmount *Number `json:"baseAmount"`
	Percentage *Number `json:"percentage"`
	Reason     *string `json:"reason"`
	ReasonCode *string `json:"reasonCode"`
}

LineAllowanceCharge is a line-level allowance/charge (BT-136..BT-141).

type NotFoundError

type NotFoundError struct{ *APIError }

NotFoundError is a 404 — the requested resource does not exist.

type Number

type Number = json.Number

Number is an arbitrary-precision decimal literal, used for every monetary and quantity field.

It is a type alias (not a new type) for encoding/json.Number, so any json.Number value works interchangeably with xingen.Number and callers don't need to import encoding/json themselves. Struct fields typed as (*)json.Number decode straight from the source-text numeric literal — confirmed empirically — with no float64 intermediate and no custom parser required, unlike the Python/TypeScript/PHP ports of this SDK, which each needed a hand-rolled numeric-JSON parser to avoid silently corrupting high-precision monetary values.

type Option

type Option func(*clientConfig)

Option configures a Client constructed by New.

func WithBaseURL

func WithBaseURL(baseURL string) Option

WithBaseURL overrides the default https://app.xingen.de/api base URL — useful for self-hosted or local testing.

func WithConnectTimeout

func WithConnectTimeout(d time.Duration) Option

WithConnectTimeout sets the TCP connect timeout. Ignored if WithHTTPClient is also passed.

func WithHTTPClient

func WithHTTPClient(httpClient *http.Client) Option

WithHTTPClient overrides the *http.Client used for every request. When set, WithConnectTimeout has no effect — configure the dialer's timeout on the supplied client instead.

func WithRequestTimeout

func WithRequestTimeout(d time.Duration) Option

WithRequestTimeout sets the per-request timeout, applied to every call the SDK makes (not the total time of a *AndWait polling helper — see PollOptions.Timeout for that).

type Page

type Page[T any] struct {
	Content          []T   `json:"content"`
	TotalElements    int64 `json:"totalElements"`
	TotalPages       int   `json:"totalPages"`
	Number           int   `json:"number"`
	Size             int   `json:"size"`
	First            bool  `json:"first"`
	Last             bool  `json:"last"`
	NumberOfElements int   `json:"numberOfElements"`
	Empty            bool  `json:"empty"`
}

Page mirrors the JSON shape Spring Data's Page<T> serializes to.

type Party

type Party struct {
	Name                      *string           `json:"name"`
	RegistrationName          *string           `json:"registrationName"`
	VatID                     *string           `json:"vatId"`
	TaxRegistrationID         *string           `json:"taxRegistrationId"`
	LegalRegistrationID       *string           `json:"legalRegistrationId"`
	LegalRegistrationSchemeID *string           `json:"legalRegistrationSchemeId"`
	AdditionalLegalInfo       *string           `json:"additionalLegalInfo"`
	LeitwegID                 *string           `json:"leitwegId"`
	EndpointID                *string           `json:"endpointId"`
	EndpointSchemeID          *string           `json:"endpointSchemeId"`
	Identifiers               []PartyIdentifier `json:"identifiers"`
	// Address is nil iff no postal address element was present in the source document.
	Address *Address `json:"address"`
	// Contact is nil iff no contact element was present in the source document.
	Contact *Contact `json:"contact"`
}

type PartyIdentifier

type PartyIdentifier struct {
	ID *string `json:"id"`
	// SchemeID is the ISO 6523 ICD, or "SEPA" for creditor identifiers.
	SchemeID *string `json:"schemeId"`
}

type PaymentMeans

type PaymentMeans struct {
	TypeCode                *string `json:"typeCode"`
	PaymentMeansText        *string `json:"paymentMeansText"`
	RemittanceInformation   *string `json:"remittanceInformation"`
	CreditTransferAccountID *string `json:"creditTransferAccountId"`
	AccountName             *string `json:"accountName"`
	ServiceProviderID       *string `json:"serviceProviderId"`
	MandateReferenceID      *string `json:"mandateReferenceId"`
	CardAccountNumber       *string `json:"cardAccountNumber"`
	CardHolderName          *string `json:"cardHolderName"`
	CreditorID              *string `json:"creditorId"`
	DebitedAccountID        *string `json:"debitedAccountId"`
}

type PermissionError

type PermissionError struct{ *APIError }

PermissionError is a 403 — e.g. the requested invoice exists but is not owned by the caller.

type PollCancelledError

type PollCancelledError struct {
	Message string
}

PollCancelledError is returned by a *AndWait polling helper when the context passed to it is cancelled before the invoice reaches a terminal status.

func (*PollCancelledError) Error

func (e *PollCancelledError) Error() string

type PollOptions

type PollOptions struct {
	InitialInterval   time.Duration
	MaxInterval       time.Duration
	BackoffMultiplier float64
	// Timeout is the total time budget across the whole poll loop, not a per-request timeout.
	Timeout time.Duration
}

PollOptions configures the polling loop used by the *AndWait helpers on InvoicesService.

func DefaultPollOptions

func DefaultPollOptions() PollOptions

DefaultPollOptions returns the default backoff schedule: 500ms initial interval, 1.5x multiplier, capped at 5s, with a 60s overall timeout.

type PollTimeoutError

type PollTimeoutError struct {
	Message       string
	PartialResult *InvoiceRecord
}

PollTimeoutError is returned by a *AndWait polling helper when PollOptions.Timeout elapses before the invoice reaches a terminal status. PartialResult holds the last known state.

func (*PollTimeoutError) Error

func (e *PollTimeoutError) Error() string

type PrecedingInvoiceReference

type PrecedingInvoiceReference struct {
	ID        *string `json:"id"`
	IssueDate *Date   `json:"issueDate"`
}

type QuotaExceededError

type QuotaExceededError struct{ *APIError }

QuotaExceededError is a 429 — the API key's request quota has been exhausted. This bypasses the backend's normal error pipeline, so the body is {"error": "..."}, not the standard ErrorResponse shape.

type Severity

type Severity string

Severity is how serious a ValidationError is.

const (
	SeverityError   Severity = "ERROR"
	SeverityWarning Severity = "WARNING"
	SeverityInfo    Severity = "INFO"
)

type SupportingDocument

type SupportingDocument struct {
	ID       *string `json:"id"`
	SchemeID *string `json:"schemeId"`
	// TypeCode is the UNTDID 1001 document type code, e.g. "50", "130".
	TypeCode    *string `json:"typeCode"`
	Description *string `json:"description"`
	// ExternalURI is nil for no external-reference element; empty string for present but the URI missing.
	ExternalURI     *string `json:"externalUri"`
	MimeCode        *string `json:"mimeCode"`
	Filename        *string `json:"filename"`
	EmbeddedPresent bool    `json:"embeddedPresent"`
}

type TaxBreakdown

type TaxBreakdown struct {
	TaxableAmount *Number `json:"taxableAmount"`
	TaxAmount     *Number `json:"taxAmount"`
	// CategoryCode is one of S / Z / E / AE / K / G / O.
	CategoryCode *string `json:"categoryCode"`
	// Rate is nil for exempt categories (E/AE/K/G/O).
	Rate                *Number `json:"rate"`
	ExemptionReason     *string `json:"exemptionReason"`
	ExemptionReasonCode *string `json:"exemptionReasonCode"`
}

type TransportError

type TransportError struct {
	Message string
	Err     error
}

TransportError wraps a network-level failure (connection refused, DNS failure, context cancellation, etc.) that happened before an HTTP response was received — not an HTTP error response.

func (*TransportError) Error

func (e *TransportError) Error() string

func (*TransportError) Unwrap

func (e *TransportError) Unwrap() error

type ValidationError

type ValidationError struct {
	Code             *string          `json:"code"`
	Message          *string          `json:"message"`
	Field            *string          `json:"field"`
	Suggestion       *string          `json:"suggestion"`
	DocumentationURL *string          `json:"documentationUrl"`
	Layer            *ValidationLayer `json:"layer"`
	Severity         *Severity        `json:"severity"`
}

type ValidationLayer

type ValidationLayer string

ValidationLayer identifies which rule set a ValidationError came from.

const (
	// LayerCore is EN16931.
	LayerCore ValidationLayer = "CORE"
	// LayerNational is XRechnung.
	LayerNational ValidationLayer = "NATIONAL"
	// LayerNetwork is Peppol.
	LayerNetwork ValidationLayer = "NETWORK"
)

type ValidationProfile

type ValidationProfile string

ValidationProfile selects which standard an invoice is validated against.

  • EN16931 — European standard EN 16931 (free)
  • PEPPOL — PEPPOL BIS Billing 3.0 (free)
  • XRECHNUNG — German XRechnung standard (Pro)
  • FRANCE — French Factur-X standard (Pro) — not yet implemented server-side
  • ITALY — Italian FatturaPA standard (Pro) — not yet implemented server-side
const (
	ProfileEN16931   ValidationProfile = "EN16931"
	ProfilePEPPOL    ValidationProfile = "PEPPOL"
	ProfileXRechnung ValidationProfile = "XRECHNUNG"
	ProfileFrance    ValidationProfile = "FRANCE"
	ProfileItaly     ValidationProfile = "ITALY"
)

type ValidationRequestError

type ValidationRequestError struct {
	*APIError
	// FieldErrors is nil unless the failure was a bean-validation error on a request body (as
	// opposed to a plain malformed-request 400).
	FieldErrors map[string]string
}

ValidationRequestError is a 400 — malformed request body or bean-validation failure.

type ValidationResult

type ValidationResult struct {
	Valid  bool              `json:"valid"`
	Errors []ValidationError `json:"errors"`
	// KositResult is only populated for XML-based validation paths (UBL/CII/IDoc). Nil otherwise.
	KositResult *KositResult `json:"kositResult"`
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL