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

# Post a ledger entry

> Creates and posts a single new ledger entry. If a tax code is given, Infinity books the VAT alongside the entry and reports it in the `vat` property of the returned entry.

## Creating a new ledger entry

For example, the following payload will create a new ledger entry for the amount of CHF 120.50, with the VAT booked alongside it because of the `UN81` tax code:

```json theme={null}
{
  "date": "2025-01-01",
  "description": "Einnahme von 120.50 CHF",
  "debitAccount": 1020,
  "creditAccount": 3200,
  "amount": 12050,
  "currency": "CHF",
  "taxCode": "UN81"
}
```

The `taxCode` accepts the statutory tax codes as well as the organisation's own simplified codes (Saldosteuersatz) such as `SS53`, and the empty string for an entry without VAT. Use [list available tax codes](/api/accounting/tax-codes) to find out which codes the organisation can use on a given date.

The response contains the posted entry as `ledgerEntry`, in the same shape as when you [find ledger entries](/api/accounting/find) — including its `id`, and its `vat` object with the VAT amount and accounts that were booked. The individual transactions behind the entry are not listed separately.

## Foreign currency entries

To post an entry in another currency, send `amount` in that currency and set `currency` accordingly. The currency has to be enabled in the organisation. Infinity converts the amount to CHF, and the entry returned in the response reports the original amount in its `fx` object.

You can either give the exchange rate as the value of one unit of the foreign currency in CHF:

```json theme={null}
{
  "date": "2025-01-01",
  "description": "Beratung",
  "debitAccount": 1020,
  "creditAccount": 3200,
  "amount": 10000,
  "currency": "EUR",
  "exchangeRate": 0.95
}
```

Or you can give the CHF amount that should be booked as `baseAmount`, for example the amount your bank actually credited. Infinity then derives the exchange rate from it:

```json theme={null}
{
  "date": "2025-01-01",
  "description": "Beratung",
  "debitAccount": 1020,
  "creditAccount": 3200,
  "amount": 10000,
  "currency": "EUR",
  "baseAmount": 9483
}
```

* If neither is given, the exchange rate set for the currency in Infinity on that date is used.
* Sending `exchangeRate` and `baseAmount` together is rejected with `400 Bad Request` and the error code `general/missing-fields`, listing both fields in `invalidFields`.
* Sending `baseAmount` for an entry in CHF is rejected the same way, listing `baseAmount`.

## Retrying safely with idempotency keys

If a request fails or times out, you may not know whether the ledger entry was posted. To retry safely without creating duplicate bookings, provide a unique `Idempotency-Key` header (for example a UUID) with your request:

```bash theme={null}
Idempotency-Key: 4cbe4d8c-8952-46a5-8bcd-1b4a67d0c496
```

When you retry a request with the same key and payload, the API returns the status and response of the original request – including the ledger entry it posted – instead of posting the entry again.

* Keys are scoped to your organisation and API key.
* Keys are retained for 24 hours. After that, a key can be used again and will post a new entry.
* Reusing a key with a different payload returns `409 Conflict` with error code `rest-api/idempotency-key-payload-mismatch`.
* While a request is still being processed, concurrent requests with the same key return `409 Conflict` with error code `rest-api/idempotency-key-request-in-progress`.
* If a request fails, its key is released, so the same key can be used to retry.

<Tip>
  Generate a new idempotency key for every new ledger entry, and reuse it only
  when retrying the same request.
</Tip>


## OpenAPI

````yaml POST /v1/ledger-entries
openapi: 3.1.0
info:
  title: infinity.swiss Open API
  version: '1.0'
  summary: ''
servers:
  - url: https://api.infinity.swiss
security:
  - apiKey: []
