Skip to content
KoKonna OpenAPI: Build Your Own Smart Art Frame Integration KoKonna OpenAPI: Build Your Own Smart Art Frame Integration

KoKonna OpenAPI: Build Your Own Smart Art Frame Integration

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:

  1. 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:

  1. Authorization: Bearer <API_KEY>
  2. Content-Type: application/json

Getting Your API Key:

  1. Open your KoKonna frame settings
  2. Navigate to the API section
  3. 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:

  1. {
  2. "message": "Too many requests, please try again later."
  3. }

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:

  1. curl -X POST https://api.galaxyguide.cn/openapi/device \
  2. -H "Authorization: Bearer YOUR_API_KEY" \
  3. -H "Content-Type: application/json" \
  4. -d '{}'

Response:

  1. {
  2. "firmware": "B100V260412N",
  3. "nickname": "Living Room Frame",
  4. "lastHeartbeat": "2026-04-13T05:20:15.123Z",
  5. "isCharging": false,
  6. "batteryLevel": 87,
  7. "sdUsedSize": 0,
  8. "switchType": "queue",
  9. "switchMinute": 60,
  10. "imageId": 75612,
  11. "coverId": null,
  12. "timezone": "Asia/Shanghai",
  13. "point": 20,
  14. "screenWidth": 800,
  15. "screenHeight": 480,
  16. "screenRotate": 270,
  17. "synced": true,
  18. "online": true
  19. }

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:

  1. {
  2. "base64": "<BASE64_IMAGE_DATA>",
  3. "name": "my-artwork.jpg"
  4. }

Important Notes:

  • base64 is required and must be raw base64 data (nodata:image/jpeg;base64, prefix)
  • name is 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:

  1. # Convert image to base64 and upload
  2. IMAGE_BASE64=$(base64 -w 0 my-artwork.jpg)
  3. curl -X POST https://api.galaxyguide.cn/openapi/upload \
  4. -H "Authorization: Bearer YOUR_API_KEY" \
  5. -H "Content-Type: application/json" \
  6. -d "{\"base64\":\"$IMAGE_BASE64\",\"name\":\"my-artwork.jpg\"}"

Response:

  1. {
  2. "id": 789,
  3. "counter": 10
  4. }
  • id: The created image ID
  • counter: Updated frame image counter

3. Display Image by ID

Switch to a previously uploaded image by its ID.

Endpoint:POST/displayImageById

Request Body:

  1. {
  2. "imageId": 123
  3. }

Example:

  1. curl -X POST https://api.galaxyguide.cn/openapi/displayImageById \
  2. -H "Authorization: Bearer YOUR_API_KEY" \
  3. -H "Content-Type: application/json" \
  4. -d '{"imageId":123}'

Response:

  1. {
  2. "success": true
  3. }

4. Display Image by Name

Switch to a previously uploaded image by its filename.

Endpoint:POST/displayImageByName

Request Body:

  1. {
  2. "imageName": "sunset.jpg"
  3. }

Example:

  1. curl -X POST https://api.galaxyguide.cn/openapi/displayImageByName \
  2. -H "Authorization: Bearer YOUR_API_KEY" \
  3. -H "Content-Type: application/json" \
  4. -d '{"imageName":"sunset.jpg"}'

Response:

  1. {
  2. "success": true
  3. }

Code Examples

