Skip to content

Models

Auto-generated from src/saldeosmart_mcp/models/. These are the JSON-shaped types the MCP boundary serializes to and from. Inputs validate before any network call; responses are typed projections of Saldeo's XML envelopes.

For the validated string aliases (IsoDate, Nip, Pesel, VatNumber, Year, Month) used throughout the inputs, see the common module at the top of this page.

Common

common

Cross-resource models — types referenced by more than one resource family.

Read-vs-write date typing — important to know:

  • Write inputs use :data:IsoDate, which validates the YYYY-MM-DD shape at the boundary so a typo like "2026-13-99" fails fast with a clean Pydantic error instead of a 4xx from Saldeo.
  • Read models keep str | None because the source is the Saldeo XML response itself; we trust it (it's already been through Saldeo's own validation) and a stricter type would mean a single bad row could blow up an entire list response.

The asymmetry is deliberate. Don't paper over it by stuffing IsoDate into a read model — that turns a bad cell into a parser crash.

IsoDate module-attribute

IsoDate = Annotated[str, AfterValidator(_validate_iso_date)]

ISO YYYY-MM-DD date as a string.

Use anywhere a Saldeo field is documented as a date — the validator rejects non-ISO strings with a clean Pydantic error pointing at the offending field.

Nip module-attribute

Nip = Annotated[str, AfterValidator(_validate_nip)]

10-digit Polish tax ID. Strips spaces and dashes; no checksum check.

Pesel module-attribute

Pesel = Annotated[str, AfterValidator(_validate_pesel)]

11-digit Polish national ID. Strips spaces; no checksum check.

VatNumber module-attribute

VatNumber = Annotated[str, AfterValidator(_validate_vat_number)]

EU-style VAT number: optional 2-letter country prefix + 8-15 digits.

Year module-attribute

Year = Annotated[int, Field(ge=2000, le=2099)]

4-digit year for a (year, month) folder. Catches LLM off-by-millennium typos.

Month module-attribute

Month = Annotated[int, Field(ge=1, le=12)]

Calendar month, 1-12.

BankAccount pydantic-model

A bank account as it appears nested inside contractor / company XML.

Fields:

  • name (str | None)
  • number (str | None)

BankAccountInput pydantic-model

Bank account payload accepted by contractor.merge.

number is required; name is the account's friendly label.

Fields:

  • name (str | None)
  • number (str)

Companies

companies

Company resource models. Used by list_companies / synchronize_companies.

CompanySynchronizeInput pydantic-model

One COMPANY row for company.synchronize (SS15).

Both fields are required by the spec: company_id is Saldeo's internal numeric ID; company_program_id is your ERP-side identifier (must be unique within the accounting firm).

Fields:

  • company_id (int)
  • company_program_id (str)

CompanyCreateBankAccountInput pydantic-model

One <BANK_ACCOUNT> row inside a CompanyCreateInput.

The first account in the list is treated as the primary. name is optional; everything else is required by the spec.

Fields:

  • number (str)
  • bank_name (str)
  • bic_number (str)
  • currency_iso4217 (str)
  • name (str | None)

CompanyCreateInput pydantic-model

One <COMPANY> body for company.create (SS01).

Saldeo creates a new client company plus its admin user in one shot. Required: company_program_id, username, email, short_name (max 8 chars), full_name, vat_number, city, postcode, street, plus at least one bank account.

Bank accounts are unusual: the spec says the section is O (optional) at the wrapper level but warns "if missing Saldeo synthesizes a placeholder". Pass real accounts whenever possible; an empty list omits the wrapper entirely.

Fields:

  • company_program_id (str)
  • username (str)
  • email (str)
  • short_name (str)
  • full_name (str)
  • vat_number (VatNumber)
  • city (str)
  • postcode (str)
  • street (str)
  • first_name (str | None)
  • last_name (str | None)
  • telephone (str | None)
  • contact_person (str | None)
  • bank_accounts (list[CompanyCreateBankAccountInput])
  • zus_bank_account (str | None)
  • send_email (bool | None)
  • producer (str | None)

Contractors

contractors

Contractor resource models — read response and merge input.

ContractorInput pydantic-model

One contractor for contractor.merge. Spec: SS02.

Fields:

  • short_name (str)
  • full_name (str)
  • contractor_program_id (str | None)
  • contractor_id (int | None)
  • supplier (bool | None)
  • customer (bool | None)
  • vat_number (VatNumber | None)
  • city (str | None)
  • postcode (str | None)
  • street (str | None)
  • country_iso3166a2 (str | None)
  • telephone (str | None)
  • contact_person (str | None)
  • description (str | None)
  • payment_days (int | None)
  • bank_accounts (list[BankAccountInput])
  • emails (list[str])

Documents

documents

Document resource models — read responses, ID-list groupings, and write inputs.

The richest resource family in SaldeoSMART. Cost documents (invoices, receipts) and their ancillary types (line items, dimensions, OCR origins) all live here. Sales invoices are a separate file (invoices.py); some 3.0 endpoints reuse the Document shape via a parser hook.

DocumentIdGroups pydantic-model

Document IDs grouped by Saldeo's logical buckets (SS22 response).

Saldeo's 3.0 endpoint returns one container per kind so callers can decide which subset to fetch via listbyid. Empty buckets are omitted.

Fields:

  • contracts (list[int])
  • invoices_cost (list[int])
  • invoices_internal (list[int])
  • invoices_material (list[int])
  • invoices_sale (list[int])
  • orders (list[int])
  • writings (list[int])
  • other_documents (list[int])

DocumentAddInput pydantic-model

One <DOCUMENT> row for document.add (SS05).

Pairs a (year, month) folder with a single binary attachment. The attachment is read from disk at tool invocation time; the resolved display name is sent as <ATTMNT_NAME>.

Fields:

  • year (Year)
  • month (Month)
  • attachment (Attachment)

DocumentAddRecognizeInput pydantic-model

Single document upload + OCR trigger for document.add_recognize (AE01).

Saldeo accepts one attachment per request; the file is delivered as the attmnt_1 form field and the XML carries only the OCR options.

Fields:

  • attachment (Attachment)
  • vat_number (VatNumber)
  • split_mode (SplitMode)
  • document_type (Literal['COST', 'SALE'] | None)
  • no_rotate (bool | None)

DocumentAddRecognizeResult pydantic-model

Result of document.add_recognize.

status is one of SENT (success), NOT_VALID, INSUFFICIENT_FUND, ERROR. ocr_origin_id is the handle for list_recognized_documents once Saldeo finishes the OCR pass.

Monetary values (cost, remaining_credits) are returned as the raw Saldeo string. Every other monetary field in the package follows the same convention — preserve the wire value verbatim and let callers parse to Decimal when they need arithmetic.

Fields:

  • status (str)
  • status_message (str | None)
  • ocr_origin_id (int | None)
  • cost (str | None)
  • sent_document_count (int | None)
  • sent_page_count (int | None)
  • split_mode (str | None)
  • no_rotate (bool | None)
  • remaining_credits (str | None)

DocumentCorrectContractorInput pydantic-model

<CONTRACTOR> block inside a DocumentCorrectInput. All fields required by the spec when the block is present.

Fields:

  • short_name (str)
  • full_name (str)
  • vat_number (VatNumber)
  • street (str)
  • city (str)
  • postcode (str)

DocumentCorrectInput pydantic-model

One <DOCUMENT> row for document.correct (AE02).

Used to overwrite extracted fields on an OCR'd document — Saldeo's self_learning flag tells the recognizer to remember the correction and apply it the next time the same vendor's document arrives.

Fields:

DocumentImportTypeInput pydantic-model

<DOCUMENT_TYPE> choice for document.import — by name+model or by ID.

Fields:

  • short_name (str | None)
  • model_type (DocumentModelType | None)
  • id (int | None)

DocumentImportCurrencyInput pydantic-model

<CURRENCY> block on a DocumentImportInput.

Fields:

  • iso4217 (str)
  • date (IsoDate)
  • rate (str | None)

DocumentImportDimensionInput pydantic-model

<DIMENSION> row inside a DIMENSIONS list (header or per-item).

Fields:

  • name (str)
  • value (str)

DocumentImportVATRegistryInput pydantic-model

