HTTP Request node returns 401 with QuickBooks Online OAuth2 — native QBO nodes work fine with same credential

Describe the problem/error/question

I’m building a workflow that creates QBO sub-customers (projects) from Airtable records. The native QuickBooks Online nodes (Create a Customer, Get Many Customers) authenticate and work perfectly. However, any HTTP Request node using the same QBO OAuth2 credential returns a 401 Authorization Failure, regardless of configuration.

The reason I need the HTTP Request node: the native “Create a Customer” and “Update a Customer” nodes don’t expose the Job, ParentRef, or IsProject fields, which are required by QBO’s API to create/update sub-customers (projects). These fields aren’t available in the node dropdowns or additional fields.

What is the error message (if any)?

401 - {“Fault”:{“Error”:[{“Message”:“Authorization Failure”,“Detail”:“AuthorizationFailure: {0}”,“code”:“120”}],“type”:“AuthorizationFault”}}

What I’ve tried (all result in 401)

  1. HTTP Request node with Predefined Credential Type → QuickBooks Online OAuth2 API → same credential that works on native nodes → 401
  2. Same as above with Send Headers toggled off (letting the predefined credential handle headers automatically) → 401
  3. “Custom QuickBooks Online API Call” (the link at the bottom of the QBO node action picker — creates an HTTP Request node under the hood) → 401
  4. HTTP Request node with Generic Credential Type → OAuth2 API with a freshly created credential using correct Authorization URL (https://appcenter.intuit.com/connect/oauth2), Access Token URL (https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer), same Client ID/Secret from Intuit Developer portal, scope com.intuit.quickbooks.accounting, Authentication set to Header → 401
  5. Reconnected the QBO credential (fresh OAuth token) → 401
  6. Added minorversion=65 query parameter + explicit Content-Type/Accept headers → 401
  7. Tried a Python Code node with helpers.httpRequestWithAuthentication → not supported in Code node sandbox

Information on my n8n setup

  • n8n version: Latest (n8n Cloud)
  • Running n8n via: n8n Cloud
  • Operating system: N/A (Cloud)

The JSON body is correct

The body resolves and formats properly (verified in n8n’s output preview):

{
  "DisplayName": "c_994_19559 || 19559_Aye Garcia LLC_June Contract 2026",
  "Job": true,
  "BillWithParent": true,
  "ParentRef": {
    "value": "4404"
  }
}

The request details in the error output confirm the body is being sent correctly — it’s purely an authentication/token injection issue.

Notes

I found two other posts with the exact same issue (native QBO node works, HTTP Request doesn’t) and neither had a resolution:

One theory is that n8n lowercases the Authorization header to authorization, and QBO’s API may be case-sensitive.

Feature request

If the HTTP Request node auth issue is a known limitation, could the native QuickBooks Online node be updated to expose Job, ParentRef, and IsProject fields in the Create/Update Customer operations? These are standard QBO API fields required for sub-customer (project) management.

This is a known limitation with how n8n’s HTTP Request node handles OAuth2 headers—QBO’s API is strict about header case-sensitivity. Your theory about lowercasing is correct; n8n normalizes headers internally. Workarounds: (1) Try using a generic OAuth2 credential with explicit header mapping if the node allows it. (2) Some users have had success with the MCP Gateway approach (see the MCP Gateway Facade Pattern whitepaper)—it provides stateful credential handling for strict APIs like QBO. (3) Alternatively, request the native QBO node be updated to expose Job, ParentRef, and IsProject fields. For now, feature request is your best bet.

Hi @Cynthia_Valdes

If you want full control over header casing and avoid those limitations, i suggest a code node to make API call directly, something like (the code below is generated by AI so check and adapt it to yours):

const credential = await this.getCredentials(‘quickBooksOAuth2Api’);const token = credential.oauthTokenData?.access_token;const realmId = credential.companyId;
const response = await this.helpers.httpRequest({method: ‘POST’,url: https://quickbooks.api.intuit.com/v3/company/${realmId}/customer?minorversion=65,headers: {‘Authorization’: Bearer ${token},‘Content-Type’: ‘application/json’,‘Accept’: ‘application/json’,},body: {DisplayName: “your display name”,Job: true,BillWithParent: true,ParentRef: { value: “4404” }},json: true,});
return [{ json: response }];

It lets you use the Job/ParentRef/IsProject fields that the native node doesn’t expose.

Also worth filing a feature request on GitHub to add those fields to the native QBO node.

Let me know if it works :crossed_fingers: