Working with Grafana API
1. Authenticating API Requests
| Authentication Method | Description | Usage | Notes |
|---|---|---|---|
| API Key | Generated in Grafana UI for service accounts or users | Authorization: Bearer <api_key> |
Can be scoped to specific permissions |
| Personal Access Token | Generated in user profile settings | Authorization: Bearer <token> |
Scoped to user permissions |
| Basic Auth | Username/password combination | Authorization: Basic base64(<username>:<password>) |
Requires Grafana to have basic auth enabled |
Example: Using API Key
curl -H "Authorization: Bearer eyJrIjoi..." \
http://localhost:3000/api/dashboards/home</code>
</pre>
</div>
</div>
<div class="note">
<strong>Note:</strong> API keys can be generated via the Grafana UI under <code>Configuration > API Keys</code> or <code>Service Accounts</code>.
</div>
<div class="warning">
<strong>Warning:</strong> Never expose API keys in client-side code or version control.
</div>
<h2 id="2-using-dashboard-api">2. Using Dashboard API<a href="#2-using-dashboard-api" class="toc__headingLink" aria-label="Link to this section"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg></a></h2>
<table>
<tbody>
<tr>
<th>Endpoint</th>
<th>Method</th>
<th>Description</th>
<th>Notes</th>
</tr>
<tr>
<td class="property">/api/dashboards/db</td>
<td>POST</td>
<td>Create a new dashboard</td>
<td>Requires write permissions</td>
</tr>
<tr>
<td class="property">/api/dashboards/db</td>
<td>PUT</td>
<td>Update an existing dashboard</td>
<td>Overwrites the entire dashboard JSON</td>
</tr>
<tr>
<td class="property">/api/dashboards/uid/{uid}</td>
<td>GET</td>
<td>Get a dashboard by UID</td>
<td>Returns full dashboard JSON</td>
</tr>
<tr>
<td class="property">/api/dashboards/id/{id}</td>
<td>GET</td>
<td>Get a dashboard by ID</td>
<td>Returns full dashboard JSON</td>
</tr>
<tr>
<td class="property">/api/dashboards/id/{id}</td>
<td>DELETE</td>
<td>Delete a dashboard by ID</td>
<td>Deletes the dashboard permanently</td>
</tr>
</tbody>
</table>
<div class="example">
<h2 id="example-create-a-new-dashboard">Example: Create a new dashboard<a href="#example-create-a-new-dashboard" class="toc__headingLink" aria-label="Link to this section"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg></a></h2>
<div class="codeBlock" data-language="json">
<pre><code>{
"dashboard": {
"title": "My New Dashboard",
"panels": [
{
"id": 1,
"type": "graph",
"title": "CPU Usage"
}
]
},
"folderId": 0,
"overwrite": false
}
Example: Update an existing dashboard
{
"dashboard": {
"id": 123,
"title": "Updated Dashboard Title",
"panels": [
{
"id": 1,
"type": "graph",
"title": "CPU Usage"
}
]
},
"overwrite": true
}
Note: The
overwrite parameter controls whether to overwrite an existing dashboard with the same name. If set to false, a new version will be created.
3. Using Data Source API
| Endpoint | Method | Description | Notes |
|---|---|---|---|
| /api/datasources | GET | Get all data sources | Returns list of data sources with their IDs and names |
| /api/datasources | POST | Create a new data source | Requires admin permissions |
| /api/datasources/:id | GET | Get a specific data source | Fetches details of a single data source by ID |
| /api/datasources/:id | PUT | Update a data source | Updates configuration of an existing data source |
| /api/datasources/:id | DELETE | Delete a data source | Removes the specified data source from Grafana |
Example: Create a new data source
{
"name": "Prometheus",
"type": "prometheus",
"url": "http://localhost:9090",
"access": "proxy",
"isDefault": false
}
Example: Update data source configuration
{
"id": 1,
"name": "Prometheus Updated",
"type": "prometheus",
"url": "http://localhost:9091",
"access": "proxy",
"isDefault": true
}
Note: The
access field can be either proxy or direct. Proxy mode is recommended for security reasons.
Warning: When updating a data source, make sure to include all existing fields to avoid overwriting them.
4. Using User API
| Endpoint | Method | Description | Notes |
|---|---|---|---|
| /api/users | GET | Get all users | Requires admin permissions |
| /api/users | POST | Create a new user | Requires admin permissions |
| /api/users/{id} | GET | Get a specific user by ID | |
| /api/users/{id} | PUT | Update a user's details | |
| /api/users/{id} | DELETE | Delete a user | Requires admin permissions |
Example: Create a new user
{
"name": "John Doe",
"email": "john.doe@example.com",
"login": "johndoe",
"password": "securePassword123"
}
Note: The
password field is only required when creating a new user and will be hashed before storage.
Warning: Ensure that the
login and email fields are unique across all users in the Grafana instance.
5. Using Organization API
| Endpoint | Method | Description | Notes |
|---|---|---|---|
| /api/org | GET | Get current organization details | |
| /api/org | PUT | Update current organization details | |
| /api/org/users | GET | Get all users in current organization | |
| /api/org/users | POST | Add a user to current organization | |
| /api/org/users/{userId} | DELETE | Remove a user from current organization |
Example: Get Current Organization Details
curl -H "Authorization: Bearer <API_TOKEN>" \
-H "Content-Type: application/json" \
https://grafana.example.com/api/org
Example: Update Organization Name
curl -H "Authorization: Bearer <API_TOKEN>" \
-H "Content-Type: application/json" \
-X PUT \
https://grafana.example.com/api/org \
-d '{"name": "New Org Name"}'
Example: Add User to Organization
curl -H "Authorization: Bearer <API_TOKEN>" \
-H "Content-Type: application/json" \
-X POST \
https://grafana.example.com/api/org/users \
-d '{"loginOrEmail": "user@example.com", "role": "Editor"}'
6. Using Search API
| Field | Description | Example |
|---|---|---|
| query | Search query string to match against dashboard titles, tags, and folder names | prod |
| limit | Maximum number of results to return (default: 1000) | 50 |
| folderIds | Array of folder IDs to search within | [1, 2] |
| tag | Tag to filter dashboards by | database |
| type | Filter by dashboard type (e.g., dash-db, dash-folder) |
dash-db |
Example: Search for dashboards containing "prod"
curl -H "Authorization: Bearer <API_TOKEN>" \
"http://localhost:3000/api/search?query=prod&limit=10"
Example: Search in specific folders
const searchParams = {
query: "db",
folderIds: [1, 3],
limit: 20
};
fetch("http://localhost:3000/api/search", {
method: "GET",
headers: {
"Authorization": "Bearer <API_TOKEN>",
"Content-Type": "application/json"
},
params: searchParams
})
Note: The search API supports filtering by tags and folder IDs. Results are returned as an array of dashboard objects with minimal metadata.
7. Using Annotation API
| Endpoint | Method | Description | Notes |
|---|---|---|---|
| /api/annotations | POST | Create a new annotation | Requires write permission |
| /api/annotations | GET | Fetch annotations | Supports filtering by time range, dashboard, and tags |
| /api/annotations/{id} | PUT | Update an annotation | Update by ID |
| /api/annotations/{id} | DELETE | Delete an annotation | Deletes by ID |
Example: Create Annotation
{
"dashboardId": 123,
"panelId": 456,
"time": 1678886400000,
"text": "Deployment completed",
"tags": ["deployment", "prod"]
}
Example: Fetch Annotations
curl -H "Authorization: Bearer <token>" \
"http://localhost:3000/api/annotations?from=1678886400000&to=1678972800000"
Note: Annotations are stored in the Grafana database and can be used for tracking events or changes in your infrastructure.
8. Using Alert API
| Endpoint | Method | Description | Notes |
|---|---|---|---|
| /api/v1/rules | GET | Retrieve all alert rules | Requires admin permissions |
| /api/v1/rules | POST | Create a new alert rule | Supports JSON payload with rule definition |
| /api/v1/rules/{ruleUID} | PUT | Update an existing alert rule | Rule UID is required to identify the rule |
| /api/v1/rules/{ruleUID} | DELETE | Delete an alert rule | Rule UID is required to identify the rule |
Example: Create an Alert Rule
{
"name": "CPU Usage Alert",
"condition": "A > 80",
"for": "5m",
"labels": {
"severity": "warning"
},
"annotations": {
"summary": "High CPU usage detected"
}
}
Example: Retrieve Alert Rules
curl -H "Authorization: Bearer <API_TOKEN>" \
-H "Content-Type: application/json" \
http://localhost:3000/api/v1/rules
Note: Alert rules are managed via the Grafana API v1 and require appropriate permissions to read or modify.
9. Using Snapshot API
| Field | Description | Example |
|---|---|---|
| dashboard | The dashboard JSON object to create a snapshot from | {"title": "My Dashboard", ...} |
| expires | Expiration time in seconds (default is 2592000 = 30 days) | 86400 |
| name | Name of the snapshot (optional) | "Production Metrics" |
Example: Create a Snapshot
const snapshot = {
dashboard: {
title: "Production Metrics",
panels: [],
...
},
expires: 86400,
name: "Daily Production Snapshot"
};
fetch("/api/snapshots", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(snapshot)
})
.then(res => res.json())
.then(data => console.log("Snapshot URL:", data.url));
Note: Snapshots are public by default and accessible without authentication. Ensure sensitive dashboards are not shared via snapshots.
Warning: Snapshots are stored in Grafana's database and can consume significant storage if not managed properly.
10. Using Health API
| Endpoint | Method | Description | Notes |
|---|---|---|---|
| /api/health | GET |
Check Grafana server health status | Returns status of the Grafana instance including version, database status, and uptime |
Example: Check Grafana Health
curl -H "Authorization: Bearer <API_TOKEN>" http://localhost:3000/api/health
Example: Health Response
{
"commit": "abc123",
"database": "connected",
"edition": "oss",
"version": "11.0.0"
}
11. Using Folder API
| Endpoint | Method | Description | Notes |
|---|---|---|---|
| /api/folders | GET |
Get all folders | Returns list of folders with basic info |
| /api/folders | POST |
Create a new folder | Requires title and UID (optional) |
/api/folders/folderUid |
GET |
Get folder by UID | Returns full folder details |
/api/folders/folderUid |
PUT |
Update folder | Update title or description |
/api/folders/folderUid |
DELETE |
Delete folder | Deletes folder and all dashboards inside |
Example: Get all folders
curl --request GET \
--url 'http://localhost:3000/api/folders' \
--header 'Authorization: Bearer <your_token>'
Note: Folder UIDs are unique identifiers used to reference folders in API calls.
12. Handling API Errors
| Error Code | Description | Handling Recommendation |
|---|---|---|
| 400 | Bad Request - Invalid syntax or malformed request | Validate input parameters and request format before sending |
| 401 | Unauthorized - Missing or invalid API key/token | Ensure valid authentication credentials are included in the request header |
| 403 | Forbidden - Insufficient permissions to access resource | Verify user role and permissions in Grafana |
| 404 | Not Found - Resource does not exist | Check resource ID or path for correctness |
| 429 | Rate Limited - Too many requests within time window | Implement retry logic with exponential backoff |
| 500 | Internal Server Error - Server-side issue | Retry after delay or contact Grafana support |
| 503 | Service Unavailable - Grafana is temporarily unavailable | Implement circuit breaker pattern and retry logic |
Example: Error Handling in JavaScript
const response = await fetch("https://grafana.example.com/api/dashboards/uid/my-dashboard", {
headers: {
"Authorization": "Bearer <API_TOKEN>"
}
});
if (!response.ok) {
switch (response.status) {
case 400:
console.error("Invalid request parameters");
break;
case 401:
console.error("Authentication failed");
break;
case 403:
console.error("Access denied");
break;
case 404:
console.error("Dashboard not found");
break;
case 429:
console.error("Rate limit exceeded");
break;
default:
console.error(`Unexpected error: ${response.status}`);
}
} else {
const data = await response.json();
console.log("Dashboard loaded successfully", data);
}
Note: Grafana API responses include a
X-Response-Time header that can help identify performance issues related to API errors.
Warning: Always implement retry logic with exponential backoff for 429 (Rate Limited) and 503 (Service Unavailable) errors to prevent overwhelming the server.