Python

  1. import base64
  2. import requests
  3. class KoKonnaFrame:
  4. def __init__(self, api_key):
  5. self.api_key = api_key
  6. self.base_url = "https://api.galaxyguide.cn/openapi"
  7. self.headers = {
  8. "Authorization": f"Bearer {api_key}",
  9. "Content-Type": "application/json"
  10. }
  11. def get_device_info(self):
  12. """Get device information"""
  13. response = requests.post(
  14. f"{self.base_url}/device",
  15. headers=self.headers,
  16. json={}
  17. )
  18. return response.json()
  19. def upload_image(self, image_path, name=None):
  20. """Upload an image to the frame"""
  21. with open(image_path, "rb") as f:
  22. image_data = base64.b64encode(f.read()).decode('utf-8')
  23. payload = {"base64": image_data}
  24. if name:
  25. payload["name"] = name
  26. response = requests.post(
  27. f"{self.base_url}/upload",
  28. headers=self.headers,
  29. json=payload
  30. )
  31. return response.json()
  32. def display_image_by_id(self, image_id):
  33. """Display an image by its ID"""
  34. response = requests.post(
  35. f"{self.base_url}/displayImageById",
  36. headers=self.headers,
  37. json={"imageId": image_id}
  38. )
  39. return response.json()
  40. def display_image_by_name(self, image_name):
  41. """Display an image by its name"""
  42. response = requests.post(
  43. f"{self.base_url}/displayImageByName",
  44. headers=self.headers,
  45. json={"imageName": image_name}
  46. )
  47. return response.json()
  48. # Usage
  49. frame = KoKonnaFrame("your-api-key-here")
  50. # Get device info
  51. info = frame.get_device_info()
  52. print(f"Battery: {info['batteryLevel']}%")
  53. print(f"Online: {info['online']}")
  54. # Upload and display an image
  55. result = frame.upload_image("artwork.jpg", name="My Artwork")
  56. print(f"Uploaded! Image ID: {result['id']}")
  57. # Switch to a previous image
  58. frame.display_image_by_name("sunset.jpg")

JavaScript / Node.js

  1. const fs = require('fs');
  2. const axios = require('axios');
  3. class KoKonnaFrame {
  4. constructor(apiKey) {
  5. this.apiKey = apiKey;
  6. this.baseURL = 'https://api.galaxyguide.cn/openapi';
  7. this.headers = {
  8. 'Authorization': `Bearer ${apiKey}`,
  9. 'Content-Type': 'application/json'
  10. };
  11. }
  12. async getDeviceInfo() {
  13. const response = await axios.post(
  14. `${this.baseURL}/device`,
  15. {},
  16. { headers: this.headers }
  17. );
  18. return response.data;
  19. }
  20. async uploadImage(imagePath, name = null) {
  21. const imageBuffer = fs.readFileSync(imagePath);
  22. const base64 = imageBuffer.toString('base64');
  23. const payload = { base64 };
  24. if (name) payload.name = name;
  25. const response = await axios.post(
  26. `${this.baseURL}/upload`,
  27. payload,
  28. { headers: this.headers }
  29. );
  30. return response.data;
  31. }
  32. async displayImageById(imageId) {
  33. const response = await axios.post(
  34. `${this.baseURL}/displayImageById`,
  35. { imageId },
  36. { headers: this.headers }
  37. );
  38. return response.data;
  39. }
  40. async displayImageByName(imageName) {
  41. const response = await axios.post(
  42. `${this.baseURL}/displayImageByName`,
  43. { imageName },
  44. { headers: this.headers }
  45. );
  46. return response.data;
  47. }
  48. }
  49. // Usage
  50. const frame = new KoKonnaFrame('your-api-key-here');
  51. // Get device info
  52. const info = await frame.getDeviceInfo();
  53. console.log(`Battery: ${info.batteryLevel}%`);
  54. // Upload image
  55. const result = await frame.uploadImage('artwork.jpg', 'My Artwork');
  56. console.log(`Uploaded! Image ID: ${result.id}`);

Use Cases

1. Automated Weather Art

Display art that matches the weather:

  1. import requests
  2. from PIL import Image
  3. def get_weather_art(weather_condition):
  4. # Generate or fetch weather-appropriate art
  5. # This could use an AI API, weather APIs, etc.
  6. pass
  7. def update_frame_with_weather(frame, weather_condition):
  8. art_path = get_weather_art(weather_condition)
  9. frame.upload_image(art_path, name=f"weather-{weather_condition}.jpg")
  10. # Run every morning
  11. frame = KoKonnaFrame("your-api-key")
  12. update_frame_with_weather(frame, "sunny")

