Manage selected Kibana resources through authenticated API calls with guarded write confirmation.
Documents
Grafana
Try itRead and write Grafana dashboards, data sources, folders, annotations, alerts, and teams via a managed API proxy.
What it does
Proxies requests to a connected Grafana instance using Bearer-token authentication. Supports full CRUD on dashboards, folders, data sources, annotations, and teams; alert rules, service accounts, and plugins are read-only. Every write operation requires explicit user approval with specific resource identifiers, and reads should start by listing resources to confirm those identifiers first.
When to use it
- Programmatically managing dashboards across environments
- Auto-writing annotations when deployment events occur
- Auditing existing data sources and folders before restructuring
- Bulk-creating teams for new organizational units
The skill document
Grafana
Access Grafana dashboards, data sources, folders, annotations, and alerts via managed API authentication.
Quick Start
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
Base URL
https://api.maton.ai/grafana/{native-api-path}
Maton proxies requests to your Grafana instance and automatically injects authentication.
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"
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 Grafana 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=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
Create Connection
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.
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
Security & Permissions
- Access is scoped to dashboards, data sources, folders, annotations, alerts, and teams within the connected Grafana instance. The integration inherits the permissions of the service account token used during connection setup — use least-privilege tokens scoped to the needed organization and folders. Prefer a non-production instance for exploratory work. Remove the connection when no longer needed.
- Default to read-only operations. Always start by listing or retrieving resources to confirm identifiers before proposing any changes.
- All write operations require explicit user approval with specific identifiers. Before executing any POST, PUT, PATCH, or DELETE call:
- Retrieve and display the target resource (dashboard title/UID, folder name, data source name, alert rule) so the user can verify.
- Clearly describe the intended effect (e.g., "This will delete dashboard 'Production Overview' (UID: abc-123) from the 'Ops' folder").
- Wait for explicit user confirmation before proceeding.
- High-impact operations require extra caution. Deleting dashboards, modifying alert rules, changing data source configurations, and reorganizing folders can affect monitoring and observability workflows. These actions must include a summary of consequences and require confirmation.
API Reference
Organization & User
Get Current Organization
GET /grafana/api/org
Response:
{
"id": 1,
"name": "Main Org.",
"address": {
"address1": "",
"address2": "",
"city": "",
"zipCode": "",
"state": "",
"country": ""
}
}
Get Current User
GET /grafana/api/user
Response:
{
"id": 1,
"uid": "abc123",
"email": "user@example.com",
"name": "User Name",
"login": "user",
"orgId": 1,
"isGrafanaAdmin": false
}
Dashboards
Search Dashboards
GET /grafana/api/search?type=dash-db
Query Parameters:
type-dash-dbfor dashboards,dash-folderfor 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 Dashboard by UID
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
}
}
Create/Update Dashboard
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 Dashboard
DELETE /grafana/api/dashboards/uid/{uid}
Response:
{
"title": "My Dashboard",
"message": "Dashboard My Dashboard deleted",
"id": 1
}
Get Home Dashboard
GET /grafana/api/dashboards/home
Folders
List Folders
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 Folder by UID
GET /grafana/api/folders/{uid}
Create Folder
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
}
Update Folder
PUT /grafana/api/folders/{uid}
Content-Type: application/json
{
"title": "Updated Folder Name",
"version": 1
}
Delete Folder
DELETE /grafana/api/folders/{uid}
Data Sources
List Data Sources
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 Data Source by ID
GET /grafana/api/datasources/{id}
Get Data Source by UID
GET /grafana/api/datasources/uid/{uid}
Get Data Source by Name
GET /grafana/api/datasources/name/{name}
Create Data Source
POST /grafana/api/datasources
Content-Type: application/json
{
"name": "New Prometheus",
"type": "prometheus",
"url": "http://prometheus:9090",
"access": "proxy",
"isDefault": false
}
Update Data Source
PUT /grafana/api/datasources/{id}
Content-Type: application/json
{
"name": "Updated Prometheus",
"type": "prometheus",
"url": "http://prometheus:9090",
"access": "proxy"
}
Delete Data Source
DELETE /grafana/api/datasources/{id}
Annotations
List Annotations
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 results
Create Annotation
POST /grafana/api/annotations
Content-Type: application/json
{
"dashboardUID": "abc123",
"time": 1609459200000,
"text": "Deployment completed",
"tags": ["deployment", "production"]
}
Response:
{
"message": "Annotation added",
"id": 1
}
Update Annotation
PUT /grafana/api/annotations/{id}
Content-Type: application/json
{
"text": "Updated annotation text",
"tags": ["updated"]
}
Delete Annotation
DELETE /grafana/api/annotations/{id}
Teams
Search Teams
GET /grafana/api/teams/search
Query Parameters:
query- Search querypage- Page numberperpage- Results per page
Response:
{
"totalCount": 1,
"teams": [
{
"id": 1,
"orgId": 1,
"name": "Engineering",
"email": "engineering@example.com",
"memberCount": 5
}
],
"page": 1,
"perPage": 1000
}
Get Team by ID
GET /grafana/api/teams/{id}
Create Team
POST /grafana/api/teams
Content-Type: application/json
{
"name": "New Team",
"email": "team@example.com"
}
Update Team
PUT /grafana/api/teams/{id}
Content-Type: application/json
{
"name": "Updated Team Name"
}
Delete Team
DELETE /grafana/api/teams/{id}
Alert Rules (Provisioning API)
List Alert Rules
GET /grafana/api/v1/provisioning/alert-rules
Get Alert Rule
GET /grafana/api/v1/provisioning/alert-rules/{uid}
List Alert Rules by Folder
GET /grafana/api/ruler/grafana/api/v1/rules
Service Accounts
Search Service Accounts
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
}
Plugins
List Plugins
GET /grafana/api/plugins
Response:
[
{
"name": "Prometheus",
"type": "datasource",
"id": "prometheus",
"enabled": true,
"pinned": false
}
]
Code Examples
JavaScript
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);
Python
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())
Notes
- Dashboard UIDs are unique identifiers used in most operations
- Use
/api/search?type=dash-dbto find dashboard UIDs - Folder operations require folder UIDs
- Some admin operations (list all users, orgs) require elevated permissions
- Alert rules use the provisioning API (
/api/v1/provisioning/...) - Annotations require epoch timestamps in milliseconds
Error Handling
| 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 |
Resources
Questions people ask
- Does this support creating dashboards?
- Yes. POST /api/dashboards/db creates or updates a dashboard, but only after the user sees the target identifier and explicitly approves the change.
- What is out of scope?
- Instance administration, membership changes, service account token issuance, and plugin installation are not supported.
- How is authentication handled?
- Requests carry a Bearer token set as the MATON_API_KEY environment variable; the proxy forwards calls to the connected Grafana instance using the service account token configured during connection setup.
Related skills
Grafana (grafana.com). Use this skill for ANY Grafana request — reading, creating, updating, and deleting data. Whenever a task involves Grafana, use this skill instead of calling the API directly.
Run Google Analytics reports and manage analytics configuration through a managed OAuth connection.
Access Sentry errors, issues, projects, teams, and releases through managed OAuth authentication.
Read and manage Netlify sites, deploys, builds, DNS, and env vars via an OAuth-backed API gateway.
Manage Confluence pages, spaces, blogposts, comments, and attachments via the Cloud API with managed OAuth.