通过托管 OAuth 认证访问 Jira Cloud API。使用 JQL 搜索问题、创建和管理问题、自动化工作流。
快速开始
# 首先,获取 cloud ID
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/jira/oauth/token/accessible-resources')
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
req = urllib.request.Request('https://gateway.maton.ai/jira/ex/jira/{cloudId}/rest/api/3/search/jql?jql=project%3DKEY&maxResults=10')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
基础 URL
https://gateway.maton.ai/jira/{原生API路径}
将 {原生API路径} 替换为实际的 Jira API 端点路径。网关将请求代理到 api.atlassian.com 并自动注入你的 OAuth token。
获取 Cloud ID
Jira Cloud 需要 cloud ID。首先获取:
GET /jira/oauth/token/accessible-resources
响应:
[{
"id": "62909843-b784-4c35-b770-e4e2a26f024b",
"url": "https://yoursite.atlassian.net",
"name": "yoursite"
}]
认证
所有请求需要在 Authorization 头中包含 Maton API Key:
Authorization: Bearer $MATON_API_KEY
环境变量: 将 API Key 设置为 MATON_API_KEY:
export MATON_API_KEY="YOUR_API_KEY"
获取 API Key
连接管理
在 https://ctrl.maton.ai 管理你的 Jira OAuth 连接。
列出连接
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections?app=jira&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': 'jira'}).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
响应:
{
"connection": {
"connection_id": "21fd90f9-5935-43cd-b6c8-bde9d915ca80",
"status": "ACTIVE",
"creation_time": "2025-12-08T07:20:53.488460Z",
"last_updated_time": "2026-01-31T20:03:32.593153Z",
"url": "https://connect.maton.ai/?session_token=...",
"app": "jira",
"metadata": {}
}
}
在浏览器中打开返回的 url 完成 OAuth 授权。
删除连接
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
指定连接
如果你有多个 Jira 连接,使用 Maton-Connection 头指定使用哪个:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/jira/ex/jira/{cloudId}/rest/api/3/project')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', '21fd90f9-5935-43cd-b6c8-bde9d915ca80')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
如果省略,网关使用默认(最早的)活跃连接。
API 参考
项目
列出项目
GET /jira/ex/jira/{cloudId}/rest/api/3/project
获取项目
GET /jira/ex/jira/{cloudId}/rest/api/3/project/{projectKeyOrId}
问题
搜索问题(JQL)
GET /jira/ex/jira/{cloudId}/rest/api/3/search/jql?jql=project%3DKEY%20order%20by%20created%20DESC&maxResults=20&fields=summary,status,assignee
获取问题
GET /jira/ex/jira/{cloudId}/rest/api/3/issue/{issueIdOrKey}
创建问题
POST /jira/ex/jira/{cloudId}/rest/api/3/issue
Content-Type: application/json{
"fields": {
"project": {"key": "PROJ"},
"summary": "问题摘要",
"issuetype": {"name": "Task"}
}
}
更新问题
PUT /jira/ex/jira/{cloudId}/rest/api/3/issue/{issueIdOrKey}
Content-Type: application/json{
"fields": {
"summary": "更新后的摘要"
}
}
删除问题
DELETE /jira/ex/jira/{cloudId}/rest/api/3/issue/{issueIdOrKey}
分配问题
PUT /jira/ex/jira/{cloudId}/rest/api/3/issue/{issueIdOrKey}/assignee
Content-Type: application/json{
"accountId": "712020:5aff718e-6fe0-4548-82f4-f44ec481e5e7"
}
状态流转
获取可用的流转
GET /jira/ex/jira/{cloudId}/rest/api/3/issue/{issueIdOrKey}/transitions
执行流转(更改状态)
POST /jira/ex/jira/{cloudId}/rest/api/3/issue/{issueIdOrKey}/transitions
Content-Type: application/json{
"transition": {"id": "31"}
}
评论
获取评论
GET /jira/ex/jira/{cloudId}/rest/api/3/issue/{issueIdOrKey}/comment
添加评论
POST /jira/ex/jira/{cloudId}/rest/api/3/issue/{issueIdOrKey}/comment
Content-Type: application/json{
"body": {
"type": "doc",
"version": 1,
"content": [{"type": "paragraph", "content": [{"type": "text", "text": "评论文本"}]}]
}
}
用户
获取当前用户
GET /jira/ex/jira/{cloudId}/rest/api/3/myself
搜索用户
GET /jira/ex/jira/{cloudId}/rest/api/3/user/search?query=john
元数据
列出问题类型
GET /jira/ex/jira/{cloudId}/rest/api/3/issuetype
列出优先级
GET /jira/ex/jira/{cloudId}/rest/api/3/priority
列出状态
GET /jira/ex/jira/{cloudId}/rest/api/3/status
代码示例
JavaScript
// 先获取 cloud ID
const resources = await fetch(
'https://gateway.maton.ai/jira/oauth/token/accessible-resources',
{ headers: { 'Authorization': Bearer ${process.env.MATON_API_KEY} } }
).then(r => r.json());const cloudId = resources[0].id;
// 搜索问题
const issues = await fetch(
https://gateway.maton.ai/jira/ex/jira/${cloudId}/rest/api/3/search/jql?jql=project=KEY,
{ headers: { 'Authorization': Bearer ${process.env.MATON_API_KEY} } }
).then(r => r.json());
Python
import os
import requestsheaders = {'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'}
# 获取 cloud ID
resources = requests.get(
'https://gateway.maton.ai/jira/oauth/token/accessible-resources',
headers=headers
).json()
cloud_id = resources[0]['id']
# 搜索问题
issues = requests.get(
f'https://gateway.maton.ai/jira/ex/jira/{cloud_id}/rest/api/3/search/jql',
headers=headers,
params={'jql': 'project=KEY', 'maxResults': 10}
).json()
注意事项
- 始终先使用
/oauth/token/accessible-resources 获取 cloud ID
- JQL 查询必须有边界条件(如
project=KEY)
- JQL 查询参数需要 URL 编码
- 更新、删除、流转成功时返回 HTTP 204
- Agile API 需要额外的 OAuth 范围。如果收到范围错误,联系 Maton 支持 support@maton.ai,说明你需要的具体操作/API 和用例
- 重要:使用 curl 命令时,当 URL 包含方括号(
fields[]、sort[]、records[])时使用 curl -g 禁用 glob 解析
- 重要:将 curl 输出管道到
jq 或其他命令时,$MATON_API_KEY 等环境变量在某些 shell 环境中可能无法正确展开。管道操作时可能出现"Invalid API key"错误
错误处理
| 状态码 | 含义 |
|---|
| 400 | 缺少 Jira 连接或无效 JQL |
| 401 | 无效或缺少 Maton API Key |
| 429 | 速率限制(每账户每秒 10 请求) |
| 4xx/5xx | Jira API 透传错误 |
故障排除:API Key 问题
- 检查
MATON_API_KEY 环境变量是否已设置:
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
故障排除:无效的应用名称
- 正确:
https://gateway.maton.ai/jira/ex/jira/{cloudId}/rest/api/3/project
- 错误:
https://gateway.maton.ai/ex/jira/{cloudId}/rest/api/3/project
资源
Access the Jira Cloud API with managed OAuth authentication. Search issues with JQL, create and manage issues, and automate workflows.
Quick Start
# First, get your cloud ID
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/jira/oauth/token/accessible-resources')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF# Then search issues
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/jira/ex/jira/{cloudId}/rest/api/3/search/jql?jql=project%3DKEY&maxResults=10')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Base URL
https://gateway.maton.ai/jira/{native-api-path}
Replace {native-api-path} with the actual Jira API endpoint path. The gateway proxies requests to api.atlassian.com and automatically injects your OAuth token.
Getting Cloud ID
Jira Cloud requires a cloud ID. Get it first:
GET /jira/oauth/token/accessible-resources
Response:
[{
"id": "62909843-b784-4c35-b770-e4e2a26f024b",
"url": "https://yoursite.atlassian.net",
"name": "yoursite"
}]
Authentication
All requests require the Maton API key in the Authorization header:
Authorization: Bearer $MATON_API_KEY
Environment Variable: Set your API key as MATON_API_KEY:
export MATON_API_KEY="YOUR_API_KEY"
Getting Your API Key
Connection Management
Manage your Jira OAuth connections at https://ctrl.maton.ai.
List Connections
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections?app=jira&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': 'jira'}).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
Get Connection
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": "21fd90f9-5935-43cd-b6c8-bde9d915ca80",
"status": "ACTIVE",
"creation_time": "2025-12-08T07:20:53.488460Z",
"last_updated_time": "2026-01-31T20:03:32.593153Z",
"url": "https://connect.maton.ai/?session_token=...",
"app": "jira",
"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://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
Specifying Connection
If you have multiple Jira connections, specify which one to use with the Maton-Connection header:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/jira/ex/jira/{cloudId}/rest/api/3/project')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', '21fd90f9-5935-43cd-b6c8-bde9d915ca80')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
If omitted, the gateway uses the default (oldest) active connection.
API Reference
Projects
List Projects
GET /jira/ex/jira/{cloudId}/rest/api/3/project
Get Project
GET /jira/ex/jira/{cloudId}/rest/api/3/project/{projectKeyOrId}
Issues
Search Issues (JQL)
GET /jira/ex/jira/{cloudId}/rest/api/3/search/jql?jql=project%3DKEY%20order%20by%20created%20DESC&maxResults=20&fields=summary,status,assignee
Get Issue
GET /jira/ex/jira/{cloudId}/rest/api/3/issue/{issueIdOrKey}
Create Issue
POST /jira/ex/jira/{cloudId}/rest/api/3/issue
Content-Type: application/json{
"fields": {
"project": {"key": "PROJ"},
"summary": "Issue summary",
"issuetype": {"name": "Task"}
}
}
Update Issue
PUT /jira/ex/jira/{cloudId}/rest/api/3/issue/{issueIdOrKey}
Content-Type: application/json{
"fields": {
"summary": "Updated summary"
}
}
Delete Issue
DELETE /jira/ex/jira/{cloudId}/rest/api/3/issue/{issueIdOrKey}
Assign Issue
PUT /jira/ex/jira/{cloudId}/rest/api/3/issue/{issueIdOrKey}/assignee
Content-Type: application/json{
"accountId": "712020:5aff718e-6fe0-4548-82f4-f44ec481e5e7"
}
Transitions
Get Transitions
GET /jira/ex/jira/{cloudId}/rest/api/3/issue/{issueIdOrKey}/transitions
Transition Issue (change status)
POST /jira/ex/jira/{cloudId}/rest/api/3/issue/{issueIdOrKey}/transitions
Content-Type: application/json{
"transition": {"id": "31"}
}
Comments
Get Comments
GET /jira/ex/jira/{cloudId}/rest/api/3/issue/{issueIdOrKey}/comment
Add Comment
POST /jira/ex/jira/{cloudId}/rest/api/3/issue/{issueIdOrKey}/comment
Content-Type: application/json{
"body": {
"type": "doc",
"version": 1,
"content": [{"type": "paragraph", "content": [{"type": "text", "text": "Comment text"}]}]
}
}
Users
Get Current User
GET /jira/ex/jira/{cloudId}/rest/api/3/myself
Search Users
GET /jira/ex/jira/{cloudId}/rest/api/3/user/search?query=john
Metadata
List Issue Types
GET /jira/ex/jira/{cloudId}/rest/api/3/issuetype
List Priorities
GET /jira/ex/jira/{cloudId}/rest/api/3/priority
List Statuses
GET /jira/ex/jira/{cloudId}/rest/api/3/status
Code Examples
JavaScript
// Get cloud ID first
const resources = await fetch(
'https://gateway.maton.ai/jira/oauth/token/accessible-resources',
{ headers: { 'Authorization': Bearer ${process.env.MATON_API_KEY} } }
).then(r => r.json());const cloudId = resources[0].id;
// Search issues
const issues = await fetch(
https://gateway.maton.ai/jira/ex/jira/${cloudId}/rest/api/3/search/jql?jql=project=KEY,
{ headers: { 'Authorization': Bearer ${process.env.MATON_API_KEY} } }
).then(r => r.json());
Python
import os
import requestsheaders = {'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'}
# Get cloud ID
resources = requests.get(
'https://gateway.maton.ai/jira/oauth/token/accessible-resources',
headers=headers
).json()
cloud_id = resources[0]['id']
# Search issues
issues = requests.get(
f'https://gateway.maton.ai/jira/ex/jira/{cloud_id}/rest/api/3/search/jql',
headers=headers,
params={'jql': 'project=KEY', 'maxResults': 10}
).json()
Notes
- Always fetch cloud ID first using
/oauth/token/accessible-resources
- JQL queries must be bounded (e.g.,
project=KEY)
- Use URL encoding for JQL query parameters
- Update, Delete, Transition return HTTP 204 on success
- Agile API requires additional OAuth scopes. If you receive a scope error, contact Maton support at support@maton.ai with the specific operations/APIs you need and your use-case
- IMPORTANT: When using curl commands, use
curl -g when URLs contain brackets (fields[], sort[], records[]) to disable glob parsing
- IMPORTANT: When piping curl output to
jq or other commands, environment variables like $MATON_API_KEY may not expand correctly in some shell environments. You may get "Invalid API key" errors when piping.
Error Handling
| Status | Meaning |
|---|
| 400 | Missing Jira connection or invalid JQL |
| 401 | Invalid or missing Maton API key |
| 429 | Rate limited (10 req/sec per account) |
| 4xx/5xx | Passthrough error from Jira API |
Troubleshooting: API Key Issues
- Check that the
MATON_API_KEY environment 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://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
Troubleshooting: Invalid App Name
- Ensure your URL path starts with
jira. For example:
- Correct:
https://gateway.maton.ai/jira/ex/jira/{cloudId}/rest/api/3/project
- Incorrect:
https://gateway.maton.ai/ex/jira/{cloudId}/rest/api/3/project
Resources