Connect Jobber to n8n (Google Sheets + alerts)

There's no Jobber node in n8n and no Jobber template in the n8n gallery (a search for "jobber" returns 0). The forum question "Connecting Jobber to n8n" asks for exactly this: update a Google Sheet when jobs change in Jobber. The poster wanted that "when we add or update clients & job statuses n8n will automatically update certain cells within google sheets", and asked where to find a tutorial or workflow. The thread has 687 views and no solution. The usual blocker is OAuth: "everything breaks in 1 hour when the access_token expires". This guide walks through a setup that keeps working, and the free template does the rest.

Download the free Jobber → Google Sheets template

n8n workflow JSON: verified Jobber webhooks + 15-minute poll fallback, Sheets upsert, one email per new job or quote. No credentials inside. Needs n8n 2.29.0+.

Want it set up faster? The Jobber Pro Kit ($19) adds a step-by-step setup guide, the Sheet header CSV and an offline test kit (Jobber API mock + signed-webhook tester), so you can check it works before connecting your real account.

What you'll build

Before you start

Step 1: Create a Jobber app

In the Jobber Developer Center, create a new app. A private app for your own business is a custom integration: it can stay in Draft as long as it's connected to 5 or fewer paying Jobber accounts, so there's no Marketplace review.

Step 2: The OAuth2 credential (the part that usually breaks)

In n8n, create an OAuth2 API credential with these values from Jobber's app authorization docs:

FieldValue
Grant TypeAuthorization Code
Authorization URLhttps://api.getjobber.com/api/oauth/authorize
Access Token URLhttps://api.getjobber.com/api/oauth/token
Client ID / Client Secretfrom your Jobber app
Scopeleave empty (scopes come from the app)
AuthenticationBody (the accepted fix when authorization fails with Header)

Click Connect and approve the app in Jobber.