One <VAT_REGISTRY> summary inside DocumentImportVATInput.

Fields:

  • rate (str)
  • netto (str)
  • vat (str)

DocumentImportVATItemInput pydantic-model

One <ITEM> inside a VAT_DOCUMENT.ITEMS block.

Fields:

DocumentImportVATInput pydantic-model

<VAT_DOCUMENT> block for VAT-bearing imports.

Fields:

DocumentImportNoVATItemInput pydantic-model

One <ITEM> inside a NO_VAT_DOCUMENT.ITEMS block.

Fields:

DocumentImportNoVATInput pydantic-model

<NO_VAT_DOCUMENT> block for non-VAT imports.

Fields:

DocumentImportLineItemInput pydantic-model

One <DOCUMENT_ITEM> inside DOCUMENT_ITEMS — product line.

Fields:

  • code (str | None)
  • name (str | None)
  • amount (str | None)
  • unit (str | None)
  • rate (str | None)
  • unit_value (str | None)
  • netto (str | None)
  • vat (str | None)
  • gross (str | None)
  • category (str | None)
  • dimension (DocumentImportDimensionInput | None)

DocumentImportPaymentInput pydantic-model

One <PAYMENT> inside PAYMENTS — partial-payment record.

Fields:

DocumentImportAttachmentInput pydantic-model

One <ATTACHMENT> inside a DocumentImportInput.attachments list.

Distinct from :class:CloseAttachmentInput — document.import attachments only carry an optional description; no TYPE / NAME / SHORT_DESCRIPTION.

Fields:

  • attachment (Attachment)
  • description (str | None)

DocumentImportInput pydantic-model

One <DOCUMENT> row for document.import (3.0).

Saldeo accepts up to 50 documents per request. The required fields are year, month, document_type, plus the attachment (delivered as the matching attmnt_N form field). Up to 5 supporting attachments per document via attachments.

The vat_document / no_vat_document pair is mutually exclusive per the XSD's <xs:choice>; provide whichever matches the document flavor (VAT-bearing invoices vs accounts / no-VAT documents).

Fields:

DocumentUpdateInput pydantic-model

One document edit for document.update (SS17).