2. Photo Album Slideshow

Create a rotating slideshow from your photo collection:

  1. import os
  2. import time
  3. from pathlib import Path
  4. def slideshow(frame, photo_dir, interval_minutes=60):
  5. photos = list(Path(photo_dir).glob("*.jpg"))
  6. for photo in photos:
  7. frame.upload_image(str(photo))
  8. time.sleep(interval_minutes * 60)
  9. frame = KoKonnaFrame("your-api-key")
  10. slideshow(frame, "/path/to/photos")

3. Smart Home Integration

Integrate with Home Assistant or other platforms:

  1. # Home Assistant automation example
  2. automation:
  3. - alias: "Update Frame at Sunrise"
  4. trigger:
  5. - platform: sun
  6. event: sunrise
  7. action:
  8. - service: rest_command.kokonna_upload
  9. data:
  10. image: "/config/art/morning.jpg"

4. AI Art Generator

Connect to AI image generation APIs:

  1. import openai
  2. def generate_and_display(prompt):
  3. # Generate image with DALL-E
  4. response = openai.Image.create(prompt=prompt, size="1024x1024")
  5. image_url = response['data'][0]['url']
  6. # Download and upload to frame
  7. image_data = requests.get(image_url).content
  8. base64_image = base64.b64encode(image_data).decode('utf-8')
  9. frame = KoKonnaFrame("your-api-key")
  10. # Upload directly with base64
  11. # (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:

  1. // Device not found
  2. {
  3. "message": "can not find robot <apikey>"
  4. }
  5. // Rate limit exceeded
  6. {
  7. "message": "Too many requests, please try again later."
  8. }
  9. // Image not found
  10. {
  11. "message": "image not found"
  12. }

Best Practices

1. Image Sizing

Match your image aspect ratio to your device's screen:

  1. from PIL import Image
  2. def resize_for_frame(image_path, frame_width, frame_height):
  3. img = Image.open(image_path)
  4. # Calculate target ratio
  5. target_ratio = frame_width / frame_height
  6. current_ratio = img.width / img.height
  7. # Crop to match
  8. if current_ratio > target_ratio:
  9. # Image is too wide
  10. new_width = int(img.height * target_ratio)
  11. left = (img.width - new_width) // 2
  12. img = img.crop((left, 0, left + new_width, img.height))
  13. else:
  14. # Image is too tall
  15. new_height = int(img.width / target_ratio)
  16. top = (img.height - new_height) // 2
  17. img = img.crop((0, top, img.width, top + new_height))
  18. # Resize to exact dimensions
  19. img = img.resize((frame_width, frame_height), Image.LANCZOS)
  20. return img

2. Rate Limit Management

Implement request queuing:

  1. import time
  2. from collections import deque
  3. class RateLimitedClient:
  4. def __init__(self, api_key, max_requests=20, per_minutes=1):
  5. self.frame = KoKonnaFrame(api_key)
  6. self.requests = deque()
  7. self.max_requests = max_requests
  8. self.per_minutes = per_minutes
  9. def _wait_if_needed(self):
  10. now = time.time()
  11. # Remove old requests
  12. while self.requests and self.requests[0] < now - self.per_minutes * 60:
  13. self.requests.popleft()
  14. # Wait if at limit
  15. if len(self.requests) >= self.max_requests:
  16. sleep_time = self.requests[0] + self.per_minutes * 60 - now
  17. time.sleep(sleep_time)
  18. self.requests.append(now)

3. Battery Optimization

Check device status before uploads:

  1. def smart_upload(frame, image_path):
  2. info = frame.get_device_info()
  3. if not info['online']:
  4. print("Device is offline, skipping upload")
  5. return False
  6. if info['batteryLevel'] < 20 and not info['isCharging']:
  7. print("Battery low, skipping upload")
  8. return False
  9. return 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


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.

Back to top