Jobber
Jobber API integration with managed OAuth. Manage clients, jobs, invoices, quotes, properties, and team members for field service businesses. Use this skill when users want to create and manage servic
Jobber API integration with managed OAuth. Manage clients, jobs, invoices, quotes, properties, and team members for field service businesses. Use this skill when users want to create and manage servic
Real data. Real impact.
Emerging
Developers
Per week
Open source
Skills give you superpowers. Install in 30 seconds.
Access the Jobber API with managed OAuth authentication. Manage clients, jobs, invoices, quotes, properties, and team members for field service businesses.
# Get account information python <<'EOF' import urllib.request, os, json query = '{"query": "{ account { id name } }"}' req = urllib.request.Request('https://gateway.maton.ai/jobber/graphql', data=query.encode(), method='POST') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') req.add_header('Content-Type', 'application/json') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
Jobber uses a GraphQL API exclusively. All requests are POST requests to the
/graphql endpoint with a JSON body containing the query field.
https://gateway.maton.ai/jobber/graphql
The gateway proxies requests to
api.getjobber.com/api/graphql and automatically injects your OAuth token and API version header.
All requests require the Maton API key in the Authorization header:
Authorization: Bearer $MATON_API_KEY
The gateway automatically injects the
X-JOBBER-GRAPHQL-VERSION header (currently 2025-04-16).
Environment Variable: Set your API key as
MATON_API_KEY:
export MATON_API_KEY="YOUR_API_KEY"
Manage your Jobber OAuth connections at
https://ctrl.maton.ai.
python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://ctrl.maton.ai/connections?app=jobber&status=ACTIVE') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
python <<'EOF' import urllib.request, os, json data = json.dumps({'app': 'jobber'}).encode() req = urllib.request.Request('https://ctrl.maton.ai/connections', data=data, method='POST') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') req.add_header('Content-Type', 'application/json') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
Response:
{ "connection": { "connection_id": "cc61da85-8bf7-4fbc-896b-4e4eb9a5aafd", "status": "ACTIVE", "creation_time": "2026-02-07T09:29:19.946291Z", "last_updated_time": "2026-02-07T09:30:59.990084Z", "url": "https://connect.maton.ai/?session_token=...", "app": "jobber", "metadata": {} } }
Open the returned
url in a browser to complete OAuth authorization.
python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}', method='DELETE') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
If you have multiple Jobber connections, specify which one to use with the
Maton-Connection header:
python <<'EOF' import urllib.request, os, json query = '{"query": "{ account { id name } }"}' req = urllib.request.Request('https://gateway.maton.ai/jobber/graphql', data=query.encode(), method='POST') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') req.add_header('Content-Type', 'application/json') req.add_header('Maton-Connection', 'cc61da85-8bf7-4fbc-896b-4e4eb9a5aafd') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
If omitted, the gateway uses the default (oldest) active connection.
POST /jobber/graphql Content-Type: application/json{ "query": "{ account { id name } }" }
POST /jobber/graphql Content-Type: application/json{ "query": "{ clients(first: 20) { nodes { id name emails { primary address } phones { primary number } } pageInfo { hasNextPage endCursor } } }" }
POST /jobber/graphql Content-Type: application/json{ "query": "query($id: EncodedId!) { client(id: $id) { id name emails { primary address } phones { primary number } billingAddress { street city } } }", "variables": { "id": "CLIENT_ID" } }
POST /jobber/graphql Content-Type: application/json{ "query": "mutation($input: ClientCreateInput!) { clientCreate(input: $input) { client { id name } userErrors { message path } } }", "variables": { "input": { "firstName": "John", "lastName": "Doe", "email": "john@example.com", "phone": "555-1234" } } }
POST /jobber/graphql Content-Type: application/json{ "query": "mutation($id: EncodedId!, $input: ClientUpdateInput!) { clientUpdate(clientId: $id, input: $input) { client { id name } userErrors { message path } } }", "variables": { "id": "CLIENT_ID", "input": { "email": "newemail@example.com" } } }
POST /jobber/graphql Content-Type: application/json{ "query": "{ jobs(first: 20) { nodes { id title jobNumber jobStatus client { name } } pageInfo { hasNextPage endCursor } } }" }
POST /jobber/graphql Content-Type: application/json{ "query": "query($id: EncodedId!) { job(id: $id) { id title jobNumber jobStatus instructions client { name } property { address { street city } } } }", "variables": { "id": "JOB_ID" } }
POST /jobber/graphql Content-Type: application/json{ "query": "mutation($input: JobCreateInput!) { jobCreate(input: $input) { job { id jobNumber title } userErrors { message path } } }", "variables": { "input": { "clientId": "CLIENT_ID", "title": "Lawn Maintenance", "instructions": "Weekly lawn care service" } } }
POST /jobber/graphql Content-Type: application/json{ "query": "{ invoices(first: 20) { nodes { id invoiceNumber subject total invoiceStatus client { name } } pageInfo { hasNextPage endCursor } } }" }
POST /jobber/graphql Content-Type: application/json{ "query": "query($id: EncodedId!) { invoice(id: $id) { id invoiceNumber subject total amountDue invoiceStatus lineItems { nodes { name quantity unitPrice } } } }", "variables": { "id": "INVOICE_ID" } }
POST /jobber/graphql Content-Type: application/json{ "query": "mutation($input: InvoiceCreateInput!) { invoiceCreate(input: $input) { invoice { id invoiceNumber } userErrors { message path } } }", "variables": { "input": { "clientId": "CLIENT_ID", "subject": "Service Invoice", "lineItems": [ { "name": "Lawn Care", "quantity": 1, "unitPrice": 75.00 } ] } } }
POST /jobber/graphql Content-Type: application/json{ "query": "{ quotes(first: 20) { nodes { id quoteNumber title quoteStatus client { name } } pageInfo { hasNextPage endCursor } } }" }
POST /jobber/graphql Content-Type: application/json{ "query": "mutation($input: QuoteCreateInput!) { quoteCreate(input: $input) { quote { id quoteNumber } userErrors { message path } } }", "variables": { "input": { "clientId": "CLIENT_ID", "title": "Landscaping Quote", "lineItems": [ { "name": "Garden Design", "quantity": 1, "unitPrice": 500.00 } ] } } }
POST /jobber/graphql Content-Type: application/json{ "query": "{ properties(first: 20) { nodes { id address { street city state postalCode } client { name } } pageInfo { hasNextPage endCursor } } }" }
POST /jobber/graphql Content-Type: application/json{ "query": "{ requests(first: 20) { nodes { id title requestStatus client { name } } pageInfo { hasNextPage endCursor } } }" }
POST /jobber/graphql Content-Type: application/json{ "query": "{ users(first: 50) { nodes { id name { full } email { raw } } } }" }
POST /jobber/graphql Content-Type: application/json{ "query": "{ customFields(first: 50) { nodes { id name fieldType } } }" }
Jobber uses Relay-style cursor-based pagination:
# First page POST /jobber/graphql { "query": "{ clients(first: 20) { nodes { id name } pageInfo { hasNextPage endCursor } } }" }Next page using cursor
POST /jobber/graphql { "query": "{ clients(first: 20, after: "CURSOR_VALUE") { nodes { id name } pageInfo { hasNextPage endCursor } } }" }
Response includes
pageInfo:
{ "data": { "clients": { "nodes": [...], "pageInfo": { "hasNextPage": true, "endCursor": "abc123" } } } }
Jobber supports webhooks for real-time event notifications:
CLIENT_CREATE - New client createdJOB_COMPLETE - Job marked completeQUOTE_CREATE - New quote createdQUOTE_APPROVAL - Quote approvedREQUEST_CREATE - New request createdINVOICE_CREATE - New invoice createdAPP_CONNECT - App connectedWebhooks include HMAC-SHA256 signatures for verification.
const query = `{ clients(first: 10) { nodes { id name emails { address } } } }`;const response = await fetch('https://gateway.maton.ai/jobber/graphql', { method: 'POST', headers: { 'Authorization':
, 'Content-Type': 'application/json' }, body: JSON.stringify({ query }) });Bearer ${process.env.MATON_API_KEY}const data = await response.json();
import os import requestsquery = ''' { clients(first: 10) { nodes { id name emails { address } } } } '''
response = requests.post( 'https://gateway.maton.ai/jobber/graphql', headers={ 'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}', 'Content-Type': 'application/json' }, json={'query': query} ) data = response.json()
X-JOBBER-GRAPHQL-VERSION header2025-04-16 (latest)EncodedId type (base64 encoded) - pass as stringsemails/phones (arrays), jobStatus/invoiceStatus/quoteStatus/requestStatusjq or other commands, environment variables like $MATON_API_KEY may not expand correctly in some shell environments| Status | Meaning |
|---|---|
| 400 | Missing Jobber connection or malformed query |
| 401 | Invalid or missing Maton API key |
| 403 | Not authorized (check OAuth scopes) |
| 429 | Rate limited |
| 4xx/5xx | Passthrough error from Jobber API |
GraphQL errors appear in the response body:
{ "errors": [ { "message": "Error description", "locations": [...], "path": [...] } ] }
Mutation errors appear in
userErrors:
{ "data": { "clientCreate": { "client": null, "userErrors": [ { "message": "Email is required", "path": ["input", "email"] } ] } } }
MATON_API_KEY environment variable is set:echo $MATON_API_KEY
python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://ctrl.maton.ai/connections') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF
jobber. For example:https://gateway.maton.ai/jobber/graphqlhttps://gateway.maton.ai/graphqlNo automatic installation available. Please visit the source repository for installation instructions.
View Installation Instructions1,500+ AI skills, agents & workflows. Install in 30 seconds. Part of the Torly.ai family.
© 2026 Torly.ai. All rights reserved.