document_id is required (Saldeo's primary key). Only fields you actually want to change need to be set; unspecified fields are left alone.

Fields:

  • document_id (int)
  • number (str | None)
  • issue_date (IsoDate | None)
  • sale_date (IsoDate | None)
  • payment_date (IsoDate | None)
  • contractor_program_id (str | None)
  • bank_account (str | None)
  • self_learning (bool | None)

DocumentSyncInput pydantic-model

One document mapping for document.sync (SS13).

Reports the accounting-side number/status back to Saldeo for a document. Either saldeo_id or (contractor_program_id + document_number + issue_date) must identify the document.

saldeo_id is str (not int like document_id elsewhere) because the document.sync XSD declares <SALDEO_ID> as xs:string.

Fields:

  • saldeo_id (str | None)
  • saldeo_guid (str | None)
  • contractor_program_id (str | None)
  • document_number (str | None)
  • issue_date (IsoDate | None)
  • guid (str | None)
  • description (str | None)
  • numbering_type (str | None)
  • account_document_number (str | None)
  • document_status (Literal['BUFFER', 'INTRODUCED', 'BOOKED'] | None)

DocumentDimensionInput pydantic-model

One DOCUMENT_DIMENSION row for document_dimension.merge (SS20).

Fields:

  • document_id (int)
  • dimensions (list[DocumentDimensionValueInput])

RecognizeOptionInput pydantic-model

One document for document.recognize (SS06).

Fields:

  • document_id (int)
  • split_mode (SplitMode | None)
  • no_rotate (bool | None)
  • overwrite_data (bool | None)

Invoices

invoices

Invoice resource models — sales invoices issued in SaldeoSMART.

The wire shape overlaps with cost Document enough that the parser is reused; only the container/leaf names differ.

InvoiceIdGroups pydantic-model

Invoice IDs grouped by kind (SSK07 response).

Fields:

  • invoices (list[int])
  • corrective_invoices (list[int])
  • pre_invoices (list[int])
  • corrective_pre_invoices (list[int])

InvoiceAddSaleDateRangeInput pydantic-model

Optional <SALE_DATE_FROM> + <SALE_DATE_TO> block for service invoices that span a period rather than a single day.

Fields:

InvoiceAddBankAccountInput pydantic-model

<BANK_ACCOUNT> block for invoice.add — different from contractor bank accounts (only NUMBER is required, BANK / BIC_SWIFT optional).

Fields:

  • number (str)
  • bank (str | None)
  • bic_swift (str | None)

InvoiceAddDiscountInput pydantic-model

<DISCOUNT> block on an InvoiceAddItemInput.

Fields:

  • type (DiscountType)
  • value (str)

InvoiceAddItemInput pydantic-model

One <INVOICE_ITEM> row.

Saldeo accepts up to 10000 items per invoice. rate strings track the XSD's VATRateType (e.g. "23", "5", "0", "ZW", "NP"); procedure_code and gtu_code are optional GTU / procedure markings used by Polish tax law.

Fields:

  • name (str)
  • amount (str)
  • unit (str)
  • unit_value (str)
  • pkwiu (str | None)
  • discount (InvoiceAddDiscountInput | None)
  • rate (str | None)
  • procedure_code (str | None)
  • gtu_code (str | None)

InvoiceAddPaymentInput pydantic-model

<INVOICE_PAYMENTS> block — single payment record per the XSD.

Fields:

  • payment_amount (str)
  • payment_date (IsoDate)

InvoiceAddNewTransportVehicleInput pydantic-model

<NEW_TRANSPORT_VEHICLE> block — only required when the invoice documents the intra-EU sale of a new transport vehicle.

Fields:

  • vehicle_type (VehicleType)
  • admission_date (IsoDate)
  • usage_metrics (int)

InvoiceAddInput pydantic-model

One <INVOICE> body for invoice.add (3.1, SSK06).

Required fields per the XSD: issue_date, according_to_agreement, purchaser_contractor_id, currency_iso4217, payment_type, plus at least one items entry.

sale_date and sale_date_range are mutually exclusive (xs:choice in the spec); set whichever applies and leave the other None. Likewise the recipient block (recipient_contractor_id + recipient_role) is opt-in and required-as-a-pair when present.

Fields:

  • issue_date (IsoDate)
  • according_to_agreement (bool)
  • purchaser_contractor_id (int)
  • currency_iso4217 (str)
  • payment_type (str)
  • items (list[InvoiceAddItemInput])
  • number (str | None)
  • suffix (str | None)
  • sale_date (IsoDate | None)
  • sale_date_range (InvoiceAddSaleDateRangeInput | None)
  • due_date (IsoDate | None)
  • no_vat (bool | None)
  • cash_basis (bool | None)
  • profit_margin_type (str | None)
  • exempt_vat_basis (str | None)
  • calculated_from_gross (bool | None)
  • is_mpp (bool | None)
  • send_to_contractor (bool | None)
  • recipient_contractor_id (int | None)
  • recipient_role (str | None)
  • recipient_internal_id (str | None)
  • bank_account (InvoiceAddBankAccountInput | None)
  • currency_date (IsoDate | None)
  • issue_person (str | None)
  • issue_to_ksef (bool | None)
  • footer (str | None)
  • payments (list[InvoiceAddPaymentInput])
  • new_transport_vehicle (InvoiceAddNewTransportVehicleInput | None)

Bank

bank

Bank statement resource models.

Saldeo's bank-statement responses include rich nested data — matched contractors, dimensions, settled invoices. These models surface the headline fields; reach for the lower-level client for raw XML when needed.

BankOperation pydantic-model

One transaction inside a bank statement.

Kept deliberately shallow — Saldeo nests dimensions, settlements, and matched contractors in here. Surface the headline fields; callers who need the raw XML can hit the client directly.

Fields:

  • account_number (str | None)
  • operation_type (str | None)
  • operation_date (str | None)
  • accounting_date (str | None)
  • description (str | None)
  • value (str | None)
  • debit_credit (str | None)
  • currency (str | None)
  • is_approved (bool)
  • is_refund (bool)

Personnel

personnel

Personnel resource models — employees and personnel documents.

EmployeeContractInput pydantic-model

One <CONTRACT> row inside an EmployeeAddInput.

Fields:

  • type (ContractType)
  • position (str | None)
  • end_date (IsoDate | None)

EmployeeAddInput pydantic-model

One <EMPLOYEE> row for employee.add (P03).

The XSD enforces a choice rule: either employee_id is set (update an existing employee, all other fields optional) or all of acronym + first_name + last_name are set (create a new one). Mixing them — providing employee_id plus a partial set of name fields — works for updates: acronym / first_name / last_name are optional in the update branch. Saldeo enforces the rest server-side.

Fields:

  • employee_id (int | None)
  • acronym (str | None)
  • first_name (str | None)
  • last_name (str | None)
  • parents_names (str | None)
  • birth_date (IsoDate | None)
  • pesel (Pesel | None)
  • nip (Nip | None)
  • id_card_number (str | None)
  • bank_account_number (str | None)
  • email (str | None)
  • telephone_number (str | None)
  • address (str | None)
  • work_begin_date (IsoDate | None)
  • medical_test_date (IsoDate | None)
  • bhp_expiry_date (IsoDate | None)
  • department (str | None)
  • comments (str | None)
  • inactive (bool | None)
  • contracts (list[EmployeeContractInput])

PersonnelDocumentAddInput pydantic-model

One <PERSONNEL_DOCUMENT> row for personnel_document.add (P04).

Required: year, month, document_type, attachment. Saldeo accepts up to 50 personnel documents per request.

Fields:

  • year (Year)
  • month (Month)
  • document_type (PersonnelDocumentType)
  • attachment (Attachment)
  • employee_id (int | None)
  • number (int | None)
  • document_name (str | None)
  • description (str | None)
  • date_of_duty (IsoDate | None)
  • mark_when_date_of_duty_expired (bool | None)
  • notification_date (IsoDate | None)

Catalog

catalog

Catalog inputs — categories, registers, payment methods, dimensions, articles, fees.

These are the static reference data Saldeo uses to classify documents. None of these endpoints have a useful read counterpart in this server today, so the file holds only *Input models for the corresponding *.merge write endpoints.

CategoryInput pydantic-model

One category for category.merge (SS09).

Fields:

  • name (str)
  • category_program_id (str | None)
  • description (str | None)

PaymentMethodInput pydantic-model

One payment method for payment_method.merge (SS11).

Fields:

  • name (str)
  • payment_method_program_id (str | None)
  • payment_method_id (int | None)

RegisterInput pydantic-model

One register for register.merge (SS10).

Fields:

  • name (str)
  • register_program_id (str | None)
  • register_id (int | None)

DescriptionInput pydantic-model

One description for description.merge (SS14).

Fields:

  • value (str)
  • program_id (str | None)

DimensionValueInput pydantic-model

One value option for an ENUM-type dimension.

Fields:

  • code (str)
  • description (str | None)

DimensionInput pydantic-model

One dimension for dimension.merge (SS12).

type controls how the dimension is rendered: ENUM uses the values list as a fixed enumeration; NUM/LONG_NUM/DATE accept free-form values.

Fields:

  • code (str)
  • name (str)
  • type (Literal['ENUM', 'NUM', 'LONG_NUM', 'DATE'])
  • values (list[DimensionValueInput])

ArticleInput pydantic-model

One article for article.merge (SS21).

Fields:

  • name (str)
  • article_program_id (str | None)
  • code (str | None)
  • unit (str | None)
  • pkwiu (str | None)
  • for_documents (bool | None)
  • for_invoices (bool | None)
  • foreign_codes (list[ForeignCodeInput])

FeeInput pydantic-model

One fee row for fee.merge (SSK04). Always nested under a folder.

Fields:

  • type (str)
  • value (str)
  • maturity (IsoDate)
  • program_id (str | None)
  • description (str | None)

Financial balance

financial_balance

Financial balance model — accounting-firm monthly aggregates.

FinancialBalanceVATInput pydantic-model

<VAT> block inside a FinancialBalanceMergeInput.

Fields:

  • value (str)
  • value_to_shift (str | None)

FinancialBalanceMergeInput pydantic-model

One financial_balance.merge request body (SSK01).

A single (year, month) folder receives at most one balance record, optionally with income / cost / VAT amounts. attachments carries the optional <ATTACHMENTS> branch from the spec — useful for attaching the source spreadsheet or scanned report.

Fields:

Accounting close

accounting_close

Accounting-firm close models — declarations and assurances.

Both endpoints (SSK02 declaration.merge, SSK03 assurance.renew) share the same skeleton: a (year, month) folder, a list of items, each item with optional metadata + an optional list of attachments. The detail blocks differ — declarations carry tax periods, assurances carry ZUS reports discriminated by TYPE.

CloseAttachmentInput pydantic-model

One <ATTACHMENT> entry inside a tax / assurance ATTACHMENTS list.

Pairs an Attachment (path → base64) with the metadata Saldeo wants in the XML: type, display name, optional description fields.

Fields:

  • type (CloseAttachmentType)
  • name (str)
  • attachment (Attachment)
  • description (str | None)
  • short_description (str | None)

TaxDetailsInput pydantic-model

<TAX_DETAILS> block inside a DeclarationTaxInput.

Fields:

  • type (str)
  • period (str)
  • period_type (PeriodType)
  • deadline (IsoDate)
  • tax_value (str)
  • correction_no (str | None)
  • description (str | None)

DeclarationTaxInput pydantic-model

One <TAX> row inside DeclarationMergeInput.taxes.

Fields:

DeclarationMergeInput pydantic-model

One declaration.merge request body (SSK02).

Folders are 1:1 with calendar months. Provide every tax declaration entry that should be created or updated in the folder; Saldeo answers per-tax with MERGED (existed) or CREATED (new).

Fields:

AssuranceEmployeesDetailsInput pydantic-model

<ASSURANCE_DETAILS> for TYPE=EMPLOYEES — ZUS-51 to ZUS-54 totals.

Fields:

  • type (Literal['EMPLOYEES'])
  • period (str)
  • deadline (IsoDate)
  • zus_51 (str | None)
  • zus_52 (str | None)
  • zus_53 (str | None)
  • zus_54 (str | None)

AssurancePersonalDetailsInput pydantic-model

<ASSURANCE_DETAILS> for TYPE=PERSONAL — single employee.

Fields:

  • type (Literal['PERSONAL'])
  • last_name (str)
  • first_name (str)
  • person_id_type (PersonIdType)
  • person_id (str)
  • period (str)
  • deadline (IsoDate)
  • person_code (str | None)
  • zus_51 (str | None)
  • zus_52 (str | None)
  • zus_53 (str | None)
  • zus_54 (str | None)

AssuranceCompanyDetailsInput pydantic-model

<ASSURANCE_DETAILS> for TYPE=COMPANY — owner contributions.

Fields:

  • type (Literal['COMPANY'])
  • period (str)
  • deadline (IsoDate)
  • zus_contribution (str | None)
  • zus_excess_payment (str | None)
  • zus_description (str | None)

AssurancePartnerDetailsInput pydantic-model

<ASSURANCE_DETAILS> for TYPE=PARTNER — single partner.

Fields:

  • type (Literal['PARTNER'])
  • last_name (str)
  • first_name (str)
  • person_id_type (PersonIdType)
  • person_id (str)
  • period (str)
  • deadline (IsoDate)
  • person_code (str | None)
  • zus_contribution (str | None)
  • zus_underpayment (str | None)
  • zus_description (str | None)

AssuranceItemInput pydantic-model

One <ASSURANCE> row inside AssuranceRenewInput.assurances.

Saldeo's spec uses a TYPE-discriminated union for the details block: EMPLOYEES (totals), PERSONAL (one employee), COMPANY (owner), or PARTNER (one partner). Pick the matching *DetailsInput subclass.

Fields:

  • assurance_program_id (str)
  • details (AssuranceDetailsInput)
  • attachments (list[CloseAttachmentInput])

AssuranceRenewInput pydantic-model

One assurance.renew request body (SSK03).

Folders are 1:1 with calendar months. Saldeo answers per-assurance with RENEWED (existed) or CREATED (new).

Fields: