# Cannot access APIv4 from n8n while v2 works great

**URL:** <https://forum.manager.io/t/cannot-access-apiv4-from-n8n-while-v2-works-great/69808>\
**Category:** Uncategorized\
**Created:** [October 3, 2026, 1:27am UTC](https://forum.manager.io/t/cannot-access-apiv4-from-n8n-while-v2-works-great/69808 "2026-10-03T01:27:48Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![nicolaszein](https://avatars.discourse-cdn.com/v4/letter/n/b77776/32.png) [@nicolaszein](https://forum.manager.io/u/nicolaszein)\
**Post date:** [October 3, 2026, 1:27am UTC](https://forum.manager.io/t/cannot-access-apiv4-from-n8n-while-v2-works-great/69808/1 "2026-10-03T01:27:48Z")

</div>

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

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

```

Request

```auto
{ "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 }

```

---

<div class="post-metadata">

**Author:** ![Mabaega](https://sea1.discourse-cdn.com/flex019/user_avatar/forum.manager.io/mabaega/32/47471_2.png) [@Mabaega](https://forum.manager.io/u/Mabaega)\
**Post date:** [October 3, 2026, 2:17am UTC](https://forum.manager.io/t/cannot-access-apiv4-from-n8n-while-v2-works-great/69808/2 "2026-10-03T02:17:37Z")

</div>

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

```auto
#!/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)

```

---

<div class="post-metadata">

**Author:** ![nicolaszein](https://avatars.discourse-cdn.com/v4/letter/n/b77776/32.png) [@nicolaszein](https://forum.manager.io/u/nicolaszein)\
**Post date:** [October 3, 2026, 2:34am UTC](https://forum.manager.io/t/cannot-access-apiv4-from-n8n-while-v2-works-great/69808/3 "2026-10-03T02:34:25Z")

</div>

You are amazing, thank you so much!!

---

<div class="post-metadata">

**Author:** ![eko](https://avatars.discourse-cdn.com/v4/letter/e/a8b319/32.png) [@eko](https://forum.manager.io/u/eko)\
**Post date:** [October 3, 2026, 7:50am UTC](https://forum.manager.io/t/cannot-access-apiv4-from-n8n-while-v2-works-great/69808/4 "2026-10-03T07:50:22Z")

</div>