Why it used to break after an hour: Jobber access tokens last 60 minutes, and refresh token rotation means every refresh returns a new refresh token that replaces the old one. Jobber's token endpoint answers with a text/plain content type. Older n8n versions couldn't parse that and failed with Unsupported content type: text/plain (n8n issue #30345). Two fixes, #33018 (parse non-standard token responses) and #33092 (serialize refreshes so a rotated token isn't lost), shipped in n8n 2.29.0. On 2.29.0+ you don't need a cron job that refreshes the token by hand.

A forum reply warns that refresh "won't work because gql returns an HTTP 20X". That isn't what Jobber does today. We sent a bad token to api.getjobber.com/api/graphql and got HTTP 401 {"message":"Token not recognized"}, which is what triggers n8n's automatic refresh. In our tests, an expired token was refreshed and the request retried without any extra nodes.

Don't share the connection with GraphiQL. Using Test in GraphiQL in the Developer Center invalidates existing refresh tokens. If you test there, click Reconnect on the n8n credential afterwards.

Step 3: Call the GraphQL API with the version header

Use an HTTP Request node: POST to https://api.getjobber.com/api/graphql, Authentication Generic Credential Type → OAuth2 API, and a header X-JOBBER-GRAPHQL-VERSION. Jobber's versioning docs say this header "is required for all apps". Versions are dates, and the newest in the changelog is 2026-09-25. Body (JSON):

{{ JSON.stringify({
  query: `query JobById($id: EncodedId!) {
    job(id: $id) {
      id jobNumber title jobStatus total createdAt startAt jobberWebUri
      client { id name companyName emails { address primary } phones { number primary } }
      property { address { street city province postalCode } }
    }
  }`,
  variables: { id: $json.item_id }
}) }}

Every field above was checked against Jobber's live schema. For quotes, use quote(id:) with quoteNumber quoteStatus amounts { total } sentAt. Jobber also reports some failures as HTTP 200 with an errors array, for example THROTTLED when a query costs more points than you have left (rate limits: a 10,000-point bucket, refilled at 500 points per second). Check for errors before you write anything.

Step 4: Receive and verify Jobber webhooks

A Jobber webhook only says what happened. The body is {"data":{"webHookEvent":{"topic","appId","accountId","itemId","occurredAt"}}}, with no job details, so you fetch the record by itemId (step 3). Three rules from the webhook docs shape the workflow:

  1. Verify the signature. Each request has an X-Jobber-Hmac-SHA256 header: base64 HMAC-SHA256 of the raw body, keyed with your app's client secret. In n8n, turn on Raw Body in the Webhook node's options, then use a Crypto node (Action Hmac, Binary File on, property data, SHA256, Base64) with a Crypto credential that holds the client secret. Compare the result to the header and answer 401 if it doesn't match.
  2. Answer within 1 second. Set the Webhook to respond with a Respond to Webhook node and send the 200 before calling the API.
  3. Expect duplicates. Delivery is at-least-once. Upsert rows on a key (job:<id>) and put a Remove Duplicates node (Remove Items Processed in Previous Executions) before the email.

Apps created before Dec 8, 2023 get the field as occuredAt (one "r"); the template accepts both. Once the workflow is published, open your app's webhook settings in the Developer Center and add the Webhook node's production URL for JOB_CREATE, QUOTE_CREATE and APP_DISCONNECT.

Step 5: Google Sheets and the email alert

Create a sheet with a Jobber tab and this header row:

record_key, record_type, jobber_id, number, title, status, client_name, client_email, client_phone, property_address, total, created_at, start_at, jobber_url, source, synced_at

Use Google Sheets Append or Update Row with record_key as the column to match on, so a repeat webhook or a poll overlap updates the row instead of adding one. After it, Remove Duplicates on record_key and a Gmail node send the alert, so you're emailed once per job or quote.

Step 6: Add the poll fallback

A Schedule Trigger every 15 minutes runs jobs(first: 50, filter: { createdAt: { after: $since } }, sort: [{ key: CREATED_AT, direction: DESCENDING }]) and the same for quotes, looking back 30 minutes. The overlap is harmless because rows upsert and alerts are deduplicated. Each poll costs about 1,250 points, far below the bucket. If you can't register webhooks, the poll works on its own.

Download the template

Free download: n8n-jobber-to-sheets.json (import with Workflows → Import from file). It contains steps 2–6 already wired: signature check, topic routing, one GraphQL node with the version header, Sheets upsert, alert once per record and a sync-problem email. No credentials are inside; you attach your own Jobber OAuth2, Crypto, Google Sheets and Gmail credentials. The sticky notes repeat this guide's setup steps.

The JSON is and stays free. If you'd rather not wire the test setup yourself, the Jobber Pro Kit ($19 on Gumroad) bundles the same workflow with a setup guide, the Sheet header CSV and the offline test kit we used (a local Jobber API mock and a signed-webhook tester).

We tested it on n8n 2.44.4 against a local mock of Jobber that behaves like the real API: 401 on expired tokens, text/plain token responses, rotating refresh tokens. The tests covered a new job, a new quote, a duplicate webhook, a bad signature, an expired token, a revoked refresh token, throttling, the poll and an app disconnect, and all checks passed. The GraphQL queries were validated against Jobber's live schema. We have not tested it against a real Jobber account yet.

Troubleshooting

SymptomFix
Works for an hour, then 401Update n8n to 2.29.0+ and click Reconnect on the credential once.
Unsupported content type: text/plainThe same bug (#30345). Update to 2.29.0+.
The provided refresh token is not valid.The stored refresh token was rotated or revoked, often by GraphiQL testing or a second tool sharing the app. Reconnect the credential.
Every webhook gets 401 from your workflowRaw Body is off, or the Crypto credential doesn't hold the same client secret as the app.
Authorization fails when connectingSet the credential's Authentication to Body and check that the callback URL in the Jobber app matches n8n's exactly.
No webhooks arriveThe app needs the read scope for the object, the workflow must be published, and the URL must be the production one, not /webhook-test/.
Download the free Jobber → Google Sheets template

n8n workflow JSON: verified Jobber webhooks + 15-minute poll fallback, Sheets upsert, one email per new job or quote. No credentials inside. Needs n8n 2.29.0+.

Want it set up faster? The Jobber Pro Kit ($19) adds a step-by-step setup guide, the Sheet header CSV and an offline test kit (Jobber API mock + signed-webhook tester), so you can check it works before connecting your real account.

FAQ

Is there a Jobber node for n8n?
No. n8n has no built-in Jobber node and the template gallery has no Jobber templates. You connect with an HTTP Request node, a generic OAuth2 API credential and Jobber's GraphQL API at api.getjobber.com/api/graphql.

Why does my Jobber connection in n8n stop working after an hour?
Jobber access tokens expire after 60 minutes and refresh tokens rotate. n8n versions before 2.29.0 could not parse Jobber's text/plain token response (n8n issue #30345). Update to 2.29.0 or newer, set the credential's Authentication to Body, and reconnect once.

Which header does the Jobber API require?
X-JOBBER-GRAPHQL-VERSION, set to a dated API version such as 2026-09-25. Jobber's docs say it is required for all apps.

How do I verify Jobber webhooks in n8n?
Turn on Raw Body in the Webhook node, compute a base64 HMAC-SHA256 of the raw body with your app's client secret using the Crypto node, and compare it with the X-Jobber-Hmac-SHA256 header. Reply 401 if it doesn't match, and reply 200 within 1 second if it does.