> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lastaccountingcompany.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Send an e-invoice

> Issues a `maventa_einvoice` draft and transmits it over the e-invoice network: allocates the invoice number, stores the invoice, books the sale when LAC keeps the ledger, and queues the Finvoice send. For a partner-profile draft, the tenant's Maventa connection is only the material-handler transport: the partner stays the Finvoice seller and payment beneficiary, receives a bookkeeping PDF copy, and the invoice has no tenant ledger effect. The e-invoice network is the only buyer-delivery channel LAC transmits on. A partner-profile send also emails its seller a bookkeeping copy. Drafts on any other channel are refused with 409; `pdf_download` drafts are issued through `POST /invoices/{invoice_id}/finalize` instead. Requires a write-scoped key.



## OpenAPI

````yaml /openapi.yaml post /invoices/{invoice_id}/send
openapi: 3.1.0
info:
  title: LAC Customer API
  version: '2026-07-15'
  description: >
    Last Accounting Company (LAC) is an AI-native accounting firm for Finnish
    SMBs:

    continuous reconciliation, daily close, real-time dashboards, and full Vero
    reporting.

    This API is the same surface the LAC customer portal UI uses. It gives you
    programmatic

    access to your books (read-only general-ledger views), financial statements,
    documents,

    invoicing, payroll, source-system connections, and the message channel to
    Björn, the

    accounting agent.


    ## Authentication


    Every request carries `Authorization: Bearer <token>`. Two token kinds are
    accepted:


    - **Portal API key** (`lac_sk_...`) — minted in portal Settings → API
    access. Keys have a
      scope of `read` or `write`. Read-scoped keys are refused on all mutating methods
      (POST/PATCH/DELETE). Write-scoped keys act as the `operator` role: they can never
      use payroll endpoints (reads included), change company settings, grant access,
      approve or return an invoice, or manage API keys. Payroll and company settings
      require an interactive admin or existing broad approver. Invoice decisions require the matching invoice
      review permission. Write-scoped keys can prepare draft partner
      seller profiles. An interactive company admin must review the evidence and activate
      a profile or change an active profile.
    - **Firebase ID token** — the interactive session token used by the portal
    UI itself.


    API keys are pinned to a single company, so the `customer_id` parameter
    (query string on

    GETs, body field on writes) can always be omitted when authenticating with
    an API key.

    Interactive tokens with access to multiple companies use `customer_id` to
    select one.


    ## Conventions


    - All field names are `snake_case` on the wire.

    - Monetary amounts are **integer cents** (fields suffixed `_cents`).

    - Rates and percentages are **basis points** (fields suffixed
    `_basis_points`;
      10000 = 100%, e.g. Finnish standard VAT 25.5% = 2550).
    - Quantities on invoice lines are decimal strings (e.g. `"1"`, `"2.5"`).

    - Dates are `YYYY-MM-DD`; periods are `YYYY-MM`; ranges accept `YYYY-MM`,
    `YYYY-Qn`,
      `YYYY`, `all`, `this_month`, or `last_6_months`.

    ## Limits


    - Document uploads: at most 20 files and 25 MB per request.

    - Sheet pagination: `limit` is capped at 200 rows per page (0 =
    unpaginated).


    ## Errors


    Errors return a JSON envelope `{"error": "...", "detail": "..."}` with a
    conventional

    HTTP status code (401 missing/invalid token, 403 insufficient scope or role,
    404 not

    found, 422 validation failure).


    More at
    [docs.lastaccountingcompany.com](https://docs.lastaccountingcompany.com).
  contact:
    name: Last Accounting Company
    url: https://docs.lastaccountingcompany.com
servers:
  - url: https://api.app.lastaccountingcompany.com/portal
    description: Production (note the /portal base path).
security:
  - apiKey: []
tags:
  - name: Company
    description: Company profile, identity, overview, and agent status.
  - name: Onboarding
    description: Saved customer onboarding facts, source inventory, and opening statements.
  - name: Books
    description: >-
      Read-only windows into the canonical general ledger: the spreadsheet-style
      Books/VAT sheet, financial statements, and analytics. There is no
      cell-edit or batch-edit API — the books are maintained by LAC. The one
      write here is a row declaration: your answer about a row (no receipt
      exists, private, a split, or a different booking), recorded as evidence
      for Björn.
  - name: Dimensions
    description: >-
      Project, cost-centre, department, and customer-defined reporting lenses
      over posted general-ledger lines. Provider catalogs are read-only; local
      axes and values are available for bank/file-only books.
  - name: Documents
    description: Receipt/invoice/contract uploads and per-file ingest metadata.
  - name: Messages
    description: The chat channel to Björn, the accounting agent.
  - name: Work log
    description: >-
      Append-only work-hours log (date, minutes, note). Hours are records for
      invoicing and payroll evidence; they do not post to the books. Kilometres
      are not logged here — vehicle travel is submitted as an expense claim in
      the portal, where statutory reimbursement rates apply.
  - name: Filings
    description: Filing authorization, review requests, and produced output packages.
  - name: Invoicing
    description: >-
      Sales invoicing — drafts, partner seller profiles, e-invoice sending, PDF
      finalizing, credit notes, reminders, recurring templates, and the
      invoice-customer register. LAC sends buyer invoices on the e-invoice
      network only. A partner-profile invoice also sends its legal seller a
      bookkeeping PDF copy.
  - name: Payroll
    description: >-
      Payroll workspace — employees, tax cards, employer settings, draft runs,
      and payslips. Every payroll operation (reads included) requires an
      interactive admin or existing broad-approver session and is NOT available
      to API keys.
  - name: Payments
    description: >-
      Contextual review and named-human release for source-bound purchase,
      payroll, and reimbursement payments. There is no manual payment composer
      and no bank file: a batch that cannot be delivered directly to the bank
      fails closed rather than becoming the customer's manual task.
  - name: Connections
    description: >-
      Source-system connections (bank, settlement providers, commerce,
      accounting systems, inbox/Gmail, Google Sheets) and service-connection
      requests/confirmations. PayPal consent can start through this API and
      returns a URL that a company admin must open. Other browser-interactive
      consent flows remain portal-only.
  - name: Imports
    description: Historical import runs (e.g. migrated books) and their artifacts.
  - name: API keys
    description: >-
      Manage portal API keys. These endpoints require an interactive admin
      session (Firebase token) and are NOT available to API-key bearers, which
      receive 403.
  - name: Lens
    description: >-
      Typed, display-ready read models over the books: the transactions window
      (full row universe, three-state status, keyset pagination), the per-row
      booking view, data coverage, and the connections catalog.
  - name: Accounting
    description: >-
      The accountant's read models: general ledger, journal entries, context
      cards, the filings strip with previews, and the SQL explorer. Every
      endpoint here requires LAC staff access or the company admin role; other
      bearers receive 403.
paths:
  /invoices/{invoice_id}/send:
    post:
      tags:
        - Invoicing
      summary: Send an e-invoice
      description: >-
        Issues a `maventa_einvoice` draft and transmits it over the e-invoice
        network: allocates the invoice number, stores the invoice, books the
        sale when LAC keeps the ledger, and queues the Finvoice send. For a
        partner-profile draft, the tenant's Maventa connection is only the
        material-handler transport: the partner stays the Finvoice seller and
        payment beneficiary, receives a bookkeeping PDF copy, and the invoice
        has no tenant ledger effect. The e-invoice network is the only
        buyer-delivery channel LAC transmits on. A partner-profile send also
        emails its seller a bookkeeping copy. Drafts on any other channel are
        refused with 409; `pdf_download` drafts are issued through `POST
        /invoices/{invoice_id}/finalize` instead. Requires a write-scoped key.
      operationId: sendInvoice
      parameters:
        - $ref: '#/components/parameters/InvoiceIdPath'
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CustomerIdBody'
      responses:
        '200':
          description: Updated invoice.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PortalInvoice'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: >-
            The draft is not on the e-invoice channel, its VAT treatment needs
            human review, or the company requires invoice approval and this
            draft has none that matches it as written.
components:
  parameters:
    InvoiceIdPath:
      name: invoice_id
      in: path
      required: true
      schema:
        type: string
  schemas:
    CustomerIdBody:
      type: object
      description: Optional company selector for write requests.
      properties:
        customer_id:
          type: string
          description: Target company. Optional for API keys.
    PortalInvoice:
      type: object
      description: >-
        One sales invoice, sales draft, or purchase invoice. Amounts are integer
        cents; interior fields beyond the stable ones vary by status.
      properties:
        id:
          type: string
        status:
          type: string
        delivery_channel:
          type: string
        document_type:
          type: string
          enum:
            - invoice
            - credit_note
        original_invoice_id:
          type: string
        original_invoice_number:
          type: string
        original_invoice_date:
          type: string
          format: date
        correction_reason:
          type: string
        credited_cents:
          type: integer
          format: int64
        paid_cents:
          type: integer
          format: int64
          description: Live allocated payment amount in integer cents.
        open_cents:
          type: integer
          format: int64
          description: Amount still outstanding in integer cents.
        can_cancel_before_sending:
          type: boolean
          description: >-
            True only when this issued Maventa invoice has one queued intent, no
            provider attempt or id, no payment or earlier correction, and an
            active original journal. The write route repeats these checks under
            the outbound and journal locks.
        seller_name:
          type: string
          description: Customer-facing seller name captured for this invoice.
        seller_legal_name:
          type: string
          description: Registered legal seller name captured for this invoice.
        seller_business_id:
          type: string
          description: Seller Business ID captured for this invoice.
        seller_iban:
          type: string
          description: Payment account captured for this invoice.
        seller_profile_id:
          type: string
          description: Partner seller profile id; empty for the tenant's own sale.
        posts_ledger:
          type: boolean
          description: >-
            False for a partner sale. Such an invoice is excluded from this
            company's journal, VAT facts, receivables, aging, and overdue
            controls.
        partner_copy_status:
          type: string
          enum:
            - not_required
            - no_contact_email
            - pending
            - sending
            - sent
            - failed
            - ambiguous
          description: Delivery state of the partner's bookkeeping PDF copy.
        partner_copy_error:
          type: string
          description: Latest partner-copy delivery error.
        pdf_available:
          type: boolean
          description: Whether the exact issued PDF is registered as retained evidence.
        pdf_document_id:
          type: string
          description: Canonical evidence-document id for the issued PDF.
        pdf_sha256:
          type: string
          pattern: ^[0-9a-f]{64}$
          description: SHA-256 of the exact bytes returned by the PDF endpoint.
        pdf_size_bytes:
          type: integer
          format: int64
          description: Size of the retained PDF in bytes.
        approval_status:
          type: string
          enum:
            - none
            - awaiting
            - approved
            - rejected
          description: >-
            Where this draft stands with its approver, for a company whose
            `invoice_approval_policy` is `required`. Meaningful only while the
            row is a draft; an issued invoice carries an empty value because
            approval no longer applies to it. Changing a draft resets this to
            `none`: the approval was for the invoice as written.
        approval_requested_by:
          type: string
          description: Who asked for approval.
        approval_request_id:
          type: string
          pattern: ^[0-9a-f]{32}$
          description: Stable identity of the current approval request.
        approval_decided_by:
          type: string
          description: Which approver approved it or sent it back.
        approval_reason:
          type: string
          description: Why an approver did not approve it.
        approval_created_by:
          type: string
          description: Who created the draft; this person cannot decide it.
        approval_revision:
          type: string
          pattern: ^[0-9a-f]{64}$
          description: Material sales invoice revision that approve or return must echo.
        approval_returned_revision:
          type: string
          pattern: ^[0-9a-f]{64}$
          description: >-
            Material revision that was returned. A new request needs a different
            current revision.
        review_revision:
          type: string
          description: >-
            Current commercial/source review revision of a purchase invoice;
            accounting-only coding is excluded.
        review_next_action:
          type: string
          enum:
            - verify
            - approve
            - returned
            - approved
            - ready_for_payment
            - payment_in_progress
            - paid
            - source_unavailable
            - payment_details_missing
        review_can_decide:
          type: boolean
          description: Whether this person may perform the next purchase review action.
        review_history:
          type: array
          items:
            type: object
            additionalProperties: true
        review_evidence:
          type: array
          items:
            type: object
            required:
              - document_id
              - document_type
              - name
            properties:
              document_id:
                type: string
              document_type:
                type: string
              name:
                type: string
              content_type:
                type: string
        has_original:
          type: boolean
          description: >-
            Whether a retained supplier-invoice source document is available;
            explicit receipt/supporting attachments do not qualify.
        customer:
          $ref: '#/components/schemas/Party'
        lines:
          type: array
          items:
            $ref: '#/components/schemas/InvoiceLine'
      additionalProperties: true
    Party:
      type: object
      description: >-
        An invoicing counterparty (the customer you invoice), with e-invoice
        routing and per-party defaults. Rates in basis points (25.5% = 2550).
      required:
        - name
      properties:
        id:
          type: string
          description: Party id. Include on upsert to update an existing party.
        name:
          type: string
        business_id:
          type: string
          description: Finnish business ID (Y-tunnus), e.g. `1234567-8`.
        vat_number:
          type: string
          description: EU VAT number, e.g. `FI12345678`.
        address_line1:
          type: string
        postal_code:
          type: string
        city:
          type: string
        country_code:
          type: string
          description: ISO 3166-1 alpha-2, e.g. `FI`.
        email:
          type: string
        einvoice_address:
          type: string
          description: E-invoice (verkkolasku) address, e.g. an OVT identifier.
        einvoice_operator:
          type: string
          description: E-invoice operator/intermediator code.
        default_payment_terms_days:
          type: integer
        default_vat_code:
          type: string
        default_vat_rate_basis_points:
          type: integer
          description: Default VAT rate in basis points (25.5% = 2550).
        default_invoice_language:
          type: string
    InvoiceLine:
      type: object
      description: >-
        One invoice line. Money in integer cents; VAT rate in basis points;
        quantity is a decimal string.
      required:
        - description
        - quantity
        - unit_price_cents
        - net_cents
        - vat_cents
        - gross_cents
      properties:
        description:
          type: string
        quantity:
          type: string
          description: Decimal quantity as a string, e.g. `"2.5"`.
        unit_price_cents:
          type: integer
          description: Unit price in integer cents.
        vat_rate_basis_points:
          type:
            - integer
            - 'null'
          description: VAT rate in basis points (25.5% = 2550); null when not applicable.
        vat_code:
          type: string
          description: VAT treatment code.
        net_cents:
          type: integer
          description: Line net amount in integer cents.
        vat_cents:
          type: integer
          description: Line VAT amount in integer cents.
        gross_cents:
          type: integer
          description: Line gross amount in integer cents.
    Error:
      type: object
      description: Standard error envelope.
      properties:
        error:
          type: string
          description: Machine-readable error message.
        detail:
          type: string
          description: Human-readable detail.
  responses:
    Unauthorized:
      description: Missing or invalid bearer token.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Forbidden:
      description: >-
        Insufficient scope or role — e.g. a read-scoped key on a mutating
        method, or an API key on an interactive-session-only endpoint.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      bearerFormat: lac_sk_...
      description: >-
        Portal API key minted in portal Settings → API access. Scope `read` or
        `write`; pinned to one company. Send as `Authorization: Bearer
        lac_sk_...`.

````