Install
openclaw skills install grafana-apiGrafana API integration with managed authentication. This is a write-capable integration — it can read, create, update, and delete dashboards, data sources, folders, annotations, alerts, and teams in your Grafana instance. Use this skill when users want to interact with Grafana for monitoring, visualization, and observability. All write operations (creating/updating/deleting dashboards, folders, data sources, alerts, or teams) require explicit user approval with specific resource identifiers before execution. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway).
openclaw skills install grafana-apiAccess Grafana dashboards, data sources, folders, annotations, and alerts via managed API authentication.
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/grafana/api/search?type=dash-db')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
https://api.maton.ai/grafana/{native-api-path}
Maton proxies requests to your Grafana instance and automatically injects authentication.
All requests require the Maton API key:
Authorization: Bearer $MATON_API_KEY
Environment Variable: Set your API key as MATON_API_KEY:
export MATON_API_KEY="YOUR_API_KEY"
Manage your Grafana connections at https://api.maton.ai.
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections?app=grafana&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': 'grafana'}).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
Open the returned url in a browser to complete authentication. You'll need to provide your Grafana service account token. Use a dedicated, least-privilege service account token for this integration — limit it to the specific organization, folders, and resources needed for the task. Avoid admin-role tokens unless specifically required. Rotate the token periodically and revoke it immediately when the connection is no longer needed.
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
GET /grafana/api/org
Response:
{
"id": 1,
"name": "Main Org.",
"address": {
"address1": "",
"address2": "",
"city": "",
"zipCode": "",
"state": "",
"country": ""
}
}
GET /grafana/api/user
Response:
{
"id": 1,
"uid": "abc123",
"email": "user@example.com",
"name": "User Name",
"login": "user",
"orgId": 1,
"isGrafanaAdmin": false
}
GET /grafana/api/search?type=dash-db
Query Parameters:
type - dash-db for dashboards, dash-folder for foldersquery - Search query stringtag - Filter by tagfolderIds - Filter by folder IDslimit - Max results (default 1000)Response:
[
{
"id": 1,
"uid": "abc123",
"title": "My Dashboard",
"uri": "db/my-dashboard",
"url": "/d/abc123/my-dashboard",
"type": "dash-db",
"tags": ["production"],
"isStarred": false
}
]
GET /grafana/api/dashboards/uid/{uid}
Response:
{
"meta": {
"type": "db",
"canSave": true,
"canEdit": true,
"canAdmin": true,
"canStar": true,
"slug": "my-dashboard",
"url": "/d/abc123/my-dashboard",
"expires": "0001-01-01T00:00:00Z",
"created": "2024-01-01T00:00:00Z",
"updated": "2024-01-02T00:00:00Z",
"version": 1
},
"dashboard": {
"id": 1,
"uid": "abc123",
"title": "My Dashboard",
"tags": ["production"],
"panels": [...],
"schemaVersion": 30,
"version": 1
}
}
POST /grafana/api/dashboards/db
Content-Type: application/json
{
"dashboard": {
"title": "New Dashboard",
"panels": [],
"schemaVersion": 30,
"version": 0
},
"folderUid": "optional-folder-uid",
"overwrite": false
}
Response:
{
"id": 1,
"uid": "abc123",
"url": "/d/abc123/new-dashboard",
"status": "success",
"version": 1,
"slug": "new-dashboard"
}
DELETE /grafana/api/dashboards/uid/{uid}
Response:
{
"title": "My Dashboard",
"message": "Dashboard My Dashboard deleted",
"id": 1
}
GET /grafana/api/dashboards/home
GET /grafana/api/folders
Response:
[
{
"id": 1,
"uid": "folder123",
"title": "My Folder",
"url": "/dashboards/f/folder123/my-folder",
"hasAcl": false,
"canSave": true,
"canEdit": true,
"canAdmin": true
}
]
GET /grafana/api/folders/{uid}
POST /grafana/api/folders
Content-Type: application/json
{
"title": "New Folder"
}
Response:
{
"id": 1,
"uid": "folder123",
"title": "New Folder",
"url": "/dashboards/f/folder123/new-folder",
"hasAcl": false,
"canSave": true,
"canEdit": true,
"canAdmin": true,
"version": 1
}
PUT /grafana/api/folders/{uid}
Content-Type: application/json
{
"title": "Updated Folder Name",
"version": 1
}
DELETE /grafana/api/folders/{uid}
GET /grafana/api/datasources
Response:
[
{
"id": 1,
"uid": "ds123",
"orgId": 1,
"name": "Prometheus",
"type": "prometheus",
"access": "proxy",
"url": "http://prometheus:9090",
"isDefault": true,
"readOnly": false
}
]
GET /grafana/api/datasources/{id}
GET /grafana/api/datasources/uid/{uid}
GET /grafana/api/datasources/name/{name}
POST /grafana/api/datasources
Content-Type: application/json
{
"name": "New Prometheus",
"type": "prometheus",
"url": "http://prometheus:9090",
"access": "proxy",
"isDefault": false
}
PUT /grafana/api/datasources/{id}
Content-Type: application/json
{
"name": "Updated Prometheus",
"type": "prometheus",
"url": "http://prometheus:9090",
"access": "proxy"
}
DELETE /grafana/api/datasources/{id}
GET /grafana/api/annotations
Query Parameters:
from - Epoch timestamp (ms)to - Epoch timestamp (ms)dashboardId - Filter by dashboard IDdashboardUID - Filter by dashboard UIDpanelId - Filter by panel IDtags - Filter by tags (comma-separated)limit - Max resultsPOST /grafana/api/annotations
Content-Type: application/json
{
"dashboardUID": "abc123",
"time": 1609459200000,
"text": "Deployment completed",
"tags": ["deployment", "production"]
}
Response:
{
"message": "Annotation added",
"id": 1
}
PUT /grafana/api/annotations/{id}
Content-Type: application/json
{
"text": "Updated annotation text",
"tags": ["updated"]
}
DELETE /grafana/api/annotations/{id}
GET /grafana/api/teams/search
Query Parameters:
query - Search querypage - Page numberperpage - Results per pageResponse:
{
"totalCount": 1,
"teams": [
{
"id": 1,
"orgId": 1,
"name": "Engineering",
"email": "engineering@example.com",
"memberCount": 5
}
],
"page": 1,
"perPage": 1000
}
GET /grafana/api/teams/{id}
POST /grafana/api/teams
Content-Type: application/json
{
"name": "New Team",
"email": "team@example.com"
}
PUT /grafana/api/teams/{id}
Content-Type: application/json
{
"name": "Updated Team Name"
}
DELETE /grafana/api/teams/{id}
GET /grafana/api/v1/provisioning/alert-rules
GET /grafana/api/v1/provisioning/alert-rules/{uid}
GET /grafana/api/ruler/grafana/api/v1/rules
GET /grafana/api/serviceaccounts/search
Response:
{
"totalCount": 1,
"serviceAccounts": [
{
"id": 1,
"name": "api-service",
"login": "sa-api-service",
"orgId": 1,
"isDisabled": false,
"role": "Editor"
}
],
"page": 1,
"perPage": 1000
}
GET /grafana/api/plugins
Response:
[
{
"name": "Prometheus",
"type": "datasource",
"id": "prometheus",
"enabled": true,
"pinned": false
}
]
const response = await fetch('https://api.maton.ai/grafana/api/search?type=dash-db', {
headers: {
'Authorization': `Bearer ${process.env.MATON_API_KEY}`
}
});
const dashboards = await response.json();
console.log(dashboards);
import os
import requests
response = requests.get(
'https://api.maton.ai/grafana/api/search?type=dash-db',
headers={
'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'
}
)
print(response.json())
/api/search?type=dash-db to find dashboard UIDs/api/v1/provisioning/...)| Status | Meaning |
|---|---|
| 200 | Success |
| 400 | Invalid request |
| 401 | Invalid or missing authentication |
| 403 | Permission denied |
| 404 | Resource not found |
| 409 | Conflict (e.g., duplicate name) |
| 412 | Precondition failed (version mismatch) |
| 422 | Unprocessable entity |