Cannot access APIv4 from n8n while v2 works great

Hello,

i am not able to access the API in v4 from n8n while the same request form v2 works with the same setup.

Any ideas?

From HTTP Request

Error code

401

Full message

401 - "{\"error\":\"authentication_required\",\"message\":\"Authentication is required to access this endpoint.\"}"

Request

{ "headers": { "x-api-key": "**hidden**", "accept": "application/json,text/html,application/xhtml+xml,application/xml,text/*;q=0.9, image/*;q=0.8, */*;q=0.7" }, "method": "GET", "uri": "https://mydomainhere.cpt.manager.cloud/api4/balance-sheet-account?Key=01a0e4c9-f459-7f55-8b8c-1dc274daec55", "gzip": true, "rejectUnauthorized": true, "followRedirect": true, "resolveWithFullResponse": true, "sendCredentialsOnCrossOriginRedirect": false, "followAllRedirects": true, "timeout": 300000, "encoding": null, "json": false, "useStream": true }

Api v4 does not accept your existing X-API-KEY.
It uses HTTP Basic Auth instead.

#!/usr/bin/env python3
"""
Fetch a calculated Profit and Loss Statement from Manager.io Cloud via /api4.

Fill in the configuration values below, then run:
    pip install requests
    python manager_pl_report.py

This uses HTTP Basic Auth, not /api2's X-API-KEY. Use a dedicated,
permission-restricted user (not your personal/admin login) scoped to only
this business, with "View" + "Create" permission on Reports > Profit and
Loss Statement (Settings > Users in Manager).

Once you've filled in real credentials below, keep this file private —
don't commit it or share it with anyone.
"""

import sys
from datetime import date

import requests

# ── Configuration — fill these in ────────────────────────────────────────
SUBDOMAIN = ""             # from https://<SUBDOMAIN>.manager.io
USERNAME = ""              # dedicated restricted user — not your admin login
PASSWORD = ""
BUSINESS = ""              # exact business name as shown in Manager

FROM_DATE = date(2026, 1, 1)
TO_DATE = date(2026, 12, 31)
ACCOUNTING_METHOD = 0      # 0 = Accrual Basis, 1 = Cash Basis
# ──────────────────────────────────────────────────────────────────────────

BASE_URL = f"https://{SUBDOMAIN}.manager.io"


def create_profit_and_loss_report(session: requests.Session, from_date: date, to_date: date, accounting_method: int) -> str:
    """Creates a report definition and returns its key (GUID string)."""
    payload = {
        "business": BUSINESS,
        "value": {
            "periods": [
                {"fromDate": from_date.isoformat(), "toDate": to_date.isoformat()}
            ],
            "accountingMethod": accounting_method,
            "accountCodes": False,
            "excludeZeroBalances": False,
        },
    }
    response = session.post(f"{BASE_URL}/api4/profit-and-loss-statement", json=payload)
    response.raise_for_status()
    return response.json()  # the endpoint returns the new key as a raw JSON string


def get_profit_and_loss_view(session: requests.Session, key: str) -> dict:
    """Returns the calculated report: title, columns, hierarchical rows, cells."""
    params = {"business": BUSINESS, "key": key}
    response = session.get(f"{BASE_URL}/api4/profit-and-loss-statement-view", params=params)
    response.raise_for_status()
    return response.json()


def delete_profit_and_loss_report(session: requests.Session, key: str) -> None:
    """Cleans up the throwaway report definition created above."""
    params = {"business": BUSINESS, "key": key}
    response = session.delete(f"{BASE_URL}/api4/profit-and-loss-statement", params=params)
    response.raise_for_status()


def print_report(report: dict) -> None:
    print(report.get("title", "Profit and Loss Statement"))
    for subtitle in report.get("subtitles", []):
        print(f"  {subtitle}")
    print()

    columns = report.get("columns", [])
    header = "Account".ljust(40) + "".join(c["name"].rjust(15) for c in columns)
    print(header)
    print("-" * len(header))

    def print_rows(rows, indent=0):
        for row in rows:
            label = ("  " * indent + row["name"])[:40].ljust(40)
            if row.get("rows"):
                print(label)
                print_rows(row["rows"], indent + 1)
            else:
                cells = row.get("cells") or []
                values = "".join((c.get("text") or "").rjust(15) for c in cells)
                print(label + values)

    print_rows(report.get("rows", []))


def main() -> None:
    if not USERNAME or not PASSWORD:
        sys.exit("Fill in USERNAME and PASSWORD at the top of this file before running.")

    session = requests.Session()
    session.auth = (USERNAME, PASSWORD)

    print(f"Creating P&L report definition for '{BUSINESS}' ({FROM_DATE} to {TO_DATE})...")
    key = create_profit_and_loss_report(session, FROM_DATE, TO_DATE, ACCOUNTING_METHOD)
    print(f"Report key: {key}")

    print("Fetching calculated report...")
    report = get_profit_and_loss_view(session, key)
    print()
    print_report(report)

    delete_profit_and_loss_report(session, key)


if __name__ == "__main__":
    try:
        main()
    except requests.HTTPError as exc:
        status = exc.response.status_code if exc.response is not None else "?"
        body = exc.response.text if exc.response is not None else str(exc)
        print(f"Request failed: {status} {body}", file=sys.stderr)
        sys.exit(1)

You are amazing, thank you so much!!