From 340f3399c9defe574395d5785d0c1bd40a19a22a Mon Sep 17 00:00:00 2001 From: Hossain Khan Date: Sat, 31 Jan 2026 08:39:24 -0500 Subject: [PATCH] Refactor: Separate device-level and user-level API services - Create TrmnlUserApiService for user-level (Bearer auth) endpoints - Move getDevice() and updateDevice() to TrmnlUserApiService - Update TrmnlApiService to focus on device-level (Access-Token) endpoints - Remove device management endpoints from TrmnlApiService - Add OpenAPI documentation references (https://trmnl.com/api-docs/index.html) - Clean up imports and improve documentation This separation clarifies authentication requirements: - TrmnlApiService: Device API key via Access-Token header - TrmnlUserApiService: Account API key via Bearer Authorization header --- .../trmnl/android/network/TrmnlApiService.kt | 58 +- .../android/network/TrmnlUserApiService.kt | 78 ++ .../trmnl-api/trmnl-openapi.yaml | 1137 +++++++++++++++++ 3 files changed, 1222 insertions(+), 51 deletions(-) create mode 100644 app/src/main/java/ink/trmnl/android/network/TrmnlUserApiService.kt create mode 100644 project-resources/trmnl-api/trmnl-openapi.yaml diff --git a/app/src/main/java/ink/trmnl/android/network/TrmnlApiService.kt b/app/src/main/java/ink/trmnl/android/network/TrmnlApiService.kt index 15ed805..a5f36c7 100644 --- a/app/src/main/java/ink/trmnl/android/network/TrmnlApiService.kt +++ b/app/src/main/java/ink/trmnl/android/network/TrmnlApiService.kt @@ -3,28 +3,29 @@ package ink.trmnl.android.network import com.slack.eithernet.ApiResult import ink.trmnl.android.data.TrmnlDisplayRepository import ink.trmnl.android.network.model.TrmnlCurrentImageResponse -import ink.trmnl.android.network.model.TrmnlDeviceResponse -import ink.trmnl.android.network.model.TrmnlDeviceUpdateRequest import ink.trmnl.android.network.model.TrmnlDisplayResponse import ink.trmnl.android.network.model.TrmnlModelsResponse import ink.trmnl.android.network.model.TrmnlSetupResponse -import retrofit2.http.Body import retrofit2.http.GET import retrofit2.http.Header import retrofit2.http.Headers -import retrofit2.http.PATCH import retrofit2.http.Url /** - * API service interface for TRMNL or BYOS servers. + * API service interface for TRMNL device-level API endpoints. * - * This interface defines the endpoints for the TRMNL API. + * This interface defines endpoints that require device-level authentication via + * Access-Token header (Device API key), as opposed to user-level Bearer token authentication. + * + * For user-level (account) API endpoints, see [TrmnlUserApiService]. * * See: * - https://docs.usetrmnl.com/go * - https://docs.usetrmnl.com/go/private-api/introduction + * - https://trmnl.com/api-docs/index.html (OpenAPI documentation) * * @see TrmnlDisplayRepository + * @see TrmnlUserApiService */ interface TrmnlApiService { companion object { @@ -64,16 +65,6 @@ interface TrmnlApiService { * @see getDeviceModels */ internal const val MODELS_API_PATH = "api/models" - - /** - * Path template for the TRMNL API endpoint to get or update a specific device. - * - * Replace `{id}` with the actual device ID. - * - * @see getDevice - * @see updateDevice - */ - internal const val DEVICE_API_PATH = "api/devices/{id}" } /** @@ -141,39 +132,4 @@ interface TrmnlApiService { suspend fun getDeviceModels( @Url fullApiUrl: String, ): ApiResult - - /** - * Retrieve device data for a specific device using [DEVICE_API_PATH]. - * - * This endpoint provides information about a single device including its configuration, - * battery status, WiFi strength, and sleep mode settings. - * - * @param fullApiUrl The complete API URL to call (e.g., "https://usetrmnl.com/api/devices/1") - * @param accessToken The bearer authentication token - * @return An [ApiResult] containing [TrmnlDeviceResponse] with the device data - */ - @GET - suspend fun getDevice( - @Url fullApiUrl: String, - @Header("Authorization") accessToken: String, - ): ApiResult - - /** - * Update device settings for a specific device using [DEVICE_API_PATH]. - * - * This endpoint allows updating device configuration such as sleep mode settings - * and battery charge percentage. - * - * @param fullApiUrl The complete API URL to call (e.g., "https://usetrmnl.com/api/devices/1") - * @param accessToken The bearer authentication token - * @param updateRequest The device update request containing the fields to update - * @return An [ApiResult] containing [TrmnlDeviceResponse] with the updated device data - */ - @Headers("Content-Type: application/json") - @PATCH - suspend fun updateDevice( - @Url fullApiUrl: String, - @Header("Authorization") accessToken: String, - @Body updateRequest: TrmnlDeviceUpdateRequest, - ): ApiResult } diff --git a/app/src/main/java/ink/trmnl/android/network/TrmnlUserApiService.kt b/app/src/main/java/ink/trmnl/android/network/TrmnlUserApiService.kt new file mode 100644 index 0000000..34afc94 --- /dev/null +++ b/app/src/main/java/ink/trmnl/android/network/TrmnlUserApiService.kt @@ -0,0 +1,78 @@ +package ink.trmnl.android.network + +import com.slack.eithernet.ApiResult +import ink.trmnl.android.network.model.TrmnlDeviceResponse +import ink.trmnl.android.network.model.TrmnlDeviceUpdateRequest +import retrofit2.http.Body +import retrofit2.http.GET +import retrofit2.http.Header +import retrofit2.http.Headers +import retrofit2.http.PATCH +import retrofit2.http.Url + +/** + * API service interface for TRMNL user-level (account) API endpoints. + * + * This interface defines endpoints that require user-level authentication via Bearer token + * (Account API key), as opposed to device-level authentication. + * + * See: + * - https://docs.usetrmnl.com/go + * - https://trmnl.com/api-docs/index.html (OpenAPI documentation) + */ +interface TrmnlUserApiService { + companion object { + /** + * Path template for the TRMNL API endpoint to get or update a specific device. + * + * Replace `{id}` with the actual device ID. + * + * **Authentication:** Requires Bearer token (user-level Account API key) + * + * See: https://trmnl.com/api-docs/index.html#/Devices + * + * @see getDevice + * @see updateDevice + */ + internal const val DEVICE_API_PATH = "api/devices/{id}" + } + + /** + * Retrieve device data for a specific device using [DEVICE_API_PATH]. + * + * This endpoint provides information about a single device including its configuration, + * battery status, WiFi strength, and sleep mode settings. + * + * **Authentication:** Requires Bearer token with user-level Account API key + * + * @param fullApiUrl The complete API URL to call (e.g., "https://usetrmnl.com/api/devices/1") + * @param accessToken The bearer authentication token (format: "Bearer your_api_key") + * @return An [ApiResult] containing [TrmnlDeviceResponse] with the device data + */ + @GET + suspend fun getDevice( + @Url fullApiUrl: String, + @Header("Authorization") accessToken: String, + ): ApiResult + + /** + * Update device settings for a specific device using [DEVICE_API_PATH]. + * + * This endpoint allows updating device configuration such as sleep mode settings + * and battery charge percentage. + * + * **Authentication:** Requires Bearer token with user-level Account API key + * + * @param fullApiUrl The complete API URL to call (e.g., "https://usetrmnl.com/api/devices/1") + * @param accessToken The bearer authentication token (format: "Bearer your_api_key") + * @param updateRequest The device update request containing the fields to update + * @return An [ApiResult] containing [TrmnlDeviceResponse] with the updated device data + */ + @Headers("Content-Type: application/json") + @PATCH + suspend fun updateDevice( + @Url fullApiUrl: String, + @Header("Authorization") accessToken: String, + @Body updateRequest: TrmnlDeviceUpdateRequest, + ): ApiResult +} diff --git a/project-resources/trmnl-api/trmnl-openapi.yaml b/project-resources/trmnl-api/trmnl-openapi.yaml new file mode 100644 index 0000000..df7436d --- /dev/null +++ b/project-resources/trmnl-api/trmnl-openapi.yaml @@ -0,0 +1,1137 @@ +--- +openapi: 3.0.1 +info: + title: TRMNL API + version: '1' +paths: + "/api/display": + get: + summary: Fetch the next screen + tags: + - Device API + parameters: + - name: Access-Token + in: header + required: true + description: Device API Key (eg. abc-123) + schema: + type: string + - name: Battery-Voltage + in: header + required: false + description: Device battery voltage (eg. 3.7) + schema: + type: number + - name: FW-Version + in: header + required: false + description: Device firmware version (eg. 0.0.1) + schema: + type: string + - name: RSSI + in: header + required: false + description: Device RSSI (eg. -69) + schema: + type: number + - name: Height + in: header + required: false + description: Device screen height (eg. 480) + schema: + type: string + - name: Width + in: header + required: false + description: Device screen width (eg. 800) + schema: + type: string + - name: Special-Function + in: header + required: false + description: Device special function (eg. true) + schema: + type: boolean + - name: BASE64 + in: header + required: false + description: Encode image function (eg. true) + schema: + type: boolean + responses: + '200': + description: Success + content: + application/json: + schema: + type: object + properties: + status: + type: integer + example: 200 + image_url: + type: string + nullable: true + example: https://trmnl.com/images/setup/setup-logo.bmp + filename: + type: string + nullable: true + example: setup-logo.bmp + refresh_rate: + type: integer + example: 300 + reset_firmware: + type: boolean + example: false + update_firmware: + type: boolean + example: false + firmware_url: + type: string + nullable: true + example: https://trmnl.com/firmware/1.0.0.bin + special_function: + type: string + nullable: false + example: identify + action: + type: string + nullable: true + example: identify + "/api/display/current": + get: + summary: Fetch the current screen + tags: + - Device API + parameters: + - name: Access-Token + in: header + required: true + description: Device API Key (eg. abc-123) + schema: + type: string + responses: + '200': + description: Success + content: + application/json: + schema: + type: object + properties: + status: + type: integer + example: 200 + refresh_rate: + type: integer + example: 300 + image_url: + type: string + nullable: true + example: https://trmnl.com/images/setup/setup-logo.bmp + filename: + type: string + nullable: true + example: setup-logo.bmp + rendered_at: + type: string + nullable: true + example: '2023-01-01T00:00:00Z' + "/api/log": + post: + summary: Log with logs[] (array) + tags: + - Device API + parameters: + - name: Access-Token + in: header + required: true + description: Device API Key (eg. abc-123) + schema: + type: string + responses: + '204': + description: Logs created when ignore_log_messages is not set + requestBody: + content: + application/json: + schema: + type: object + properties: + logs: [] + required: + - logs + additionalProperties: false + required: true + description: 'An array of log entries. Each entry can be any JSON type: string, + object, etc.' + "/api/setup": + get: + summary: Set up device + tags: + - Device API + parameters: + - name: ID + in: header + required: true + description: Device MAC Address (eg. 41:B4:10:39:A1:24) + schema: + type: string + - name: Model + in: header + required: true + description: DEVICE_MODEL from firmware definitions + schema: + type: string + description: | + Please note that the returned `status` JSON value may NOT always equal the HTTP status code. Notably, if a device MAC address is not found, + then the HTTP status code will be 200 but the `status` code in the response will be 404. + responses: + '200': + description: Success + content: + application/json: + schema: + type: object + properties: + status: + type: integer + example: 200 + api_key: + type: string + nullable: true + example: abc-123 + friendly_id: + type: string + nullable: true + example: ABC-123 + image_url: + type: string + nullable: true + example: https://trmnl.com/images/setup/setup-logo.bmp + message: + type: string + example: Register at trmnl.com/signup with Device ID 'ABC-123' + "/api/categories": + get: + summary: List all plugin categories + tags: + - Categories + description: Returns a list of approved plugin categories. + responses: + '200': + description: Success + content: + application/json: + schema: + type: object + properties: + status: + type: integer + example: 200 + data: + type: array + items: + type: string + example: + - life + - marketing + - ecommerce + "/api/ips": + get: + summary: List all TRMNL server IP addresses + tags: + - Server IPs + description: | + Returns a list of public IP addresses for all TRMNL core servers. + + Plugin poll requests will only originate from these IPs. + responses: + '200': + description: Success + content: + application/json: + schema: + type: object + properties: + data: + type: object + properties: + ipv4: + type: array + items: + type: string + ipv6: + type: array + items: + type: string + "/api/markup": + post: + summary: Render Liquid template + tags: + - Markup + parameters: [] + responses: + '200': + description: Success + content: + application/json: + schema: + type: object + properties: + data: + oneOf: + - type: string + - type: array + items: + type: string + requestBody: + content: + application/json: + schema: + type: object + properties: + markup: + oneOf: + - type: string + example: Hello, {{ name }}! + - type: array + items: + type: string + example: + - Hello, {{ name }}! + - Goodbye, {{ name }}! + variables: + type: object + example: + name: World + required: + - markup + - variables + additionalProperties: false + required: true + description: The Liquid markup(s) to render and an optional set of variables + to use in the rendering process. + "/api/models": + get: + summary: List all device models + tags: + - Models + responses: + '200': + description: Success + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + "$ref": "#/components/schemas/Model" + "/api/palettes": + get: + summary: List all palettes + tags: + - Palettes + responses: + '200': + description: Success + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + "$ref": "#/components/schemas/Palette" + "/api/devices": + get: + summary: List my devices + tags: + - Devices + security: + - bearer_auth: [] + responses: + '401': + description: Unauthorized + content: + application/json: + schema: + "$ref": "#/components/schemas/Error" + '200': + description: Success + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + "$ref": "#/components/schemas/Device" + "/api/devices/{id}": + parameters: + - name: id + in: path + description: Device ID + required: true + schema: + type: integer + get: + summary: Get the data of a device + tags: + - Devices + security: + - bearer_auth: [] + responses: + '401': + description: Unauthorized + content: + application/json: + schema: + "$ref": "#/components/schemas/Error" + '200': + description: Success + content: + application/json: + schema: + type: object + properties: + data: + "$ref": "#/components/schemas/Device" + '404': + description: Not found + content: + application/json: + schema: + "$ref": "#/components/schemas/Error" + patch: + summary: Update a device + tags: + - Devices + parameters: [] + security: + - bearer_auth: [] + responses: + '401': + description: Unauthorized + content: + application/json: + schema: + "$ref": "#/components/schemas/Error" + '200': + description: Updated + requestBody: + content: + application/json: + schema: + type: object + properties: + sleep_mode_enabled: + type: boolean + example: true + sleep_start_time: + type: integer + example: 1320 + sleep_end_time: + type: integer + example: 480 + percent_charged: + type: number + example: 69.0 + "/api/me": + get: + summary: Get my user data + tags: + - Users + security: + - bearer_auth: [] + responses: + '401': + description: Unauthorized + content: + application/json: + schema: + "$ref": "#/components/schemas/Error" + '200': + description: Success + content: + application/json: + schema: + type: object + properties: + data: + "$ref": "#/components/schemas/User" + "/api/playlists/items": + get: + summary: List my playlist items + tags: + - Playlists + security: + - bearer_auth: [] + responses: + '401': + description: Unauthorized + content: + application/json: + schema: + "$ref": "#/components/schemas/Error" + '200': + description: Success + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + "$ref": "#/components/schemas/PlaylistItem" + "/api/playlists/items/{id}": + patch: + summary: Update a playlist item + tags: + - Playlists + parameters: + - name: id + in: path + description: ID of the playlist item + required: true + schema: + type: integer + security: + - bearer_auth: [] + responses: + '401': + description: Unauthorized + content: + application/json: + schema: + "$ref": "#/components/schemas/Error" + '200': + description: Updated + requestBody: + content: + application/json: + schema: + type: object + properties: + visible: + type: boolean + required: + - visible + "/api/plugin_settings/{id}/archive": + parameters: + - name: id + in: path + description: Plugin setting ID + required: true + schema: + type: integer + get: + summary: Download a plugin setting archive + tags: + - Plugin Settings + description: | + This endpoint is available for unauthenticated requests. + + When unauthenticated, any published recipe may be archived. + + When authenticated, the requesting user's private plugins are also archivable. + security: + - bearer_auth: [] + responses: + '200': + description: Success + '404': + description: Not Found + content: + application/json: + schema: + "$ref": "#/components/schemas/Error" + '422': + description: Unprocessable Entity + content: + application/json: + schema: + "$ref": "#/components/schemas/Error" + post: + summary: Upload a plugin setting archive + tags: + - Plugin Settings + security: + - bearer_auth: [] + parameters: [] + responses: + '401': + description: Unauthorized + content: + application/json: + schema: + "$ref": "#/components/schemas/Error" + '422': + description: Unprocessable Entity + content: + application/json: + schema: + "$ref": "#/components/schemas/Error" + '200': + description: Success + content: + application/json: + schema: + type: object + properties: + data: + "$ref": "#/components/schemas/PluginSettingArchive" + requestBody: + content: + multipart/form-data: + schema: + type: file + required: true + description: Plugin setting archive file + "/api/plugin_settings/{id}/data": + parameters: + - name: id + in: path + description: Plugin setting ID or UUID + required: true + schema: + type: string + get: + summary: Get the data of a plugin setting + tags: + - Plugin Settings + security: + - bearer_auth: [] + responses: + '401': + description: Unauthorized + content: + application/json: + schema: + "$ref": "#/components/schemas/Error" + '200': + description: Success + content: + application/json: + schema: + type: object + properties: + data: + type: object + '404': + description: Not found + content: + application/json: + schema: + "$ref": "#/components/schemas/Error" + '422': + description: Data is not available + content: + application/json: + schema: + "$ref": "#/components/schemas/Error" + post: + summary: Update data for a plugin setting + tags: + - Plugin Settings + security: + - bearer_auth: [] + parameters: [] + responses: + '401': + description: Unauthorized + content: + application/json: + schema: + "$ref": "#/components/schemas/Error" + '200': + description: Success with UUID (no auth required) + content: + application/json: + schema: + type: object + properties: + data: + type: object + '404': + description: Not found + content: + application/json: + schema: + "$ref": "#/components/schemas/Error" + '422': + description: Data cannot be modified + content: + application/json: + schema: + "$ref": "#/components/schemas/Error" + requestBody: + content: + application/json: + schema: + type: object + properties: + merge_variables: {} + required: + - merge_variables + additionalProperties: false + required: true + description: The value of `merge_variables` must be a JSON object + "/api/plugin_settings/{id}/image": + parameters: + - name: id + in: path + description: Plugin setting UUID + required: true + schema: + type: string + post: + summary: Upload an image for a webhook_image plugin + tags: + - Plugin Settings + responses: + '200': + description: Success with home_assistant_screenshot plugin + content: + application/json: + schema: + type: object + properties: + data: + type: object + properties: + message: + type: string + '404': + description: Not found + '422': + description: Image too large + '429': + description: Rate limited + "/api/plugin_settings": + get: + summary: List my plugin settings + tags: + - Plugin Settings + security: + - bearer_auth: [] + parameters: + - name: plugin_id + in: query + required: false + description: ID of a plugin or "calendars" to filter calendar plugins + schema: + type: string + responses: + '401': + description: Unauthorized + content: + application/json: + schema: + "$ref": "#/components/schemas/Error" + '200': + description: Returns all calendar plugin settings except Google Calendar + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + "$ref": "#/components/schemas/PluginSetting" + post: + summary: Create a new plugin setting + tags: + - Plugin Settings + security: + - bearer_auth: [] + parameters: [] + responses: + '401': + description: Unauthorized + content: + application/json: + schema: + "$ref": "#/components/schemas/Error" + '200': + description: Success + content: + application/json: + schema: + type: object + properties: + data: + "$ref": "#/components/schemas/PluginSetting" + '422': + description: Unprocessable Entity + content: + application/json: + schema: + "$ref": "#/components/schemas/Error" + requestBody: + content: + application/json: + schema: + "$ref": "#/components/schemas/PluginSettingParams" + required: true + "/api/plugin_settings/{id}": + delete: + summary: Delete a plugin setting + tags: + - Plugin Settings + security: + - bearer_auth: [] + parameters: + - name: id + in: path + required: true + description: ID of the plugin setting to delete + schema: + type: integer + responses: + '401': + description: Unauthorized + content: + application/json: + schema: + "$ref": "#/components/schemas/Error" + '204': + description: Deleted + '404': + description: Not found + content: + application/json: + schema: + "$ref": "#/components/schemas/Error" +servers: +- url: https://{defaultHost} + variables: + defaultHost: + default: trmnl.com +components: + securitySchemes: + bearer_auth: + type: http + scheme: bearer + bearerFormat: Account API key + schemas: + Error: + type: object + additionalProperties: false + properties: + error: + type: string + example: An error occurred + Device: + type: object + additionalProperties: false + properties: + id: + type: integer + example: 123 + name: + type: string + example: My TRMNL + friendly_id: + type: string + example: ABC-123 + mac_address: + type: string + example: 12:34:56:78:9A:BC + battery_voltage: + type: number + nullable: true + example: 3.7 + rssi: + type: integer + nullable: true + example: -70 + sleep_mode_enabled: + type: boolean + nullable: false + example: false + sleep_start_time: + type: integer + example: 1320 + sleep_end_time: + type: integer + example: 480 + percent_charged: + type: number + example: 85.0 + minimum: 0 + maximum: 100 + wifi_strength: + type: number + example: 75.0 + minimum: 0 + maximum: 100 + Model: + type: object + additionalProperties: false + properties: + name: + type: string + example: trmnl_original + description: Unique identifier + label: + type: string + example: TRMNL + description: Human-readable name + description: + type: string + example: Original TRMNL model + description: Description + width: + type: integer + example: 800 + description: Screen width in pixels + height: + type: integer + example: 480 + description: Screen height in pixels + colors: + type: integer + example: 2 + description: Number of colors supported + bit_depth: + type: integer + example: 1 + description: Color bit depth + scale_factor: + type: number + example: 1.0 + description: Display scale factor + rotation: + type: integer + example: 90 + description: Screen rotation in degrees + mime_type: + type: string + example: image/png + description: Image MIME type + offset_x: + type: integer + example: 10 + description: X offset for image rendering + offset_y: + type: integer + example: 20 + description: Y offset for image rendering + kind: + type: string + example: trmnl + description: Device kind (e.g., trmnl, kindle, byod) + enum: + - trmnl + - kindle + - byod + - tidbyt + palette_ids: + type: array + items: + type: string + example: + - bw + - gray-4 + - gray-16 + description: Supported color palette IDs + image_size_limit: + type: integer + example: 92160 + description: Maximum image file size in bytes for webhook uploads + image_upload_supported: + type: boolean + example: true + description: Whether webhook image uploads are supported for this device + type + css: + type: object + nullable: true + description: CSS classes and variables for web rendering + properties: + classes: + type: object + properties: + device: + type: string + example: screen--og_plus + size: + type: string + example: screen--md + variables: + type: array + items: + type: array + items: + type: string + example: + - "--screen-w" + - 800px + Palette: + type: object + additionalProperties: false + properties: + id: + type: string + example: gray-16 + description: Unique identifier + required: true + name: + type: string + example: 16-Gray + description: Human-readable name + required: true + grays: + type: integer + nullable: true + example: 16 + description: Number of grayscale levels (null for color palettes) + colors: + type: array + nullable: true + items: + type: string + example: + - "#FF0000" + - "#00FF00" + - "#0000FF" + - "#FFFF00" + - "#000000" + - "#FFFFFF" + description: Array of hex color codes (null for grayscale palettes) + framework_class: + type: string + example: screen--4bit + description: Framework CSS class for this palette + PlaylistItem: + type: object + additionalProperties: false + properties: + created_at: + type: string + format: date_time + example: '2023-10-01T12:00:00Z' + device_id: + type: integer + example: 1 + id: + type: integer + example: 1 + mashup_id: + type: integer + example: 1 + nullable: true + mirror: + type: boolean + example: true + playlist_group_id: + type: integer + example: 1 + plugin_setting: + "$ref": "#/components/schemas/PluginSetting" + plugin_setting_id: + type: integer + example: 1 + rendered_at: + type: string + format: date_time + example: '2023-10-01T12:00:00Z' + row_order: + type: integer + example: 1 + updated_at: + type: string + format: date_time + example: '2023-10-01T12:00:00Z' + visible: + type: boolean + example: true + PlaylistItemParams: + type: object + additionalProperties: false + properties: + visible: + type: boolean + example: true + PluginSetting: + type: object + additionalProperties: false + properties: + id: + type: integer + example: 1 + name: + type: string + example: My Plugin Setting + plugin_id: + type: integer + example: 1 + PluginSettingArchive: + type: object + properties: + settings_yaml: + type: string + description: YAML settings file + PluginSettingParams: + type: object + additionalProperties: false + properties: + name: + type: string + example: My Plugin Setting + required: true + plugin_id: + type: integer + example: 1 + required: true + PluginSettingDataParams: + type: object + additionalProperties: false + properties: + merge_variables: + type: content + required: true + example: true + error: + type: string + required: false + User: + type: object + additionalProperties: false + properties: + id: + type: integer + example: 42 + name: + type: string + example: Jim Bob + email: + type: string + example: jimbob@gmail.net + first_name: + type: string + example: Jim + last_name: + type: string + example: Bob + locale: + type: string + example: en + time_zone: + type: string + example: Eastern Time (US & Canada) + time_zone_iana: + type: string + example: America/New_York + utc_offset: + type: integer + example: -14400 + api_key: + type: string + example: user_xxxxxx