KoKonna OpenAPI: Build Your Own Smart Art Frame Integration
Apr 13, 2026
KoKonna OpenAPI: Build Your Own Smart Art Frame Integration
A developer's guide to controlling KoKonna e-ink frames via HTTPS
Introduction
KoKonna isn't just a beautiful e-ink art frame—it's also a developer-friendly platform. With the KoKonna OpenAPI, you can programmatically control your frame, upload images, and build custom integrations that make your art frame part of your smart home ecosystem.
Whether you want to:
- Build a custom mobile app
- Create automated art curation systems
- Integrate with home automation platforms
- Develop AI-powered art generation pipelines
The KoKonna OpenAPI gives you full control over your frame with a simple, token-based REST API.

Getting Started
Base URL
All API requests are made to:
https://api.galaxyguide.cn/openapi
Authentication
KoKonna uses Bearer token authentication. Your token is the device's API key, which you can find in your frame's settings page.
Required Headers:
Authorization: Bearer <API_KEY>Content-Type: application/json
Getting Your API Key:
- Open your KoKonna frame settings
- Navigate to the API section
- Copy your device's API key
Rate Limiting
The API enforces a rate limit of 20 requests per minute per device key.
If you exceed this limit, you'll receive:
{"message": "Too many requests, please try again later."}
API Endpoints
1. Get Device Information
Retrieve your frame's current status, battery level, screen dimensions, and more.
Endpoint:POST/device
Request Body:{} (empty or omitted)
Example:
curl -X POST https://api.galaxyguide.cn/openapi/device \-H "Authorization: Bearer YOUR_API_KEY" \-H "Content-Type: application/json" \-d '{}'
Response:
{"firmware": "B100V260412N","nickname": "Living Room Frame","lastHeartbeat": "2026-04-13T05:20:15.123Z","isCharging": false,"batteryLevel": 87,"sdUsedSize": 0,"switchType": "queue","switchMinute": 60,"imageId": 75612,"coverId": null,"timezone": "Asia/Shanghai","point": 20,"screenWidth": 800,"screenHeight": 480,"screenRotate": 270,"synced": true,"online": true}
Key Fields:
| Field | Description |
|---|---|
firmware |
Current firmware version |
nickname |
Device nickname |
batteryLevel |
Battery percentage (0-100) |
isCharging |
Whether the device is charging |
screenWidth/Height |
Physical screen dimensions in pixels |
screenRotate |
Screen rotation angle (0, 90, 180, 270) |
online |
Whether the device is currently online |
synced |
Whether the device has applied the latest image |
2. Upload Image
Upload a new image to your frame. The image will automatically become the active display.
Endpoint:POST/upload
Request Body:
{"base64": "<BASE64_IMAGE_DATA>","name": "my-artwork.jpg"}
Important Notes:
base64is required and must be raw base64 data (nodata:image/jpeg;base64,prefix)nameis optional and defaults to the uploaded filename- Maximum payload size: 50 MB
- Images are automatically cropped to match your device's display aspect ratio
Example:
# Convert image to base64 and uploadIMAGE_BASE64=$(base64 -w 0 my-artwork.jpg)curl -X POST https://api.galaxyguide.cn/openapi/upload \-H "Authorization: Bearer YOUR_API_KEY" \-H "Content-Type: application/json" \-d "{\"base64\":\"$IMAGE_BASE64\",\"name\":\"my-artwork.jpg\"}"
Response:
{"id": 789,"counter": 10}
id: The created image IDcounter: Updated frame image counter
3. Display Image by ID
Switch to a previously uploaded image by its ID.
Endpoint:POST/displayImageById
Request Body:
{"imageId": 123}
Example:
curl -X POST https://api.galaxyguide.cn/openapi/displayImageById \-H "Authorization: Bearer YOUR_API_KEY" \-H "Content-Type: application/json" \-d '{"imageId":123}'
Response:
{"success": true}
4. Display Image by Name
Switch to a previously uploaded image by its filename.
Endpoint:POST/displayImageByName
Request Body:
{"imageName": "sunset.jpg"}
Example:
curl -X POST https://api.galaxyguide.cn/openapi/displayImageByName \-H "Authorization: Bearer YOUR_API_KEY" \-H "Content-Type: application/json" \-d '{"imageName":"sunset.jpg"}'
Response:
{"success": true}
Code Examples
Python
import base64import requestsclass KoKonnaFrame:def __init__(self, api_key):self.api_key = api_keyself.base_url = "https://api.galaxyguide.cn/openapi"self.headers = {"Authorization": f"Bearer {api_key}","Content-Type": "application/json"}def get_device_info(self):"""Get device information"""response = requests.post(f"{self.base_url}/device",headers=self.headers,json={})return response.json()def upload_image(self, image_path, name=None):"""Upload an image to the frame"""with open(image_path, "rb") as f:image_data = base64.b64encode(f.read()).decode('utf-8')payload = {"base64": image_data}if name:payload["name"] = nameresponse = requests.post(f"{self.base_url}/upload",headers=self.headers,json=payload)return response.json()def display_image_by_id(self, image_id):"""Display an image by its ID"""response = requests.post(f"{self.base_url}/displayImageById",headers=self.headers,json={"imageId": image_id})return response.json()def display_image_by_name(self, image_name):"""Display an image by its name"""response = requests.post(f"{self.base_url}/displayImageByName",headers=self.headers,json={"imageName": image_name})return response.json()# Usageframe = KoKonnaFrame("your-api-key-here")# Get device infoinfo = frame.get_device_info()print(f"Battery: {info['batteryLevel']}%")print(f"Online: {info['online']}")# Upload and display an imageresult = frame.upload_image("artwork.jpg", name="My Artwork")print(f"Uploaded! Image ID: {result['id']}")# Switch to a previous imageframe.display_image_by_name("sunset.jpg")
JavaScript / Node.js
const fs = require('fs');const axios = require('axios');class KoKonnaFrame {constructor(apiKey) {this.apiKey = apiKey;this.baseURL = 'https://api.galaxyguide.cn/openapi';this.headers = {'Authorization': `Bearer ${apiKey}`,'Content-Type': 'application/json'};}async getDeviceInfo() {const response = await axios.post(`${this.baseURL}/device`,{},{ headers: this.headers });return response.data;}async uploadImage(imagePath, name = null) {const imageBuffer = fs.readFileSync(imagePath);const base64 = imageBuffer.toString('base64');const payload = { base64 };if (name) payload.name = name;const response = await axios.post(`${this.baseURL}/upload`,payload,{ headers: this.headers });return response.data;}async displayImageById(imageId) {const response = await axios.post(`${this.baseURL}/displayImageById`,{ imageId },{ headers: this.headers });return response.data;}async displayImageByName(imageName) {const response = await axios.post(`${this.baseURL}/displayImageByName`,{ imageName },{ headers: this.headers });return response.data;}}// Usageconst frame = new KoKonnaFrame('your-api-key-here');// Get device infoconst info = await frame.getDeviceInfo();console.log(`Battery: ${info.batteryLevel}%`);// Upload imageconst result = await frame.uploadImage('artwork.jpg', 'My Artwork');console.log(`Uploaded! Image ID: ${result.id}`);
Use Cases
1. Automated Weather Art
Display art that matches the weather:
import requestsfrom PIL import Imagedef get_weather_art(weather_condition):# Generate or fetch weather-appropriate art# This could use an AI API, weather APIs, etc.passdef update_frame_with_weather(frame, weather_condition):art_path = get_weather_art(weather_condition)frame.upload_image(art_path, name=f"weather-{weather_condition}.jpg")# Run every morningframe = KoKonnaFrame("your-api-key")update_frame_with_weather(frame, "sunny")
2. Photo Album Slideshow
Create a rotating slideshow from your photo collection:
import osimport timefrom pathlib import Pathdef slideshow(frame, photo_dir, interval_minutes=60):photos = list(Path(photo_dir).glob("*.jpg"))for photo in photos:frame.upload_image(str(photo))time.sleep(interval_minutes * 60)frame = KoKonnaFrame("your-api-key")slideshow(frame, "/path/to/photos")
3. Smart Home Integration
Integrate with Home Assistant or other platforms:
# Home Assistant automation exampleautomation:- alias: "Update Frame at Sunrise"trigger:- platform: sunevent: sunriseaction:- service: rest_command.kokonna_uploaddata:image: "/config/art/morning.jpg"
4. AI Art Generator
Connect to AI image generation APIs:
import openaidef generate_and_display(prompt):# Generate image with DALL-Eresponse = openai.Image.create(prompt=prompt, size="1024x1024")image_url = response['data'][0]['url']# Download and upload to frameimage_data = requests.get(image_url).contentbase64_image = base64.b64encode(image_data).decode('utf-8')frame = KoKonnaFrame("your-api-key")# Upload directly with base64# (implementation depends on your upload method)
Error Handling
The API returns standard HTTP status codes:
| Status Code | Meaning |
|---|---|
| 200 | Success |
| 404 | Unknown endpoint |
| 429 | Rate limit exceeded |
| 500 | Server error (device not found, etc.) |
Common Errors:
// Device not found{"message": "can not find robot <apikey>"}// Rate limit exceeded{"message": "Too many requests, please try again later."}// Image not found{"message": "image not found"}
Best Practices
1. Image Sizing
Match your image aspect ratio to your device's screen:
from PIL import Imagedef resize_for_frame(image_path, frame_width, frame_height):img = Image.open(image_path)# Calculate target ratiotarget_ratio = frame_width / frame_heightcurrent_ratio = img.width / img.height# Crop to matchif current_ratio > target_ratio:# Image is too widenew_width = int(img.height * target_ratio)left = (img.width - new_width) // 2img = img.crop((left, 0, left + new_width, img.height))else:# Image is too tallnew_height = int(img.width / target_ratio)top = (img.height - new_height) // 2img = img.crop((0, top, img.width, top + new_height))# Resize to exact dimensionsimg = img.resize((frame_width, frame_height), Image.LANCZOS)return img
2. Rate Limit Management
Implement request queuing:
import timefrom collections import dequeclass RateLimitedClient:def __init__(self, api_key, max_requests=20, per_minutes=1):self.frame = KoKonnaFrame(api_key)self.requests = deque()self.max_requests = max_requestsself.per_minutes = per_minutesdef _wait_if_needed(self):now = time.time()# Remove old requestswhile self.requests and self.requests[0] < now - self.per_minutes * 60:self.requests.popleft()# Wait if at limitif len(self.requests) >= self.max_requests:sleep_time = self.requests[0] + self.per_minutes * 60 - nowtime.sleep(sleep_time)self.requests.append(now)
3. Battery Optimization
Check device status before uploads:
def smart_upload(frame, image_path):info = frame.get_device_info()if not info['online']:print("Device is offline, skipping upload")return Falseif info['batteryLevel'] < 20 and not info['isCharging']:print("Battery low, skipping upload")return Falsereturn frame.upload_image(image_path)
Conclusion
The KoKonna OpenAPI provides a simple yet powerful way to integrate your e-ink art frame into any workflow or application. With just a few API calls, you can:
- Monitor your frame's status
- Upload and display custom artwork
- Build automated art curation systems
- Create smart home integrations
Whether you're a hobbyist building a personal project or a developer creating commercial integrations, the KoKonna OpenAPI gives you the tools to make your art frame truly smart.
Resources
- API Documentation: kokonna.art/pages/openapi
- KoKonna Website: kokonna.art
- Support: support@kokonna.art
Have questions or built something cool? We'd love to hear from you! Reach out at support@kokonna.art or tag us on Instagram @KoKonna365.