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

# Update Transaction API

> Update a single unlocked Breezing transaction by ID to patch crypto accounting fields without changing other transaction values.



## OpenAPI

````yaml PATCH /transactions/{id}
openapi: 3.1.0
info:
  title: Breezing Public API
  version: 1.0.0
  description: >-
    Crypto accounting API for programmatic access and AI agents. Authenticate
    with an API key using the Authorization header: `Bearer brz_...`
servers:
  - url: https://api.breezing.io/v1
security:
  - BearerAuth: []
paths:
  /transactions/{id}:
    patch:
      tags:
        - Transactions
      summary: Update a single transaction
      description: >-
        Update accounting fields on a single unlocked transaction (partial
        update: only provided fields change). Returns 409 if locked or
        processing.


        FULLY CATEGORIZING A TRANSACTION requires three account fields:

        • "account": the contra (income/expense) account. What was this
        transaction for? (e.g. Sales, Legal Expense, Consulting Revenue). Choose
        based on type, functionName, walletFromName/walletToName context.

        • "assetAccount": the balance-sheet asset account. Where does this token
        sit on the balance sheet? Required in ALL balance sheet modes. If the
        value is "(auto)", Breezing resolves it at sync time from token-level
        mappings (set via assets_update) or rule-based mappings. You can leave
        "(auto)" as-is or override with a specific account code.

        • "feeAssetAccount": the balance-sheet account for the fee portion.
        Always set this field (typically the same account as assetAccount). If
        "(auto)", Breezing resolves it at sync time.


        All three fields accept numeric account codes from the chart of accounts
        (call company_get first). Never pass free-text names like "sales".


        Categorization workflow:

        1. Set "account" (contra account: what was the transaction for?)

        2. Check assetAccount. If "(auto)", leave as-is when token-level
        mappings exist (Token View), or set explicitly for Wallet/Combined View.

        3. Set feeAssetAccount; always set this field (same account as
        assetAccount in most cases).

        4. Optionally set "accountingDescription" for journal entry context.

        Do NOT automatically change status. Leave it for the user to decide when
        the transaction is ready for reconciliation.


        How balanceSheetSetup affects asset accounts:

        • "token" (Token View) → asset accounts are managed at the token level
        via assets_update. Transactions show "(auto)" which resolves to the
        token's mapped account at sync time. assets_update sets the mapping;
        "(auto)" on transactions references it. They are not competing.

        • "wallet" (Wallet View) → asset accounts are set per-transaction,
        usually via Rules. Each wallet maps to one GL account.

        • "wallet-token" (Combined View) → asset accounts are set
        per-transaction, usually via Rules with wallet+token conditions.


        Other fields:

        • "type": freeform label, safe to overwrite. System may set values like
        "transaction" or "internal" during import, but these are just labels,
        not business logic. The system uses the isInternal boolean (not type)
        for internal transfer logic. Set to any descriptive value.

        • "status": lifecycle: notStarted (new/uncategorized) → reviewRequired
        (flagged for client review via the Client Review workflow) → reconciled
        (categorized and verified, ready for sync) → manuallyReconciled
        (manually confirmed) → paid (synced to Xero/QuickBooks/Bexio). Do not
        change status automatically; leave for the user.

        • "accountingDescription": syncs as the journal entry description in
        Xero/QuickBooks/Bexio. Use for invoice numbers, vendor names, or payment
        references. Distinct from "note" which is internal only.

        • "isSpam": mark airdrop/scam tokens as spam to hide them. Breezing
        auto-detects many common spam tokens; use this for any missed.

        • "vat": freeform string that syncs to journal entries. Must match a tax
        rate name configured in the user's Xero/QuickBooks/Bexio account (e.g.
        "Output 8.1% VAT", "Tax Exempt"). Default is "no-vat". No validation, so
        invalid codes may cause sync errors.

        • "skipNgl" / "skipNglReason": set skipNgl=true to exclude this
        transaction from net gain/loss (NGL) and tax calculations (e.g.
        wrapping, staking, bridging). skipNglReason is REQUIRED when
        skipNgl=true. Cannot be set on internal transfers (isInternal=true).
        Setting skipNgl does NOT recalculate NGL; call POST /ngl/calculate
        afterward to recompute net.

        • "qboClass" / "xeroTrackingCategory": accounting-software tracking
        dimensions. Set the QuickBooks class id (from POST /qbo/classes/refresh)
        or the Xero tracking category option id (from POST
        /xero/categories/refresh). Only relevant when that platform is linked.


        IMPORTANT, internal transfers and exchange trades:

        • If isInternal=true (system-computed), the transaction is a transfer
        between the user's own wallets. Recommend using Breezing's Auto Apply
        Account feature instead of manual assignment.

        • If exchangeId is a non-null number (system-set), the transaction is an
        exchange trade. Also recommend Auto Apply Account.

        • Note: isInternal and type are independent. A transaction can have
        isInternal=false with type="internal". The system uses isInternal for
        business logic, not type.
      parameters:
        - schema:
            type: string
            description: Transaction ID
            example: '12345'
          required: true
          description: Transaction ID
          name: id
          in: path
        - schema:
            type: string
            description: >-
              Organization ID. Use GET /v1/companies to discover available
              org/company pairs.
            example: '1'
          required: true
          description: >-
            Organization ID. Use GET /v1/companies to discover available
            org/company pairs.
          name: orgId
          in: query
        - schema:
            type: string
            description: >-
              Company ID. Use GET /v1/companies to discover available companies
              and their access levels.
            example: '1'
          required: true
          description: >-
            Company ID. Use GET /v1/companies to discover available companies
            and their access levels.
          name: companyId
          in: query
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PatchTransactionBody'
      responses:
        '200':
          description: Transaction updated successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - true
                  data:
                    type: object
                    properties:
                      updated:
                        type: integer
                    required:
                      - updated
                required:
                  - success
                  - data
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - false
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                      message:
                        type: string
                    required:
                      - code
                      - message
                required:
                  - success
                  - error
        '401':
          description: Invalid or missing API key
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - false
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                      message:
                        type: string
                    required:
                      - code
                      - message
                required:
                  - success
                  - error
        '403':
          description: >-
            API key has no access to this company, has read-only access where
            write was required, or the company subscription is inactive
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - false
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                      message:
                        type: string
                    required:
                      - code
                      - message
                required:
                  - success
                  - error
        '404':
          description: Transaction not found
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - false
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                      message:
                        type: string
                    required:
                      - code
                      - message
                required:
                  - success
                  - error
        '409':
          description: Transaction is locked or currently processing
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - false
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                      message:
                        type: string
                    required:
                      - code
                      - message
                required:
                  - success
                  - error
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    enum:
                      - false
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                      message:
                        type: string
                    required:
                      - code
                      - message
                required:
                  - success
                  - error
      security:
        - BearerAuth: []
