2026-10-02 00:03:48 +08:00
|
|
|
# Optional external integration contract
|
|
|
|
|
|
|
|
|
|
Ticktar integration is optional. Frame Flow has no runtime dependency on Ticktar.
|
|
|
|
|
No external client receives a KoKonna API key, accesses the SQLite database, or
|
|
|
|
|
imports a vendor SDK. Web UI and external clients use the same application services.
|
|
|
|
|
|
|
|
|
|
## Architecture
|
|
|
|
|
|
|
|
|
|
External client → /api/v1 → Application / DisplayService → FrameDeviceDriver → KoKonna.
|
|
|
|
|
Configure the caller with FRAME_FLOW_URL and FRAME_FLOW_TOKEN only. No caller-specific
|
|
|
|
|
branch exists in core. Frame Flow starts and works with no integration configuration.
|
|
|
|
|
|
|
|
|
|
## Authentication and permissions
|
|
|
|
|
|
|
|
|
|
Authorization: Bearer FRAME_FLOW_TOKEN. The bootstrap token is provided through
|
|
|
|
|
.env or a secret file; database stores SHA-256 hash only. The client model supports
|
|
|
|
|
client_id, name, permissions, enabled, created_at, last_used_at. Permissions:
|
|
|
|
|
devices:read, images:read, images:delete, display:write, templates:read, render:write,
|
|
|
|
|
jobs:read, jobs:write, history:read, settings:write, admin.
|
2026-10-10 01:25:32 +08:00
|
|
|
The deployment token seeds an administrator. Administrators can create separate
|
|
|
|
|
scoped clients through Connections or POST /api/v1/clients. The returned token is
|
|
|
|
|
shown once; GET /api/v1/clients never returns tokens. DELETE /api/v1/clients/{id}
|
|
|
|
|
revokes access. For Ticktar, grant devices:read, templates:read, render:write and
|
|
|
|
|
display:write; add images:read or jobs permissions only when needed. Use a trusted server-to-server
|
2026-10-02 00:03:48 +08:00
|
|
|
connection; CORS is opt-in by exact origins, never wildcard by default.
|
|
|
|
|
|
|
|
|
|
## Discovery and capabilities
|
|
|
|
|
|
|
|
|
|
GET /api/v1/devices; GET /api/v1/devices/{id}; GET /api/v1/templates.
|
|
|
|
|
Device provides id/name/status, display geometry, power, current_content, firmware,
|
|
|
|
|
model/model_code, timezone, last_seen_at, capabilities. Model fallback is flagged
|
|
|
|
|
model_verified=false when the cloud omits model fields. Do not branch on driver:
|
|
|
|
|
check capabilities upload/gallery/delete/switch/battery/color/remote_refresh.
|
|
|
|
|
Native slideshow members/editing are unavailable in KoKonna's documented API.
|
|
|
|
|
|
|
|
|
|
## Display
|
|
|
|
|
|
|
|
|
|
POST /api/v1/display, Idempotency-Key: a-unique-client-request-key
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
{
|
|
|
|
|
"device_id": "living-room",
|
|
|
|
|
"content": {
|
|
|
|
|
"type": "template",
|
|
|
|
|
"template": "daily-dashboard",
|
|
|
|
|
"data": {"title": "Good Morning", "events": []},
|
|
|
|
|
"profile": "color"
|
|
|
|
|
},
|
|
|
|
|
"options": {"duration": 1800, "restore_previous": true, "priority": 50},
|
|
|
|
|
"source": {"client": "external-app", "request_id": "caller-trace"}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Content supports image (exactly one image_id/image_name/asset_id/base64), image_url
|
|
|
|
|
(HTTPS/public DNS/exact allowlist), template. html/markdown explicitly return
|
|
|
|
|
UNSUPPORTED_CAPABILITY. For upload-only use device /upload with display_now=false;
|
|
|
|
|
this is safe local staging because KoKonna cloud upload always activates an image.
|
|
|
|
|
|
|
|
|
|
Returns HTTP 202: {operation_id, job_id, status:"accepted"}. job_id is a legacy
|
|
|
|
|
acceptance alias for operation_id, not a scheduler job ID.
|
|
|
|
|
|
|
|
|
|
## Render and operations
|
|
|
|
|
|
|
|
|
|
POST /api/v1/render with template content returns 202 and a local rendered asset
|
|
|
|
|
when completed; no device write. GET /api/v1/operations/{operation_id}:
|
|
|
|
|
QUEUED → RENDERING → UPLOADING → SYNCING → COMPLETED / FAILED / UNKNOWN.
|
|
|
|
|
Result includes image_id or asset_id/url. SYNCING confirms imageId plus synced
|
|
|
|
|
through read-only device status; there is no documented physical-screen telemetry.
|
|
|
|
|
Token must own the operation or be admin. Never interpret HTTP 202 as refreshed.
|
|
|
|
|
|
|
|
|
|
## Idempotency
|
|
|
|
|
|
|
|
|
|
Key is scoped to authenticated client, retained seven days. Same key and same
|
|
|
|
|
normalized action/body returns the same operation, even across restart. A different
|
|
|
|
|
body with the same key returns CONFLICT (409). Do not retry UNKNOWN with a new key.
|
|
|
|
|
Cloud writes have no automatic retries. UNKNOWN blocks further device writes;
|
|
|
|
|
admin /operations/{id}/reconcile reads device/gallery and may acknowledge a manually
|
|
|
|
|
verified outcome without reissuing a write.
|
|
|
|
|
|
|
|
|
|
## Errors and tracing
|
|
|
|
|
|
|
|
|
|
All API errors: {error:{code,message,request_id,details:{}}}. Stable codes include
|
|
|
|
|
INVALID_REQUEST, UNAUTHORIZED, FORBIDDEN, DEVICE_NOT_FOUND, DEVICE_OFFLINE,
|
|
|
|
|
UNSUPPORTED_CAPABILITY, RENDER_FAILED, UPLOAD_FAILED, WRITE_RESULT_UNKNOWN,
|
|
|
|
|
RATE_LIMITED, INTERNAL_ERROR, CONFIG_REQUIRED, WRITE_DISABLED, CONFLICT, NOT_FOUND,
|
|
|
|
|
CLOUD_UNAVAILABLE. Use code, not message text. Validation does not echo inputs.
|
|
|
|
|
X-Request-ID accepts a bounded safe identifier; it is returned on the response.
|
|
|
|
|
The authenticated client is authoritative; source.client is optional metadata.
|
|
|
|
|
History stores client_id/request_id/operation_id/device_id/action/result/timestamp.
|
|
|
|
|
No internal endpoints, headers, stacks, paths or secrets are returned.
|
|
|
|
|
|
2026-10-10 01:25:32 +08:00
|
|
|
## Webhooks
|
2026-10-02 00:03:48 +08:00
|
|
|
|
2026-10-10 01:25:32 +08:00
|
|
|
Administrators register callbacks through POST /api/v1/webhooks. Allowed public
|
|
|
|
|
HTTPS hosts must be configured explicitly. Durable callbacks cover
|
|
|
|
|
operation.completed, operation.failed, display.changed and observed
|
|
|
|
|
device.online/device.offline/device.low_battery transitions. Device observation
|
|
|
|
|
runs at most once per minute; failed cloud queries do not imply offline.
|
|
|
|
|
|
|
|
|
|
X-Frame-Flow-Signature: sha256=<hex> is HMAC-SHA256 over the exact request body.
|
|
|
|
|
Signing secrets are shown once and stored in mode-0600 files. Verify signatures
|
|
|
|
|
and deduplicate event IDs. Delivery retries at most three times; events before
|
|
|
|
|
registration are not replayed. Polling Operations remains available.
|
|
|
|
|
OAuth, tenancy and generated SDKs are future work.
|
2026-10-02 00:03:48 +08:00
|
|
|
|
|
|
|
|
## Compatibility
|
|
|
|
|
|
|
|
|
|
/openapi.json and /docs are the contract. Snapshot tests cover paths, response
|
|
|
|
|
codes, standard device fields, security and operation enums. Static snapshot is
|
|
|
|
|
also supplied in docs/openapi.json. Breaking changes require /api/v2.
|