paths:
  /v1/ledger-entries:
    post:
      tags: []
      summary: Post a ledger entry
      description: >-
        Creates and posts a single new ledger entry. If a tax code is given,
        Infinity books the VAT alongside the entry and reports it in the `vat`
        property of the returned entry.
      operationId: post-unreviewed-ledger-entry-v1
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              x-examples:
                Example 1:
                  date: '2025-01-01'
                  description: Einnahme von 120.50 CHF
                  debitAccount: 1020
                  creditAccount: 3200
                  amount: 12050
                  currency: CHF
                  taxCode: UN81
              required:
                - date
                - description
                - debitAccount
                - creditAccount
                - amount
              properties:
                date:
                  type: string
                  description: >-
                    The date of the ledger entry in YYYY-MM-DD format.


                    The transaction date must be within an editable period (e.g.
                    adding transactions in a closed VAT period or outside of an
                    open fiscal year is not allowed).
                  format: date
                  example: '2025-01-30'
                description:
                  type: string
                  description: The single-line text line for the ledger entry.
                  maxLength: 128
                  minLength: 1
                debitAccount:
                  type: integer
                  description: >-
                    The account number of the debit account of this ledger
                    entry. An account with this account number must exist to
                    post the transaction.
                  minimum: 1000
                  maximum: 9999
                creditAccount:
                  type: integer
                  minimum: 1000
                  maximum: 9999
                  description: >-
                    The account number of the credit account of this ledger
                    entry. An account with this account number must exist to
                    post the transaction.
                amount:
                  type: integer
                  minimum: 1
                  example: 12030
                  description: The gross transaction amount in cents (e.g. 12030 = 120.30).
                currency:
                  type: string
                  minLength: 3
                  maxLength: 3
                  description: >-
                    The 3-character alphanumeric currency code (ISO 4217) for
                    the amount of this transaction. Must be a currency code of a
                    currency that is enabled in this organisation. Defaults to
                    the primary accounting currency of Infinity, which currently
                    is always `CHF`.
                  default: CHF
                  example: EUR
                exchangeRate:
                  type: number
                  x-stoplight:
                    id: lub9vdj2vfhuv
                  description: >-
                    A decimal number representing the conversion rate as the
                    rate of the foreign basis unit = X CHF. For example, the
                    exchange rate is 0.98 for Euro if 1 EUR = 0.98 CHF. Not
                    allowed to be zero or negative.


                    If not provided, defaults to the applicable exchange rate
                    set for the currency in Infinity.
                  exclusiveMinimum: 0
                baseAmount:
                  type: integer
                  minimum: 1
                  example: 9800
                  description: >-
                    The amount of this ledger entry in CHF, in cents, as an
                    alternative to `exchangeRate`. The exchange rate is derived
                    from `amount` and `baseAmount`, so that exactly this CHF
                    amount is booked.


                    Only allowed for ledger entries in a foreign currency.
                    Sending `baseAmount` together with `exchangeRate`, or
                    sending it for an entry in CHF, is rejected with `400 Bad
                    Request` and the error code `general/missing-fields`.
                taxCode:
                  oneOf:
                    - title: Statutory tax code
                      description: >-
                        A statutory tax code, such as `UN81` for the normal
                        rate.
                      enum:
                        - UN81
                        - UN77
                        - UR26
                        - UR25
                        - US38
                        - US37
                        - UO81
                        - UO77
                        - BZB81
                        - BZB77
                        - BZM81
                        - BZM77
                        - VM81
                        - VM38
                        - VM26
                        - VB81
                        - VB38
                        - VB26
                        - VM77
                        - VM37
                        - VM25
                        - VB77
                        - VB37
                        - VB25
                        - ES81
                        - ES26
                        - ES77
                        - ES25
                        - UNO
                        - UEX
                        - ULA
                        - ZOLLM
                        - ZOLLB
                    - title: Simplified tax code
                      description: >-
                        One of the organisation's own simplified tax codes
                        (Saldosteuersatz), such as `SS53` or `SS06R`. Only
                        accepted if the organisation accounts for VAT with the
                        simplified method.
                      type: string
                      pattern: ^SS\d{2}[RS]?$
                      example: SS53
                    - title: No VAT
                      description: The empty string posts the ledger entry without VAT.
                      enum:
                        - ''
                  description: >-
                    The VAT tax code applicable for this ledger entry. Based on
                    the provided tax code, the ledger entry will be
                    appropriately split into a net amount transaction and a VAT
                    debt transaction.


                    Which codes are accepted depends on the VAT settings of the
                    organisation and on the date of the entry. Use [GET
                    /v1/tax-codes](/api/accounting/tax-codes) to list the codes
                    available for a date.


                    If unset, null, or "", no VAT will be applied to this
                    transaction.


                    See [“Liste der
                    MWST-Codes“](https://docs.infinity.swiss/de/docs/accounting/vat/tax-codes)
                    for details.
                  example: UN81
        description: Provide a single ledger entry to create.
      responses:
        '201':
          description: The ledger entry was posted successfully.
          content:
            application/json:
              schema:
                type: object
                required:
                  - ledgerEntry
                properties:
                  ledgerEntry:
                    $ref: '#/components/schemas/LedgerEntry'
        '400':
          description: >-
            A bad request is thrown if the provided ledger entry payload is
            invalid.
          content:
            application/json:
              schema:
                type: object
                required:
                  - code
                properties:
                  code:
                    type: string
                    x-stoplight:
                      id: mn0l8j4nbiqtl
                    description: >-
                      The specific error code for this request.

                      May be:

                      - `general/missing-fields`, also when `baseAmount` is
                      combined with `exchangeRate`, or when `baseAmount` is used
                      for an entry in CHF

                      - `general/malformed-request`

                      - `general/zero-or-negative-amount-not-allowed`

                      - `general/negative-amount-not-allowed`

                      - `general/invalid-date`

                      - `general/input-too-long`
                  invalidFields:
                    type: array
                    x-stoplight:
                      id: grq90gsll1pvg
                    uniqueItems: true
                    description: A list of the fields which were invalid, if applicable.
                    items:
                      x-stoplight:
                        id: lxm92y2xhucrj
                      type: string
                      example: description
        '401':
          $ref: '#/components/responses/Unauthorised'
        '403':
          description: >-
            A forbidden error is thrown when posting this ledger entry is
            disallowed.
          headers: {}
          content:
            application/json:
              schema:
                type: object
                properties:
                  code:
                    type: string
                    x-stoplight:
                      id: yctwlfywky9e3
                    description: >-
                      The specific error code for this request.


                      The following errors may be thrown if the transaction date
                      is outside of a valid, editable fiscal year:

                      - `fiscal-year/not-found`

                      - `fiscal-year/closed`


                      The following error may be thrown if the transaction date
                      falls within a settled, non-editable VAT period:

                      - `transactions/from-closed-vat-period`


                      The following errors may be thrown in cases where the tax
                      code can not be applied correctly:

                      - `vat/invalid-tax-code`

                      - `vat/no-tax-applicable-account`
        '404':
          description: >-
            A 404 error may be received when attempting to book to an account
            which does not exist in the organisation.
          content:
            application/json:
              schema:
                type: object
                properties:
                  code:
                    type: string
                    x-stoplight:
                      id: a9im42ie7thqq
                    description: |-
                      The specific error code for this request.
                      Can be:
                      - `ledger/account-not-found`
        '409':
          $ref: '#/components/responses/IdempotencyConflict'
components:
  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: false
      schema:
        type: string
        minLength: 1
        maxLength: 200
      description: >-
        A unique key that makes this request idempotent, for example a UUID. If
        a request fails or times out, it can safely be retried with the same key
        without creating a duplicate: a retry with the same key and payload
        returns the status and response of the original request, including the
        resource it created.


        Keys are scoped to your organisation and API key, and are retained for
        24 hours. Reusing a key with a different payload returns `409 Conflict`.
        While a request is still being processed, other requests with the same
        key also return `409 Conflict`.
  schemas:
    LedgerEntry:
      title: LedgerEntry
      type: object
      description: >-
        A ledger entry is a single booking in the ledger: one amount, posted
        from a debit to a credit account on a date.


        Infinity books the VAT of an entry as a separate VAT transaction
        internally, but the API never returns it on its own: it is folded into
        the `vat` property of the entry it belongs to.
      required:
        - id
        - date
        - description
        - debitAccount
        - creditAccount
        - amount
        - netAmount
        - currency
        - source
        - reviewState
        - receiptIds
        - createdAt
        - updatedAt
      properties:
        id:
          type: string
          description: >-
            A unique hex identifier for the ledger entry. It stays the same when
            the entry is edited.
          example: 682338d9e9500b3ffe4baa5a
        date:
          type: string
          format: date
          description: The date of the ledger entry in YYYY-MM-DD format.
          example: '2025-02-05'
        description:
          type: string
          description: The single text-line description of the ledger entry.
          example: Consulting revenue
        debitAccount:
          type: integer
          minimum: 1000
          maximum: 9999
          description: The account number of the debit account of the ledger entry.
          example: 1020
        creditAccount:
          type: integer
          minimum: 1000
          maximum: 9999
          description: The account number of the credit account of the ledger entry.
          example: 3400
        amount:
          type: integer
          description: >-
            The gross amount of the ledger entry in cents (e.g. 108100 =
            1081.00), in CHF.


            For entries without VAT, this is the same as `netAmount`. It is also
            the same for reverse charge tax codes (acquisition tax), where the
            VAT is booked on top of the entry instead of being contained in it.
          example: 108100
        netAmount:
          type: integer
          description: >-
            The amount in cents that is booked between the debit and the credit
            account, in CHF, without the VAT booked alongside it.
          example: 100000
        currency:
          type: string
          minLength: 3
          maxLength: 3
          description: >-
            The 3-character alphanumeric currency code (ISO 4217) of `amount`
            and `netAmount`. These are always given in the accounting currency,
            which currently is always `CHF`. The currency the entry was posted
            in is reported in `fx`.
          example: CHF
        vat:
          $ref: '#/components/schemas/LedgerEntryVat'
          description: >-
            The VAT booked with this entry. Present for every entry that has a
            tax code.
        fx:
          $ref: '#/components/schemas/LedgerEntryFx'
          description: >-
            The original amount of this entry in a foreign currency. Present for
            every entry that was posted in a currency other than CHF.
        source:
          $ref: '#/components/schemas/LedgerEntrySource'
          description: Which part of Infinity this entry originates from.
        reviewState:
          $ref: '#/components/schemas/LedgerEntryReviewState'
          description: >-
            Whether a person stands behind this entry, or AI accounting posted
            it and it still awaits review.
        receiptIds:
          type: array
          description: >-
            The ids of the receipts attached to this ledger entry, in the order
            in which they were attached.
          items:
            type: string
            example: 686f1b2ce9500b3ffe4bbc71
        reversedBy:
          type: string
          description: >-
            The id of the ledger entry that reverses this entry (Storno). Only
            present if the entry has been reversed; such an entry can no longer
            be deleted.
          example: 6851f42ae9500b3ffe4bb0c4
        reverses:
          type: string
          description: >-
            The id of the ledger entry that this entry reverses. Only present
            for entries with the source `reversal`.
          example: 682338d9e9500b3ffe4baa5a
        createdAt:
          type: string
          format: date-time
          description: The time at which the ledger entry was created.
          example: '2025-02-05T09:12:44.000Z'
        updatedAt:
          type: string
          format: date-time
          description: >-
            The time at which the ledger entry was last changed. Use it together
            with the `updatedSince` filter to synchronise changes incrementally.
          example: '2025-02-05T09:12:44.000Z'
    LedgerEntryVat:
      title: LedgerEntryVat
      type: object
      description: >-
        The VAT that was booked with a ledger entry, as it stands in the ledger.


        With reverse charge tax codes (acquisition tax, `BZB…` and `BZM…`), the
        VAT is booked on top of the entry rather than contained in it: the
        `amount` of the entry equals its `netAmount`, and the VAT booking runs
        between two VAT accounts.
      required:
        - taxCode
        - amount
      properties:
        taxCode:
          type: string
          description: >-
            The tax code of the ledger entry, either a statutory code such as
            `UN81`, or one of the organisation's own simplified codes
            (Saldosteuersatz) such as `SS53`.
          examples:
            - UN81
            - SS53
        rate:
          type: number
          description: >-
            The VAT rate in percent that was actually booked, e.g. `8.1`. With
            the simplified method (Saldosteuersatz), this is the organisation's
            simplified rate, e.g. `5.3`.


            Absent only for tax codes that are no longer defined.
          example: 8.1
        statutoryRate:
          type: number
          description: >-
            The statutory VAT rate in percent that the tax code stands for, e.g.
            `8.1`. Only present for simplified tax codes (Saldosteuersatz),
            where the rate charged to the customer differs from the rate booked.
          example: 8.1
        amount:
          type: integer
          description: >-
            The VAT amount in cents that was booked, in CHF.


            `0` if no VAT booking was made after all, for example because the
            VAT amount rounded to zero.
          example: 8100
        debitAccount:
          type: integer
          minimum: 1000
          maximum: 9999
          description: >-
            The account number of the debit account of the VAT booking. Absent
            if no VAT booking was made.
          example: 1020
        creditAccount:
          type: integer
          minimum: 1000
          maximum: 9999
          description: >-
            The account number of the credit account of the VAT booking. Absent
            if no VAT booking was made.
          example: 2200
    LedgerEntryFx:
      title: LedgerEntryFx
      type: object
      description: >-
        The foreign currency details of a ledger entry. Only present if the
        entry has an amount in a foreign currency; the amounts of the entry
        itself are always converted to CHF.
      required:
        - amount
        - currency
      properties:
        amount:
          type: integer
          description: >-
            The gross amount of the ledger entry in cents (e.g. 10000 = 100.00),
            in the foreign currency.
          example: 10000
        currency:
          type: string
          minLength: 3
          maxLength: 3
          description: >-
            The 3-character alphanumeric currency code (ISO 4217) of the foreign
            currency.
          example: EUR
        exchangeRate:
          type: number
          description: >-
            The exchange rate that was used to convert the amount, as the value
            of one unit of the foreign currency in CHF. Absent only for legacy
            entries that were posted without a rate.
          example: 0.95
    LedgerEntrySource:
      title: LedgerEntrySource
      type: string
      description: >-
        Which part of Infinity a ledger entry originates from:

        - `manual`: posted by hand in Infinity, or through this API

        - `customer-invoice`: posted by a customer invoice (Forderung), for
        example its positions, payments, discounts or rebates

        - `vendor-invoice`: posted by a vendor invoice (Kreditor), for example
        its positions or payments

        - `bank`: posted from a synchronised bank transaction in Live Accounting

        - `vat`: posted by a VAT settlement or a VAT payment

        - `closing`: posted when a fiscal year is opened or closed, for example
        accruals, depreciation or the profit appropriation

        - `reversal`: posted to reverse another ledger entry (Storno)

        - `salary`: posted by a salary payment
      enum:
        - manual
        - customer-invoice
        - vendor-invoice
        - bank
        - vat
        - closing
        - reversal
        - salary
      example: manual
    LedgerEntryReviewState:
      title: LedgerEntryReviewState
      type: string
      description: >-
        Whether a person stands behind a ledger entry:

        - `ai-proposed`: AI accounting posted the entry from a synchronised bank
        transaction, and nobody has reviewed it yet. Treat it as provisional:
        reviewing may still change or remove it.

        - `reviewed`: a person posted the entry, or reviewed one that AI
        accounting had posted. Entries posted by hand, through this API, or by
        another part of Infinity are always `reviewed`.
      enum:
        - ai-proposed
        - reviewed
      example: reviewed
  responses:
    Unauthorised:
      description: >-
        An unauthorised request was submitted. You may be using an incorrect or
        expired API token, or are attempting to access a document outside of the
        scope of the token.
      content:
        application/json:
          schema:
            type: object
            properties:
              code:
                type: string
                x-stoplight:
                  id: 08hkw8ukmi2lp
                description: Specific error code
          examples:
            Unauthorised request:
              value:
                code: general/unauthorised
    IdempotencyConflict:
      description: >-
        A conflict is returned when an idempotency key is reused with a
        different payload, or while another request with the same idempotency
        key is still being processed.
      content:
        application/json:
          schema:
            type: object
            properties:
              code:
                type: string
                description: |-
                  The specific error code for this request.
                  May be:
                  - `rest-api/idempotency-key-payload-mismatch`
                  - `rest-api/idempotency-key-request-in-progress`
  securitySchemes:
    apiKey:
      name: x-api-token
      type: apiKey
      in: header
      description: >-
        API token for authentication. Obtain from your Infinity account
        settings.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.