components:
  schemas:
    PatchTransactionBody:
      type: object
      properties:
        account:
          type: string
          nullable: true
          description: >-
            Account code (numeric string). The contra (income/expense) account:
            what was this transaction for? (e.g. Sales, Legal Expense,
            Consulting Revenue). IMPORTANT: Always call company_get first to
            retrieve the chart of accounts, find the account by name, and use
            its "code" field. Never pass a free-text name like "sales".
        assetAccount:
          type: string
          nullable: true
          description: >-
            Asset account code (numeric string). The balance-sheet account for
            the token in this transaction. Required in ALL balance sheet modes.
            If the current value is "(auto)", Breezing resolves it at sync time
            from token-level or rule-based mappings. You can leave it or
            override with a specific code. IMPORTANT: Always call company_get
            first to retrieve the chart of accounts and use the numeric code.
        feeAssetAccount:
          type: string
          nullable: true
          description: >-
            Fee asset account code (numeric string). The balance-sheet account
            for the fee portion. Same rules as assetAccount: required in ALL
            balance sheet modes. If "(auto)", Breezing resolves it at sync time.
            IMPORTANT: Always call company_get first to retrieve the chart of
            accounts and use the numeric code.
        status:
          type: string
          enum:
            - notStarted
            - reviewRequired
            - reconciled
            - manuallyReconciled
            - paid
            - synced
          description: >-
            Transaction status lifecycle: notStarted (new/uncategorized) →
            reviewRequired (flagged for client review; client sees these in the
            Client Review workflow) → reconciled (categorized and verified) →
            manuallyReconciled (manually confirmed) → paid (synced to accounting
            software). Set to reviewRequired when the accountant needs the
            client to clarify a transaction.
        type:
          type: string
          nullable: true
          description: >-
            Transaction type as a freeform label, safe to overwrite. System may
            set values like "transaction" or "internal" during import, but these
            are just labels, not business logic. The isInternal boolean controls
            actual internal transfer logic. Set to any descriptive value:
            "Opening Balance", "Staking Reward", "Payment", etc.
        note:
          type: string
          nullable: true
          description: >-
            User note. Internal only, not synced to accounting software. Use
            accountingDescription for text that should appear in journal
            entries.
        accountingDescription:
          type: string
          nullable: true
          description: >-
            Description that syncs as the journal entry description in
            Xero/QuickBooks/Bexio. Use for invoice references, vendor names, or
            transaction context that should appear in the accounting software.
            Distinct from "note" which is internal only.
        vat:
          type: string
          nullable: true
          description: >-
            VAT or sales tax code as a freeform string that syncs to journal
            entries. Must match a tax rate name configured in the user's
            Xero/QuickBooks/Bexio account (e.g. "Output 8.1% VAT", "Tax
            Exempt"). Default is "no-vat". No validation, so invalid codes may
            cause sync errors.
        isSpam:
          type: boolean
          description: >-
            Spam flag. Set true to hide airdrop/scam tokens from the main view
            and prevent syncing to accounting software. Breezing auto-detects
            many spam tokens; use this for any it missed.
        extraLabel:
          type: string
          nullable: true
          description: >-
            Extra label: freeform text for custom tagging or grouping, visible
            in Breezing reports.
        skipNgl:
          type: boolean
          description: >-
            Skip net gain/loss. When true, realized gain/loss is zeroed for this
            transaction (excluded from NGL and tax calculations). Use for
            non-taxable movements like wrapping, staking, or bridging. Requires
            skipNglReason when set to true. Cannot be set on internal transfers
            (isInternal=true). Setting this does NOT recalculate NGL
            automatically; run POST /ngl/calculate afterward to recompute net.
        skipNglReason:
          type: string
          nullable: true
          description: >-
            Reason net gain/loss is skipped (e.g. "Wrapping", "Staking", "Bridge
            transfer"). Required when skipNgl is set to true.
        qboClass:
          type: string
          nullable: true
          description: >-
            QuickBooks Online class ID. Syncs as the class on the journal entry
            in QuickBooks. Use the "id" returned by the QuickBooks classes
            refresh endpoint (call it first to retrieve valid class IDs). Only
            relevant when QuickBooks is linked.
        xeroTrackingCategory:
          type: string
          nullable: true
          description: >-
            Xero tracking category option ID. Syncs as the tracking category on
            the journal entry in Xero. Use the "id" returned by the Xero
            categories refresh endpoint (call it first to retrieve valid option
            IDs). Only relevant when Xero is linked.

````