Skip to main content

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:

  1. Get your Admin API key from the dashboard
  2. Create a bucket to organize your data
  3. Create Write and Read API keys for secure access
  4. Create a data source to define what data you'll store
  5. Send data points to your bucket
  6. Query your data to retrieve it
  7. 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

  1. Go to app.dakkio.io
  2. Sign in or create an account
  3. Navigate to SettingsAPI Keys
  4. 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 TypePrefixWhat It Can Do
Writedakkio_w_Send data, manage data sources, create alerts
Readdakkio_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"
}
}
Save Your Key!

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

FieldRequiredDescription
bucketIdYesThe bucket to store data in
dataSourceIdYesThe data source defining the schema
timestampYesISO 8601 format (e.g., 2024-01-15T10:30:00Z)
valuesYesObject with your data fields
metadataNoAdditional 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

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-Key header (not Authorization)
  • 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: