Your First API Request
This guide walks you through every step from getting your API key to sending and querying data. We'll build a complete temperature monitoring setup step by step.
Overview
Here's what we'll do:
- Get your Admin API key from the dashboard
- Create a bucket to organize your data
- Create Write and Read API keys for secure access
- Create a data source to define what data you'll store
- Send data points to your bucket
- Query your data to retrieve it
- Set up an alert (optional)
Each step builds on the previous one, so follow them in order.
Step 1: Get Your Admin API Key
Your Admin API key is created when you sign up. It has full access to your organization.
From the Dashboard
- Go to app.dakkio.io
- Sign in or create an account
- Navigate to Settings → API Keys
- Copy your Admin API key (starts with
dakkio_a_)
Set Up Your Environment
Store your Admin key as an environment variable (never hardcode it):
export DAKKIO_ADMIN_KEY="dakkio_a_your_admin_key_here"
Test Your Admin Key
Verify your Admin key works by listing your buckets:
curl -X GET "https://api.dakkio.io/api/buckets" \
-H "X-API-Key: $DAKKIO_ADMIN_KEY"
Expected Response:
{
"buckets": []
}
An empty array is expected if you haven't created any buckets yet.
Step 2: Create a Bucket
A bucket is a container for your time-series data. Think of it as a project or application. For example:
- "Home Sensors" for your smart home
- "Factory Floor" for industrial monitoring
- "Weather Station" for environmental data
Each bucket can have its own data sources, API keys, and retention policy.
Create Your First Bucket
curl -X POST "https://api.dakkio.io/api/buckets" \
-H "X-API-Key: $DAKKIO_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Home Sensors",
"description": "Temperature and humidity sensors for my home"
}'
Expected Response:
{
"message": "Bucket created successfully",
"bucket": {
"_id": "507f1f77bcf86cd799439011",
"name": "Home Sensors",
"description": "Temperature and humidity sensors for my home",
"createdAt": "2024-01-15T10:00:00Z"
}
}
Save Your Bucket ID
Copy the _id from the response - you'll need it for all subsequent requests:
export BUCKET_ID="507f1f77bcf86cd799439011"
Verify Your Bucket
List your buckets to confirm it was created:
curl -X GET "https://api.dakkio.io/api/buckets" \
-H "X-API-Key: $DAKKIO_ADMIN_KEY"
Expected Response:
{
"buckets": [
{
"_id": "507f1f77bcf86cd799439011",
"name": "Home Sensors",
"description": "Temperature and humidity sensors for my home",
"createdAt": "2024-01-15T10:00:00Z"
}
]
}
Step 3: Create Write and Read API Keys
While your Admin key can do everything, it's a security risk to use it everywhere. Instead, create scoped API keys with limited permissions:
| Key Type | Prefix | What It Can Do |
|---|---|---|
| Write | dakkio_w_ | Send data, manage data sources, create alerts |
| Read | dakkio_r_ | Query data, view analytics |
This follows the principle of least privilege - give each device or service only the permissions it needs.
Create a Write Key
This key will be used by your sensors/devices to send data:
curl -X POST "https://api.dakkio.io/api/buckets/$BUCKET_ID/keys" \
-H "X-API-Key: $DAKKIO_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Living Room Sensor",
"type": "write"
}'
Expected Response:
{
"message": "API key created successfully",
"apiKey": {
"_id": "507f1f77bcf86cd799439013",
"name": "Living Room Sensor",
"type": "write",
"key": "dakkio_w_abc123def456...",
"bucketId": "507f1f77bcf86cd799439011",
"createdAt": "2024-01-15T10:05:00Z"
}
}
The full API key is only shown once when created. Copy it now and store it securely. If you lose it, you'll need to create a new one.
export DAKKIO_WRITE_KEY="dakkio_w_abc123def456..."
Create a Read Key
This key will be used by your dashboard or analytics tools to query data:
curl -X POST "https://api.dakkio.io/api/buckets/$BUCKET_ID/keys" \
-H "X-API-Key: $DAKKIO_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Dashboard Reader",
"type": "read"
}'
Expected Response:
{
"message": "API key created successfully",
"apiKey": {
"_id": "507f1f77bcf86cd799439014",
"name": "Dashboard Reader",
"type": "read",
"key": "dakkio_r_xyz789ghi012...",
"bucketId": "507f1f77bcf86cd799439011",
"createdAt": "2024-01-15T10:06:00Z"
}
}
export DAKKIO_READ_KEY="dakkio_r_xyz789ghi012..."
List Your API Keys
Verify your keys were created (note: the full key value is not shown after creation):
curl -X GET "https://api.dakkio.io/api/buckets/$BUCKET_ID/keys" \
-H "X-API-Key: $DAKKIO_ADMIN_KEY"
Expected Response:
{
"apiKeys": [
{
"_id": "507f1f77bcf86cd799439013",
"name": "Living Room Sensor",
"type": "write",
"keyPrefix": "dakkio_w_abc1...",
"createdAt": "2024-01-15T10:05:00Z"
},
{
"_id": "507f1f77bcf86cd799439014",
"name": "Dashboard Reader",
"type": "read",
"keyPrefix": "dakkio_r_xyz7...",
"createdAt": "2024-01-15T10:06:00Z"
}
]
}
Step 4: Create a Data Source
A data source defines the structure of your data. It tells dakkio:
- What type of data you're collecting (sensor, application, etc.)
- What fields/values your data will have
- What units each field uses
For example, a temperature sensor data source might have:
temperature(in Celsius)humidity(in percentage)
Create a Data Source
Use your Write key to create a data source:
curl -X POST "https://api.dakkio.io/api/buckets/$BUCKET_ID/sources" \
-H "X-API-Key: $DAKKIO_WRITE_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Temperature Sensor",
"type": "sensor",
"description": "DHT22 temperature and humidity sensor",
"schema": {
"temperature": {
"type": "number",
"unit": "celsius",
"description": "Temperature reading"
},
"humidity": {
"type": "number",
"unit": "percent",
"description": "Relative humidity"
}
}
}'
Expected Response:
{
"message": "Data source created successfully",
"dataSource": {
"_id": "507f1f77bcf86cd799439015",
"name": "Temperature Sensor",
"type": "sensor",
"description": "DHT22 temperature and humidity sensor",
"schema": {
"temperature": {
"type": "number",
"unit": "celsius",
"description": "Temperature reading"
},
"humidity": {
"type": "number",
"unit": "percent",
"description": "Relative humidity"
}
},
"status": "active",
"createdAt": "2024-01-15T10:10:00Z"
}
}
Save Your Data Source ID
export DATA_SOURCE_ID="507f1f77bcf86cd799439015"
List Your Data Sources
Verify the data source was created:
curl -X GET "https://api.dakkio.io/api/buckets/$BUCKET_ID/sources" \
-H "X-API-Key: $DAKKIO_WRITE_KEY"
Expected Response:
{
"dataSources": [
{
"_id": "507f1f77bcf86cd799439015",
"name": "Temperature Sensor",
"type": "sensor",
"status": "active",
"createdAt": "2024-01-15T10:10:00Z"
}
]
}
Step 5: Send Data Points
Now you're ready to send actual data! Use your Write key to ingest data points.
Send a Single Data Point
curl -X POST "https://api.dakkio.io/api/data" \
-H "X-API-Key: $DAKKIO_WRITE_KEY" \
-H "Content-Type: application/json" \
-d "{
\"bucketId\": \"$BUCKET_ID\",
\"dataSourceId\": \"$DATA_SOURCE_ID\",
\"timestamp\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",
\"values\": {
\"temperature\": 22.5,
\"humidity\": 65
},
\"metadata\": {
\"location\": \"Living Room\",
\"deviceId\": \"ESP32-001\"
}
}"
Expected Response:
{
"message": "Data point ingested successfully",
"dataPoint": {
"_id": "507f1f77bcf86cd799439016",
"bucketId": "507f1f77bcf86cd799439011",
"dataSourceId": "507f1f77bcf86cd799439015",
"timestamp": "2024-01-15T10:30:00Z",
"values": {
"temperature": 22.5,
"humidity": 65
},
"metadata": {
"location": "Living Room",
"deviceId": "ESP32-001"
}
}
}
Understanding the Request
| Field | Required | Description |
|---|---|---|
bucketId | Yes | The bucket to store data in |
dataSourceId | Yes | The data source defining the schema |
timestamp | Yes | ISO 8601 format (e.g., 2024-01-15T10:30:00Z) |
values | Yes | Object with your data fields |
metadata | No | Additional context (location, device ID, etc.) |
Send Multiple Data Points (Batch)
For better efficiency, send multiple readings at once:
curl -X POST "https://api.dakkio.io/api/data/batch" \
-H "X-API-Key: $DAKKIO_WRITE_KEY" \
-H "Content-Type: application/json" \
-d "{
\"bucketId\": \"$BUCKET_ID\",
\"dataPoints\": [
{
\"dataSourceId\": \"$DATA_SOURCE_ID\",
\"timestamp\": \"2024-01-15T10:00:00Z\",
\"values\": { \"temperature\": 22.0, \"humidity\": 68 }
},
{
\"dataSourceId\": \"$DATA_SOURCE_ID\",
\"timestamp\": \"2024-01-15T10:05:00Z\",
\"values\": { \"temperature\": 22.2, \"humidity\": 67 }
},
{
\"dataSourceId\": \"$DATA_SOURCE_ID\",
\"timestamp\": \"2024-01-15T10:10:00Z\",
\"values\": { \"temperature\": 22.5, \"humidity\": 65 }
}
]
}"
Expected Response:
{
"message": "Batch data ingested successfully",
"insertedCount": 3
}
Batch ingestion is more efficient than individual requests. You can send up to 1000 data points per batch request.
Step 6: Query Your Data
Now let's retrieve the data you just sent. Use your Read key for queries.
Query Recent Data
curl -X POST "https://api.dakkio.io/api/data/query" \
-H "X-API-Key: $DAKKIO_READ_KEY" \
-H "Content-Type: application/json" \
-d "{
\"bucketId\": \"$BUCKET_ID\",
\"filters\": {
\"dataSourceIds\": [\"$DATA_SOURCE_ID\"],
\"startTime\": \"2024-01-15T00:00:00Z\",
\"endTime\": \"2024-01-15T23:59:59Z\"
},
\"limit\": 100
}"
Expected Response:
{
"data": [
{
"timestamp": "2024-01-15T10:00:00Z",
"dataSourceId": "507f1f77bcf86cd799439015",
"values": { "temperature": 22.0, "humidity": 68 },
"metadata": {}
},
{
"timestamp": "2024-01-15T10:05:00Z",
"dataSourceId": "507f1f77bcf86cd799439015",
"values": { "temperature": 22.2, "humidity": 67 },
"metadata": {}
},
{
"timestamp": "2024-01-15T10:10:00Z",
"dataSourceId": "507f1f77bcf86cd799439015",
"values": { "temperature": 22.5, "humidity": 65 },
"metadata": {}
},
{
"timestamp": "2024-01-15T10:30:00Z",
"dataSourceId": "507f1f77bcf86cd799439015",
"values": { "temperature": 22.5, "humidity": 65 },
"metadata": { "location": "Living Room", "deviceId": "ESP32-001" }
}
],
"metadata": {
"count": 4,
"hasMore": false
}
}
Query with Aggregation
Get hourly averages:
curl -X POST "https://api.dakkio.io/api/data/query" \
-H "X-API-Key: $DAKKIO_READ_KEY" \
-H "Content-Type: application/json" \
-d "{
\"bucketId\": \"$BUCKET_ID\",
\"filters\": {
\"dataSourceIds\": [\"$DATA_SOURCE_ID\"],
\"startTime\": \"2024-01-15T00:00:00Z\",
\"endTime\": \"2024-01-15T23:59:59Z\"
},
\"aggregation\": \"avg\",
\"groupBy\": \"hour\"
}"
Expected Response:
{
"data": [
{
"timestamp": "2024-01-15T10:00:00Z",
"values": { "temperature": 22.3, "humidity": 66.25 }
}
],
"metadata": {
"count": 1,
"aggregation": "avg",
"groupBy": "hour"
}
}
Step 7: Set Up an Alert (Optional)
Create alerts to get notified when conditions are met. dakkio supports natural language alerts.
Create an Alert Rule
curl -X POST "https://api.dakkio.io/api/alerts" \
-H "X-API-Key: $DAKKIO_WRITE_KEY" \
-H "Content-Type: application/json" \
-d "{
\"bucketId\": \"$BUCKET_ID\",
\"dataSourceId\": \"$DATA_SOURCE_ID\",
\"name\": \"High Temperature Alert\",
\"condition\": \"temperature is greater than 30\",
\"webhookUrl\": \"https://your-webhook-url.com/alerts\"
}"
Expected Response:
{
"message": "Alert rule created successfully",
"alertRule": {
"_id": "507f1f77bcf86cd799439017",
"name": "High Temperature Alert",
"condition": "temperature is greater than 30",
"status": "active",
"createdAt": "2024-01-15T10:35:00Z"
}
}
Now whenever temperature exceeds 30°C, you'll receive a webhook notification.
Environment Variables Summary
Here's a summary of all the environment variables you should have:
# Your API keys
export DAKKIO_ADMIN_KEY="dakkio_a_..." # Full organization access
export DAKKIO_WRITE_KEY="dakkio_w_..." # Bucket write access
export DAKKIO_READ_KEY="dakkio_r_..." # Bucket read access
# Your resource IDs
export BUCKET_ID="507f1f77bcf86cd799439011"
export DATA_SOURCE_ID="507f1f77bcf86cd799439015"
Code Examples
Now that you understand the flow, here are complete code examples in different languages.
JavaScript/Node.js
const axios = require('axios');
const API_BASE = 'https://api.dakkio.io';
const ADMIN_KEY = process.env.DAKKIO_ADMIN_KEY;
const WRITE_KEY = process.env.DAKKIO_WRITE_KEY;
const READ_KEY = process.env.DAKKIO_READ_KEY;
// Helper function for API calls
async function apiCall(method, endpoint, key, data = null) {
const config = {
method,
url: `${API_BASE}${endpoint}`,
headers: {
'X-API-Key': key,
'Content-Type': 'application/json'
}
};
if (data) config.data = data;
return (await axios(config)).data;
}
// 1. Create a bucket (Admin key)
async function createBucket(name, description) {
return apiCall('POST', '/api/buckets', ADMIN_KEY, { name, description });
}
// 2. Create an API key (Admin key)
async function createApiKey(bucketId, name, type) {
return apiCall('POST', `/api/buckets/${bucketId}/keys`, ADMIN_KEY, { name, type });
}
// 3. Create a data source (Write key)
async function createDataSource(bucketId, name, type, schema) {
return apiCall('POST', `/api/buckets/${bucketId}/sources`, WRITE_KEY, {
name, type, schema
});
}
// 4. Send data (Write key)
async function sendData(bucketId, dataSourceId, values, metadata = {}) {
return apiCall('POST', '/api/data', WRITE_KEY, {
bucketId,
dataSourceId,
timestamp: new Date().toISOString(),
values,
metadata
});
}
// 5. Query data (Read key)
async function queryData(bucketId, dataSourceIds, startTime, endTime) {
return apiCall('POST', '/api/data/query', READ_KEY, {
bucketId,
filters: { dataSourceIds, startTime, endTime }
});
}
// Example usage
(async () => {
try {
// If you already have IDs, use them directly
const bucketId = process.env.BUCKET_ID;
const dataSourceId = process.env.DATA_SOURCE_ID;
// Send a data point
const result = await sendData(bucketId, dataSourceId, {
temperature: 23.5,
humidity: 62
}, {
deviceId: 'node-app-001'
});
console.log('Data sent:', result);
// Query recent data
const data = await queryData(
bucketId,
[dataSourceId],
new Date(Date.now() - 3600000).toISOString(),
new Date().toISOString()
);
console.log('Query result:', data);
} catch (error) {
console.error('Error:', error.response?.data || error.message);
}
})();
Python
import os
import requests
from datetime import datetime, timedelta
API_BASE = 'https://api.dakkio.io'
ADMIN_KEY = os.environ.get('DAKKIO_ADMIN_KEY')
WRITE_KEY = os.environ.get('DAKKIO_WRITE_KEY')
READ_KEY = os.environ.get('DAKKIO_READ_KEY')
def api_call(method, endpoint, key, data=None):
"""Helper function for API calls"""
headers = {
'X-API-Key': key,
'Content-Type': 'application/json'
}
url = f'{API_BASE}{endpoint}'
response = requests.request(method, url, headers=headers, json=data)
response.raise_for_status()
return response.json()
# 1. Create a bucket (Admin key)
def create_bucket(name, description):
return api_call('POST', '/api/buckets', ADMIN_KEY, {
'name': name,
'description': description
})
# 2. Create an API key (Admin key)
def create_api_key(bucket_id, name, key_type):
return api_call('POST', f'/api/buckets/{bucket_id}/keys', ADMIN_KEY, {
'name': name,
'type': key_type
})
# 3. Create a data source (Write key)
def create_data_source(bucket_id, name, source_type, schema):
return api_call('POST', f'/api/buckets/{bucket_id}/sources', WRITE_KEY, {
'name': name,
'type': source_type,
'schema': schema
})
# 4. Send data (Write key)
def send_data(bucket_id, data_source_id, values, metadata=None):
return api_call('POST', '/api/data', WRITE_KEY, {
'bucketId': bucket_id,
'dataSourceId': data_source_id,
'timestamp': datetime.utcnow().isoformat() + 'Z',
'values': values,
'metadata': metadata or {}
})
# 5. Query data (Read key)
def query_data(bucket_id, data_source_ids, start_time, end_time):
return api_call('POST', '/api/data/query', READ_KEY, {
'bucketId': bucket_id,
'filters': {
'dataSourceIds': data_source_ids,
'startTime': start_time,
'endTime': end_time
}
})
# Example usage
if __name__ == '__main__':
bucket_id = os.environ.get('BUCKET_ID')
data_source_id = os.environ.get('DATA_SOURCE_ID')
# Send a data point
result = send_data(bucket_id, data_source_id, {
'temperature': 23.5,
'humidity': 62
}, {
'deviceId': 'python-app-001'
})
print('Data sent:', result)
# Query recent data
end_time = datetime.utcnow()
start_time = end_time - timedelta(hours=1)
data = query_data(
bucket_id,
[data_source_id],
start_time.isoformat() + 'Z',
end_time.isoformat() + 'Z'
)
print('Query result:', data)
Arduino/ESP32
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <time.h>
// WiFi credentials
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
// dakkio API configuration
const char* apiBase = "https://api.dakkio.io";
const char* writeKey = "dakkio_w_..."; // Your Write key
const char* bucketId = "507f1f77bcf86cd799439011";
const char* dataSourceId = "507f1f77bcf86cd799439015";
// NTP for timestamps
const char* ntpServer = "pool.ntp.org";
void setup() {
Serial.begin(115200);
// Connect to WiFi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi connected");
// Initialize NTP
configTime(0, 0, ntpServer);
}
String getISOTimestamp() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
return "2024-01-15T10:00:00Z"; // Fallback
}
char buffer[30];
strftime(buffer, sizeof(buffer), "%Y-%m-%dT%H:%M:%SZ", &timeinfo);
return String(buffer);
}
bool sendData(float temperature, float humidity) {
if (WiFi.status() != WL_CONNECTED) {
Serial.println("WiFi not connected");
return false;
}
HTTPClient http;
String url = String(apiBase) + "/api/data";
http.begin(url);
http.addHeader("Content-Type", "application/json");
http.addHeader("X-API-Key", writeKey);
// Build JSON payload
StaticJsonDocument<512> doc;
doc["bucketId"] = bucketId;
doc["dataSourceId"] = dataSourceId;
doc["timestamp"] = getISOTimestamp();
JsonObject values = doc.createNestedObject("values");
values["temperature"] = temperature;
values["humidity"] = humidity;
JsonObject metadata = doc.createNestedObject("metadata");
metadata["deviceId"] = "ESP32-001";
metadata["location"] = "Living Room";
String payload;
serializeJson(doc, payload);
Serial.println("Sending: " + payload);
int httpCode = http.POST(payload);
String response = http.getString();
http.end();
if (httpCode == 201) {
Serial.println("Success: " + response);
return true;
} else {
Serial.printf("Error %d: %s\n", httpCode, response.c_str());
return false;
}
}
void loop() {
// Read from your sensors (replace with actual sensor readings)
float temperature = 22.5 + random(-10, 10) / 10.0;
float humidity = 65.0 + random(-5, 5);
sendData(temperature, humidity);
delay(60000); // Send every minute
}
Common Errors
401 Unauthorized
{
"error": "Unauthorized",
"message": "Invalid or missing API key"
}
Solutions:
- Check that you're using
X-API-Keyheader (notAuthorization) - Verify the API key is correct
- Ensure the key hasn't been deleted
403 Forbidden
{
"error": "Forbidden",
"message": "Insufficient permissions"
}
Solutions:
- Use the correct key type:
- Admin key for bucket and key management
- Write key for data ingestion and data sources
- Read key for queries
- For bucket-scoped keys, verify the bucket ID matches
400 Validation Error
{
"error": "Validation Error",
"details": [
{
"path": ["body", "bucketId"],
"message": "Expected string, received undefined"
}
]
}
Solutions:
- Check all required fields are included
- Verify data types match the schema
- Ensure IDs are valid 24-character hex strings
Next Steps
You've completed the basics! Here's where to go next:
- API Playground - Test endpoints interactively
- API Reference - Complete endpoint documentation
- Alert Rules Guide - Advanced alerting
- Examples - More code examples