flutter-update-forge-companion/WEB_API.md

6.4 KiB

UpdateForge API

Base URL: https://<your-server>
All API routes are under /api/v1.
All request and response bodies are JSON.


Authentication

UpdateForge uses Bearer token authentication. Obtain a token via the login endpoint and include it in every subsequent request:

Authorization: Bearer <token>

Tokens are long-lived JWTs signed by the server. Store them securely (e.g. Android EncryptedSharedPreferences). There is no built-in expiry endpoint — simply re-authenticate when you receive a 401.


Endpoints

POST /api/v1/auth

Authenticate with email and password. Does not require an existing token.

Request

{
    "email": "user@example.com",
    "password": "secret"
}

Response 200

{
    "token": "eyJ...",
    "userId": "abc123",
    "email": "user@example.com"
}

Error responses

Status Body Reason
400 {"error": "email and password are required"} Missing fields
401 {"error": "invalid credentials"} Wrong email or password

GET /api/v1/apps

Returns all teams the authenticated user belongs to, each with its apps. A user may belong to multiple teams. Within each app, the response includes the latest current and pending version per build type.

  • current — the highest semver version that has an artifact file attached. Always present (may be null if none exists yet).
  • pending — the highest semver version with no artifact file yet (work in progress). null when none exists.

Teams and apps are ordered oldest-first by creation date.

Response 200

{
    "teams": [
        {
            "id": "team_id",
            "name": "Acme",
            "apps": [
                {
                    "id": "app_id",
                    "title": "My App",
                    "packageName": "com.example.myapp",
                    "icon": "/api/files/apps/app_id/icon.png",
                    "release": {
                        "current": {
                            "id": "ver_id",
                            "version": "1.2.0",
                            "name": "January update",
                            "public": true,
                            "hasFile": true,
                            "created": "2026-01-15T10:30:00Z"
                        },
                        "pending": null
                    },
                    "debug": {
                        "current": {
                            "id": "ver_id_2",
                            "version": "1.3.0",
                            "name": "",
                            "public": false,
                            "hasFile": true,
                            "created": "2026-01-20T08:00:00Z"
                        },
                        "pending": {
                            "id": "ver_id_3",
                            "version": "1.4.0",
                            "name": "Next sprint",
                            "public": false,
                            "hasFile": false,
                            "created": "2026-01-21T09:00:00Z"
                        }
                    },
                    "profile": {
                        "current": null,
                        "pending": null
                    }
                }
            ]
        }
    ]
}

teams is an empty array if the user belongs to no teams.

Version object fields

Field Type Description
id string Version record ID — use this for downloads
version string Semantic version string, e.g. "1.2.0"
name string Optional human-readable label, empty string if not set
public bool Whether this version is intended for all testers
hasFile bool Whether an artifact is available for download
created string ISO 8601 UTC timestamp

Error responses

Status Body Reason
401 {"error": "unauthorized"} Missing or invalid token

GET /api/v1/versions/{id}/download

Download the artifact file for a version. {id} is the version's id field from the apps response.

The response is the raw file with Content-Type: application/octet-stream and a Content-Disposition: attachment header carrying the original filename. Supports HTTP range requests, so partial downloads and resume work out of the box.

Error responses

Status Body Reason
401 {"error": "unauthorized"} Missing or invalid token
403 {"error": "forbidden"} User is not a member of the version's team
404 {"error": "version not found"} ID does not exist
404 {"error": "no file attached"} Version exists but hasFile is false

Build types

Every version belongs to exactly one build type:

Type Intended use
release Production-ready builds for general testers
debug Debug builds with logging/tooling enabled
profile Performance-profiling builds

Icons

The icon field in the app object is a root-relative URL path. Prepend the server base URL to fetch it:

GET https://<your-server>/api/files/apps/<app_id>/<filename>

Icon files are served publicly and do not require authentication.


Typical client flow

1.  POST /api/v1/auth              → store token
2.  GET  /api/v1/apps              → display teams and their apps; cache version IDs
3.  For each app, compare installed version string with current.version
4.  If update available and current.hasFile == true:
      GET /api/v1/versions/{id}/download   → save & install APK

Error format

All error responses share the same shape:

{ "error": "<human-readable message>" }