通过托管 OAuth 接入 Quo 商业电话 API,可发送短信、查询通话、管理联系人、获取录音与转写。
设计与多媒体
jobber
试用通过托管 OAuth 在 Jobber GraphQL API 上管理客户、工单、发票、报价和物业等现场服务数据。
它能做什么
通过 Maton 网关(https://api.maton.ai/jobber/graphql)以 Bearer 令牌方式调用 Jobber GraphQL API。支持账户信息查询,以及客户、工单、发票、报价、物业、请求、成员和自定义字段的列表与创建操作,同时提供 Relay 游标分页和 Webhook 事件订阅能力。默认仅执行读取与列表调用,所有创建、更新、删除操作在执行前需用户明确确认;多账户场景可通过 Maton-Connection 头指定目标连接。
什么时候用它
- 从已连接的 Jobber 账户分页拉取客户或发票列表
- 为已有客户创建新的服务工单或报价单
- 查询账户信息、成员、物业或自定义字段
- 订阅 JOB_COMPLETE、INVOICE_CREATE 等 Webhook 事件
技能文档
Jobber
Access the Jobber API with managed OAuth authentication. Manage clients, jobs, invoices, quotes, properties, and team members for field service businesses.
Quick Start
# Get account information
python <<'EOF'
import urllib.request, os, json
query = '{"query": "{ account { id name } }"}'
req = urllib.request.Request('https://api.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
API Type
Jobber uses a GraphQL API exclusively. All requests are POST requests to the /graphql endpoint with a JSON body containing the query field.
Base URL
https://api.maton.ai/jobber/graphql
Maton proxies requests to api.getjobber.com/api/graphql and automatically injects your OAuth token and API version header.
Authentication
All requests require the Maton API key in the Authorization header:
Authorization: Bearer $MATON_API_KEY
Maton 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"
Getting Your API Key
- Sign in or create an account at maton.ai
- Go to maton.ai/settings
- Copy your API key
Connection Management
Manage your Jobber OAuth connections at https://api.maton.ai.
List Connections
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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
Create Connection
python <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'jobber'}).encode()
req = urllib.request.Request('https://api.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
Get Connection
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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": "{connection_id}",
"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.
Delete Connection
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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
Specifying Connection
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://api.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', '{connection_id}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
If you have multiple connections, always include this header to ensure requests go to the intended account.
Security & Permissions
- Access is scoped to clients, jobs, invoices, quotes, properties, and team members for field service businesses within the connected Jobber account.
- All write operations require explicit user approval. Before executing any create, update, or delete call, confirm the target resource and intended effect with the user.
API Reference
Account Operations
Get Account Information
POST /jobber/graphql
Content-Type: application/json
{
"query": "{ account { id name } }"
}
Client Operations
List Clients
POST /jobber/graphql
Content-Type: application/json
{
"query": "{ clients(first: 20) { nodes { id name emails { primary address } phones { primary number } } pageInfo { hasNextPage endCursor } } }"
}
Get Client by ID
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" }
}
Create Client
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"
}
}
}
Update Client
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"
}
}
}
Job Operations
List Jobs
POST /jobber/graphql
Content-Type: application/json
{
"query": "{ jobs(first: 20) { nodes { id title jobNumber jobStatus client { name } } pageInfo { hasNextPage endCursor } } }"
}
Get Job by ID
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" }
}
Create Job
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"
}
}
}
Invoice Operations
List Invoices
POST /jobber/graphql
Content-Type: application/json
{
"query": "{ invoices(first: 20) { nodes { id invoiceNumber subject total invoiceStatus client { name } } pageInfo { hasNextPage endCursor } } }"
}
Get Invoice by ID
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" }
}
Create Invoice
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
}
]
}
}
}
Quote Operations
List Quotes
POST /jobber/graphql
Content-Type: application/json
{
"query": "{ quotes(first: 20) { nodes { id quoteNumber title quoteStatus client { name } } pageInfo { hasNextPage endCursor } } }"
}
Create Quote
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
}
]
}
}
}
Property Operations
List Properties
POST /jobber/graphql
Content-Type: application/json
{
"query": "{ properties(first: 20) { nodes { id address { street city state postalCode } client { name } } pageInfo { hasNextPage endCursor } } }"
}
Request Operations
List Requests
POST /jobber/graphql
Content-Type: application/json
{
"query": "{ requests(first: 20) { nodes { id title requestStatus client { name } } pageInfo { hasNextPage endCursor } } }"
}
User/Team Operations
List Users
POST /jobber/graphql
Content-Type: application/json
{
"query": "{ users(first: 50) { nodes { id name { full } email { raw } } } }"
}
Custom Field Operations
List Custom Fields
POST /jobber/graphql
Content-Type: application/json
{
"query": "{ customFields(first: 50) { nodes { id name fieldType } } }"
}
Pagination
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"
}
}
}
}
Webhooks
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 connected
Webhooks include HMAC-SHA256 signatures for verification.
Code Examples
JavaScript
const query = `{ clients(first: 10) { nodes { id name emails { address } } } }`;
const response = await fetch('https://api.maton.ai/jobber/graphql', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.MATON_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ query })
});
const data = await response.json();
Python
import os
import requests
query = '''
{
clients(first: 10) {
nodes { id name emails { address } }
}
}
'''
response = requests.post(
'https://api.maton.ai/jobber/graphql',
headers={
'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}',
'Content-Type': 'application/json'
},
json={'query': query}
)
data = response.json()
Notes
- Jobber uses GraphQL exclusively (no REST API)
- Maton automatically injects the
X-JOBBER-GRAPHQL-VERSIONheader - Current gateway API version:
2025-04-16(latest) - Old API versions are supported for 12-18 months from release
- Use the GraphiQL explorer in Jobber's Developer Center for schema discovery
- IDs use
EncodedIdtype (base64 encoded) - pass as strings - Field naming: use
emails/phones(arrays),jobStatus/invoiceStatus/quoteStatus/requestStatus - Rate limits:
- DDoS protection: 2,500 requests per 5 minutes per app/account
- Query cost: Points-based using leaky bucket algorithm (max 10,000 points, restore 500/sec)
- Avoid deeply nested queries to reduce query cost
- IMPORTANT: When piping curl output to
jqor other commands, environment variables like$MATON_API_KEYmay not expand correctly in some shell environments
Error Handling
| 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"]
}
]
}
}
}
Troubleshooting: API Key Issues
- Check that the
MATON_API_KEYenvironment variable is set:
echo $MATON_API_KEY
- Verify the API key is valid by listing connections:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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
Troubleshooting: Invalid App Name
- Ensure your URL path starts with
jobber. For example:
- Correct:
https://api.maton.ai/jobber/graphql - Incorrect:
https://api.maton.ai/graphql
Resources
- Jobber Developer Documentation
- Getting Started Guide
- API Support
- Maton Community
- Maton Support
相关技能
通过托管 OAuth 代理调用 JotForm API,读写表单、提交记录与 Webhook。
Read your Jobber Client Hub — the customer portal a service business (pest control, lawn care, HVAC, cleaning) uses to send you appointments, quotes and invoices — from a shell with the fpx CLI (@fetchproxy/cli), instead of running the jobber-mcp server. Use when you want your Jobber data without the MCP, in a script, or on a machine where the MCP isn't installed.
通过托管 OAuth 连接 Motion API,管理任务、项目、循环任务和工作区。
JobNimbus (jobnimbus.com). Use this skill for ANY JobNimbus request — reading, creating, and updating data. Whenever a task involves JobNimbus, use this skil...
通过托管网关调用第三方 API,免去自行管理 OAuth 和密钥的负担。