Files
pigway-frame-flow/docs/integrations/TICKTAR.md
T

111 lines
5.5 KiB
Markdown

# 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.
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
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.
## Webhooks
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.
## 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.