Skip to content
Docs for Flare v3.1.0Latest stable · 0de5c7d2Build details ↗Versions & changes
View docs

Endpoint inventory ​

Flare's dashboard also talks to HTTP routes. Their existence does not make all of them part of the named-token API. This inventory distinguishes the supported automation surface from session-based account/admin actions and public content routes.

Use the OpenAPI document for custom clients using flr_… tokens. It describes the 13 supported method/path combinations across eight paths. The rest of this page is a map for operators and contributors, not a promise of a general administrator REST API.

Paths use {id} for a dynamic segment. {path} and {nextauth} are catch-all path segments. Methods listed here are the implemented handlers; do not assume another method is supported because the path exists.

Answers and errors ​

JSON answers, errors included, carry Cache-Control: private, no-store unless the route sets its own value: account security sends no-store, and file content follows the file's sharing state. Earlier builds sent no Cache-Control with many of them, private ones included: GET /api/urls, /api/upload-profiles, /api/users, /api/users/{id}/files, /api/users/{id}/urls, /api/users/{id}/email, /api/settings/email and /api/files/{id}/expiry among them.

An error answer is { "error": "…" }, with success: false on routes whose successful answers use { "success": true, "data": … }, except sign-in and permission refusals. The multipart upload, POST /api/files, is also an exception: a successful upload has that envelope, but its errors don't include success. A request whose body, query or form a route can't read answers 400 with that route's message. Anything else that goes wrong answers 500 with the route's general message, and the server logs the cause. That includes saved settings or upload profile options Flare can't read. Earlier builds answered some of those failures with 400 and logged nothing: an upload whose saved profile options or settings weren't valid answered Invalid upload options., and unexpected failures on account security, account email, email settings, the settings form, the logo upload and personal appearance answered 400.

Named-token API ​

All of these routes also use Flare's shared account authentication helper. A named token must have the specific scope and its owner must currently have the matching role permission. Results are limited to its owner's account. See the scope-to-permission table.

PathMethodScopePurpose
/api/filesGETfiles:readPaginated file metadata, selected-ID refreshes, search, filters, and image neighbors.
/api/filesPOSTfiles:uploadOne multipart file upload.
/api/files/timelineGETfiles:readAccount-wide bucket counts; non-date sorts use null from/to boundaries.
/api/files/typesGETfiles:readMIME types present in the account.
/api/files/chunksPOSTfiles:uploadInitialize a chunk upload.
/api/files/chunksGETfiles:uploadObtain a part URL using uploadId and partNumber query parameters.
/api/files/chunksPUTfiles:uploadComplete an upload, returning a data wrapper.
/api/files/chunks/{uploadId}/part/{partNumber}GETfiles:uploadObtain a part upload URL.
/api/files/chunks/{uploadId}/part/{partNumber}PUTfiles:uploadUpload raw part bytes through Flare.
/api/files/chunks/{uploadId}/completePOSTfiles:uploadComplete an upload, returning links without a wrapper.
/api/urlsGETurls:readList the account's short links.
/api/urlsPOSTurls:writeCreate a short link.
/api/urls/{id}DELETEurls:writeDelete an owned short link.

These routes also answer OPTIONS preflight requests. When the instance sets FLARE_CORS_ORIGINS, an allowed origin gets CORS headers for the methods above, and only those; without the setting, preflights get a plain 204 that browsers treat as a refusal.

See files, short links, and authentication for request/response details. When the dashboard calls the write routes above with a browser session, they follow the browser-session write rule; token requests don't. Chunk part and completion routes reject 409 when the actual storage target changed or older session metadata lacks provenance; initialize a fresh upload. This does not add scopes or alter successful response shapes.

File content and access checks ​

These routes check the file's visibility, password, and an optional browser session. They do not use named bearer tokens to grant file access. Public unprotected files can be fetched anonymously. Private files require an owner session with files.read, or a session with content.read and return 404 to ineligible viewers. A password-protected public file requires its password unless the browser session belongs to its owner with files.read, or a person with content.read.

PathMethodsPurpose
/api/files/{path}GETRaw stored content by file URL path; download=true requests attachment handling and is audited as file.download.
/api/files/{id}/downloadGET, POSTDownload content. GET accepts a password query value and one Range; POST accepts password JSON and ignores Range. S3 storage can redirect after access validation to a signed URL, which makes S3 send the Content-Disposition Flare would.
/api/files/{id}/thumbnailGETServe an image for thumbnail display: a smaller WebP copy with w, otherwise the original. Access is checked before the type, so only someone who may read the file gets 400 for a non-image.
/api/files/{id}/ocrGETFetch image OCR text after access validation; unsaved text waits for the OCR queue (limits). A non-image answers 400 only after access validation.

These routes answer OPTIONS preflights, as do /{userUrlId}/{filename}/raw, /{userUrlId}/{filename}/direct, and /{userUrlId}/{filename}/media. With FLARE_CORS_ORIGINS set, allowed sites can read their GET and HEAD answers as an anonymous visitor would. A browser may still send the session cookie with a credentials: 'include' request, but without Access-Control-Allow-Credentials it won't let the page read that answer.

Raw/thumbnail/OCR GET requests accept a password query parameter when applicable. Prefer the normal share-page password flow for people using a browser; URLs containing passwords can be retained in history or logs. After 10 different incorrect passwords for a file from one client address, or 100 from all addresses, within 15 minutes, these routes, downloads, and shared-archive reads answer 429 with Retry-After in seconds until the window ends, even for the correct password, unless that address unlocked the file in the last 10 minutes. Repeating an identical wrong password does not count again. See incorrect password attempts.

Archive share pages use separate read operations under the same file-access rules. They reject Authorization headers, require same-origin requests, and accept file passwords only in a request body. A listing that verifies a visitor password sets a one-hour unlock cookie scoped to that file's shared archive routes, which the GET entry route accepts instead of the password. Body reading is limited to 16 KiB, five seconds, and 32 pending reads per process; schema validation and file authorization finish before any archive data is read. They do not grant extraction or library access. See archive API contracts for schemas and limits.

Inline content responses from /{userUrlId}/{filename}/raw, /api/files/{path}, and /api/files/{id}/thumbnail send Content-Security-Policy: sandbox and X-Content-Type-Options: nosniff with the stored Content-Type. A browser that opens one of these URLs directly renders the document in a sandbox with an opaque origin, so stored HTML, SVG, and XML cannot run script or make credentialed requests as Flare. <img> and <video> elements still display the bytes. Downloads use attachment disposition. Builds before this change sent thumbnails without the sandbox policy; see the upgrade note.

PathMethodsPurpose
/api/files/{id}/archive/sharePOSTRead an accessible archive listing; JSON {password?, progress?, after?}. Unprotected public archives allow anonymous access.
/api/files/{id}/archive/share/entryGETStream a member by entry position or path, with Range and inline media support; access from the session, public visibility, or an unlock cookie.
/api/files/{id}/archive/share/entryPOSTDownload a member; JSON or URL-encoded {path,password?} body, with file access checked again.

The public-facing route /{userUrlId}/{filename}/raw also enforces file access. /{userUrlId}/{filename}/direct is a video-only lookup that returns JSON containing a signed storage URL or raw-route fallback after checking access; it does not stream the file itself. An issued S3 URL can remain valid until its own expiry after Flare access settings change. /{userUrlId}/{filename}/media checks access the same way and answers 302: to a newly signed storage URL for video and audio on S3, and to the file's /raw address otherwise, keeping a password you sent. It is the address to keep in a player or a preview, because each request signs a new URL. /{userUrlId}/{filename} is the rendered share page. A request for it from a link-preview fetcher is answered by /{userUrlId}/{filename}/embed instead: a 307 to /raw or a small HTML page of preview tags, as embeds describes. GET /u/{shortCode} publicly redirects a short link and increments its count.

Each successful raw-content GET adds one file view, including 206 range responses; denied requests, missing files, failures opening storage, and HEAD probes do not. This route uses public-file/password or browser-session access, not named-token authorization. The file-list views field includes these increments. See raw request examples and the view-count limitations.

When the stored object itself is gone (ENOENT on local storage, NoSuchKey or a 404 HEAD on S3), the raw, content, download, and thumbnail routes answer 404 with an empty body; earlier builds answered 500 from raw, download, and thumbnail requests. On S3, a download redirects to its signed URL without reading the object, so S3 answers a missing key itself. Another storage failure or a failed view-counter write returns 500 and closes the acquired storage stream; /api/files/{path} answers 404 for every failure. Resolve the storage or database failure before retrying.

OCR request limits ​

GET /api/files/{id}/ocr returns saved text immediately as 200 with { success, text, confidence }. Text that isn't saved yet is read through the same queue as automatic OCR, one image at a time per Flare process, and requests for an image that is already queued wait for that work. Responses other than saved text:

StatusBodyMeaning
200{ success: false, error, retryAfter? }Reading failed. The error never includes storage or recognition details. Flare reads the image again only after 5 minutes; until then retryAfter gives seconds.
202{ success: false, status: "processing", error, retryAfter }The request waited 60 seconds. Reading continues, and a later request returns the saved text.
429{ success: false, error, retryAfter }The requester started 20 readings in the last 10 minutes: per account when signed in, otherwise per client address.
503{ success: false, error, retryAfter }Ten new images are already waiting to be read, or 30 requests are already waiting for results, counting requests that joined an image being read.

202, 429, and 503 also send Retry-After in seconds. A requester is charged only when its request starts reading an image. Joining work that is already queued, several simultaneous requests for one image (charged once), and reading saved text don't count toward the limit, and a request refused with 503 is never charged. The 30-request cap bounds the connections OCR can hold open for up to 60 seconds each, even when many visitors wait for one popular image. Limits and queue state are per process and reset when Flare restarts.

Dashboard account routes requiring a browser session ​

These routes explicitly read an interactive session. Neither a named API token nor a legacy account upload token by itself supplies that session. Ownership, current role permission, and feature-policy checks still apply. Profile edits use profile.update; full exports require profile.export, files.read, and links.read together (progress alone uses profile.export); upload profiles uploadProfiles.manage; token and uploader-configuration management tokens.manage; webhooks webhooks.manage; personal appearance appearance.personal. File changes separately check files.share, files.update, or files.delete.

PathMethodsPurpose
/api/integrationsGET, POSTList/manage named tokens, webhooks, and deliveries. POST uses action commands and validates same-origin JSON requests.
/api/upload-profilesGET, POSTList profiles with updatedAt and effective-settings effectiveRevision; create or import one (JSON up to 64 KiB, else 413).
/api/upload-profiles/{id}PUT, DELETEUpdate an owned profile using its revision or delete it.
/api/upload-profiles/{id}/exportGETExport a portable profile recipe: the flare-upload-profile version 1 JSON that POST imports.
/api/upload-profiles/defaultPUTSelect or clear the account's default profile.
/api/customizationGETRead published appearance; sessions with appearance.manage also receive draft/history state.
/api/customization/preferencesGET, PATCHRead/save personal appearance preference.
/api/profile/embedGET, PATCHRead the account's embed choice and whether the instance allows one; save it with files.share (403 when personal embeds are off).
/api/profile/avatarPOSTUpload a PNG, JPEG, GIF, or WebP avatar up to 2 MB (413 if larger, 415 for other types); success yields {success:true,url}.
/api/profile/sharexGETDownload a ShareX configuration. ?profileId= selects an owned upload profile; never cached (private, no-store).
/api/profile/itakeGETDownload an iTake configuration. ?profileId= selects an owned upload profile; never cached (private, no-store).
/api/profile/bashGETDownload the Bash uploader script. ?profileId= selects an owned upload profile; never cached (private, no-store).
/api/profile/flameshotPOSTGenerate a Flameshot script from JSON useWayland and useCompositor. ?profileId= selects a profile; never cached.
/api/profile/spectaclePOSTGenerate a Spectacle script from JSON tool options (delay is optional). ?profileId= selects a profile; never cached.
/api/profile/export/progressGETStream server-sent progress of the caller's export started with this id; ends when it finishes or fails, or the client leaves.
/api/files/{id}PATCH, DELETEChange an owned file's visibility/password or delete it.

Every write these routes take from a browser session follows the browser-session write rule: Flare's own origin, and JSON or multipart bodies sent as such. Integration commands also bound the body size. Generated uploader configurations contain a credential and should be treated as private downloads.

POST /api/profile/avatar reads its image as the logo and favicon uploads do: content that isn't a PNG, JPEG, GIF, or WebP image answers 400 with File content is not a PNG, JPEG, GIF, or WebP image. An image in one of those formats sent as another of them, such as a JPEG sent as image/png, is accepted. Earlier builds refused that too and answered both with File content does not match claimed image type.

Archive workspace ​

The following owner-library archive operations require the owner's browser session and reject an Authorization header. content.read and administrator privileges do not substitute for source-file ownership on these routes. Share-page reads use the separate file-content routes above; creation and extraction remain owner-only. Their optional profileRevision and profileEffectiveRevision bind a selected profile and its effective inherited settings to the values returned by the profile list. See archive API contracts for formats, limits, request examples, and response shapes.

PathMethodsPurpose and permission
/api/files/{id}/archiveGETList an owned archive from its index; optional progress and after for polling a slow read; files.read.
/api/files/{id}/archive/entryGETStream one member by its path or entry position, with Range and inline media support; files.read.
/api/files/{id}/archive/extractPOSTExtract into a new wrapper folder; files.read, files.upload, and folders.manage.
/api/files/archivePOSTCreate ZIP or TAR.GZ from owned files; files.read and files.upload, plus folders.manage for a non-null destination.

Email account flows ​

Email enrollment and change operations use an account session that remains available for verification/recovery flows. They deliberately do not use upload bearer credentials. These verification, enrollment, recovery, and confirmed address-change paths remain available independently of profile.update, subject to identity proof and email policy, including restricted verification sessions. Email requests are limited per client IP address and per email address (limits); a refused request returns 429 with Retry-After set to the seconds until the limit that refused it resets.

PathMethodsAuthentication and purpose
/api/auth/email/statusGETSession; current verification, enrollment, change, and recovery eligibility.
/api/auth/email/enrollPOSTSession and recent identity/password requirements; begin local verification enrollment.
/api/auth/email/changePOSTSession and identity/policy checks; request an address change.
/api/auth/email/resendPOSTSession; resend an eligible pending verification.
/api/auth/email/cancel-changePOSTSession; cancel the pending address change.
/api/auth/email/request-resetPOSTPublic recovery request, rate-limited with a generic eligibility response.
/api/auth/email/resetPOSTA valid one-time reset token and new password; not an API bearer token.
/api/auth/email/verifyPOSTA valid one-time email action token.
/api/auth/email/capabilitiesGETPublic view of enabled email capabilities.

Email session mutations follow the browser-session write rule; earlier builds also accepted the origin of the email public URL. Password/identity confirmation, feature enablement, verified-address policy, and cooldowns are additional checks beyond the authentication column. An account that requires passkeys must supply fresh passkey or dedicated passkey-recovery session proof for enrollment and address changes; password/SSO proof cannot substitute. Password resets preserve that requirement.

GET /api/auth/email/status gives the account's eligibility already worked out, by the rules the email routes apply. canRequestChange says whether the account may ask for a new address now, which also needs a verified current address when the old address must approve changes. verifyBy is the date the account must verify by to keep access during an all-user grace period, or null when no deadline applies to it. Both fields are new; the older ones keep their values. canChangeEmail only says whether the instance allows address changes, graceEndsAt is the instance's grace end whether or not it applies to the account, verificationMode is the saved mode even while email is disabled (/api/auth/email/capabilities gives the mode in force), and hasPassword and requiresPassword always carry the same value.

Authenticator, recovery-code, and passkey flows ​

Security management uses the account browser session, independently of profile.update, and requires fresh identity proof for sensitive changes. Neither named tokens nor the legacy upload credential are accepted. Mutations follow the browser-session write rule; only passkeys need NEXTAUTH_URL. See session security contracts for request bodies, responses, limits, and sign-in behavior.

PathMethodsAuthentication and purpose
/api/auth/securityGETBrowser session; inspect authenticator/passkey status, the passkey requirement, and both remaining recovery-code counts.
/api/auth/security/totp/setupPOSTSession and identity proof; begin five-minute authenticator setup for an account with a local password.
/api/auth/security/totp/enablePOSTSession and correct pending setup code; enable TOTP and return one-time recovery codes.
/api/auth/security/totp/disablePOSTSession and identity proof; remove TOTP and recovery codes.
/api/auth/security/recovery-codesPOSTSession and identity proof; replace all recovery codes and return the new set once.
/api/auth/security/passkeys/optionsPOSTSession and identity proof; start account-bound passkey registration.
/api/auth/security/passkeys/verifyPOSTSession and pending WebAuthn proof; register the passkey.
/api/auth/security/passkeys/requirePOSTSession and fresh passkey proof to enable the requirement; fresh passkey or dedicated recovery proof to disable it.
/api/auth/security/passkeys/recovery-codesPOSTSession and fresh passkey/dedicated recovery proof; replace the dedicated recovery set while passkeys are required.
/api/auth/security/passkeys/{id}PATCH, DELETESession and identity proof; rename or remove an owned passkey.
/api/auth/passkeys/optionsPOSTPublic, rate-limited; begin passkey sign-in with an expiring WebAuthn challenge.

NextAuth completes passkey sign-in through its credentials callback after validating the WebAuthn proof; obtaining public options is not authentication. Its separate passkey-recovery provider accepts email plus a dedicated single-use code while the account requires passkeys. It identifies the current email case-insensitively and requires an unambiguous account match; conflicting legacy addresses are rejected without consuming a code. Credential additions/removals, either recovery-set change, and toggling the requirement invalidate browser sessions; renaming a passkey preserves them. API credentials and sharing permissions keep their existing boundaries. See the session security contract.

Personal session and login-history routes ​

These routes require the caller's own current browser session and do not require profile.update or users.sessions. They reject named API tokens and the legacy upload credential. Revocation is same-origin and does not retire integration credentials. Request/response contracts and runnable browser examples cover pagination and current-session sign-out.

PathMethodsAuthentication and purpose
/api/profile/sessionsGET, DELETEBrowser session; list active sessions, or revoke all of the caller's sessions including the current one. DELETE returns JSON.
/api/profile/sessions/{id}DELETEBrowser session; revoke one owned session, returning the count and whether the caller was signed out.
/api/profile/login-historyGETBrowser session; read the caller's attributed successful/failed login history with outcome and cursor filters.

Dashboard routes using the shared account helper ​

These routes use requireAccount, whose compatibility path accepts a browser session or the legacy account upload token. They are absent from the named-token allowlist, so an flr_… token cannot authorize them. This is why the legacy token should not be described as a narrowly scoped credential.

PathMethodsPurpose
/api/profilePUT, DELETEUpdate the account (image is ignored) or delete it with profile.update; password/plain-email updates also need browser-session identity proof. DELETE returns 204 once account removal and durable cleanup work commit.
/api/profile/upload-tokenGET, POSTRead or regenerate the legacy account upload credential. Responses send Cache-Control: private, no-store.
/api/profile/exportGETStream a ZIP of account data and stored files; the account guide describes its layout, entry names, and cancellation. Optional id (16-64 of A-Za-z0-9_-) names it for progress.
/api/files/{id}/expiryGET, POST, DELETEInspect, schedule, or cancel expiration for an owned file (404 for any other). POST takes expiresAt in the form uploads take and action: DELETE (default) or SET_PRIVATE.
/api/foldersGET, POSTList or create folders.
/api/folders/{id}PATCH, DELETERename an owned folder or turn its share link on or off (sharing also needs folders.share). DELETE dissolves it: its files and subfolders move up one level. PATCH can't move a folder.
/api/files/foldersPOSTMove owned files into a folder or make them unfiled.
/api/tagsGET, POSTList or create tags and their rules. Names are unique per account without regard to letter case; a duplicate answers 409.
/api/tags/{id}PATCH, DELETEEdit or delete an owned tag.
/api/tags/{id}/applyPOSTApply a tag's rule to existing files.
/api/files/tagsGET, PATCHGET reads current tag assignments for 1–100 owned file IDs with files.read; PATCH changes assignments with files.update and tags.manage. See the selection contract.

Writes from a browser session follow the browser-session write rule; legacy-token requests are not origin- or type-checked. This table describes actual authentication code, not a recommendation to use the legacy token to automate account changes. New integrations should use the documented named-token API, and people should use the dashboard for these operations.

Invite routes ​

These routes require a browser session; named API tokens and the legacy upload credential cannot authorize them. Mutations reject cross-origin requests, and request bodies must be JSON. Invite request/response contracts cover schemas, statuses, limits, and errors.

PathMethodsRequired permission and purpose
/api/invitesGET, POSTGET scope=mine: invites.create or invites.manage; GET scope=all: invites.manage. POST: invites.create; attaching roles also needs users.roles. Member limits apply without users.create.
/api/invites/{id}DELETERevoke: invites.create for your own invite, or invites.manage for anyone's. Returns the revoked invite as JSON.
/api/settings/invitesGET, PUTGET: settings.read; PUT: settings.security and your own invites.create. Read member limits, or add/remove invites.create on Everyone.

Delegated administration session routes ​

These operations require a browser session and the permission listed below. Administrator grants every permission. Account writes and role assignments also check hierarchy; role/account mutations preserve an accessible administrator. Named tokens do not inherit these capabilities from their owner. Role and account request/response contracts document replacement of the old scalar role field.

PathMethodsRequired permission and purpose
/api/auditGETaudit.read; filter instance-wide audit events by text, category, action, outcome, actor/target, time range, and page. Browser session only.
/api/rolesGET, POSTGET: any of roles.manage, users.roles, users.read; POST: roles.manage. List the catalog/roles or create a role.
/api/roles/{id}PATCH, DELETEroles.manage; edit/delete a role within hierarchy and delegation limits.
/api/usersGET, POST, PUTGET: users.read; POST: users.create; PUT identity: users.update. Assignment additionally requires users.roles; role-only PUT needs users.roles.
/api/users/{id}DELETEusers.delete; remove an account within delegation limits. Returns 204 after account removal and durable storage-cleanup work commit.
/api/users/{id}/avatarDELETEusers.update; clear an account's avatar and queue its stored bytes for cleanup; 204 after commit.
/api/users/{id}/sessionsDELETEusers.sessions; invalidate an account’s browser sessions. Success is 204 No Content, with no JSON body. API credentials remain active.
/api/users/{id}/emailGET, POSTusers.email; inspect/manage email access. GET adds canResend, whether the resend action would send another verification link.
/api/users/{id}/filesGETcontent.read; page through an account's files (limit default 10, at most 100). Contract.
/api/users/{id}/files/{fileId}PATCH, DELETEPATCH: content.update; DELETE: content.delete, returns 204. Wrong owner/missing file returns 404 (PATCH returned 500 before).
/api/users/{id}/urlsGETcontent.read; page through an account's short links: page, limit (default 10, at most 100), search. Contract.
/api/users/{id}/urls/{urlId}DELETEcontent.delete; session-only deletion of a short link owned by that target account. Returns 204; wrong owner/missing URL returns 404.
/api/users/{id}/loginPOSTusers.read; fetch target account information. Does not itself issue a login session. The dashboard no longer calls it; it remains for existing clients.
/api/settingsPATCH, POSTPATCH: corresponding section permission; legacy whole-settings POST: Administrator. Field mapping.
/api/settings/faviconPOST, DELETEappearance.manage; POST replaces the favicon with a multipart file, a PNG of at most 1 MB, and answers { url }. More.
/api/settings/emailGET, PUTsettings.email; read/save email configuration and diagnostics.
/api/settings/email/impactGET, POSTsettings.email; preview email-policy impact.
/api/settings/email/testPOSTsettings.email; test SMTP or send a test message.
/api/settings/email/retryPOSTsettings.email; retry an eligible outbox entry.
/api/customizationPOSTappearance.manage; save/import/publish/restore appearance, or reset-theme to publish Flare's default theme and classic colors.
/api/customization/assetsPOSTappearance.manage; turn a multipart file, a PNG, JPEG, or WebP of at most 256 KB, into a data URL, else 413, 415 or 400, as for the favicon.
/api/updates/checkGETsettings.read; check release availability.

Administration writes follow the browser-session write rule. Permission checks are independent of these request guards. A valid role does not bypass malformed requests, email eligibility, or ownership rules.

Favicon routes ​

POST /api/settings/favicon refuses a file over 1 MB with 413, a type other than PNG with 415, and content that isn't a PNG with 400. DELETE /api/settings/favicon stops pages linking the custom favicon, deletes the stored image and answers { url: null }, also when no favicon is set. Earlier versions had no DELETE. GET /api/favicon and GET /favicon.ico serve the image from Flare with every storage provider; earlier versions redirected S3 storage to a signed bucket URL. See Legacy colors and favicon.

A /api/settings save that includes storage settings with S3 selected answers 400 with the missing or invalid value, such as Bucket name is required, when the saved result would lack a bucket, region, either key, or a valid HTTP(S) endpoint; a blank key keeps the saved one. Earlier builds saved such settings.

PATCH and the legacy POST on /api/settings both save submitted custom CSS trimmed, with at most one blank line in a row. Earlier builds tidied it only in the POST, so CSS saved from Settings kept its extra blank lines.

Public and bootstrap routes ​

PathMethodsAuthentication and purpose
/api/healthGETPublic process liveness: { "success": true, "data": { "status": "ok" } }. Does not probe PostgreSQL or storage.
/api/oembedGETPublic oEmbed description of a share link, for preview apps. Answers only for a public file without a password; 404 otherwise and 501 for a format other than json.
/api/storage/typeGETPublic storage kind the saved settings name (local or s3). Earlier builds answered local when S3 couldn't start. Not a storage health check.
/api/setup/checkGETPublic setup-completion state: { "completed": boolean }, true once any account exists. Answers 503 when the database can't be read instead of reporting false.
/api/setupPOSTFirst-run bootstrap only while no users exist; creates Everyone, the full-access Admin role, the first account assignment, and settings atomically and rate-limits attempts.
/api/auth/registration-statusGETPublic registration availability and message.
/api/auth/registerPOSTPublic account creation, subject to registration settings, validation, email policy, and rate limits. An active invite creates an account while registration is closed and applies its roles.
/api/auth/{nextauth}GET, POSTNextAuth session, sign-in/out, provider, CSRF, and callback flows; protocol-specific protections apply.
/api/settingsGETReturns public settings by default. A browser session with settings.read receives private settings with storage/OIDC credentials masked; named tokens receive only the public projection.
/api/faviconGETServe the uploaded favicon; 404 when there is none. Only a ?v= naming the saved image is cached (one year). /favicon.ico answers the same. More.
/api/avatars/{filename}GETServe a currently referenced avatar; 404 for obsolete/unowned keys and 503 when its recorded storage target is unavailable.

Public does not mean unrestricted mutation: registration can be closed and bootstrap stops once a user exists. With closed registration, account creation additionally requires an active invite. Email one-time-token routes are listed separately because possession of the relevant action token is their authorization.

While the saved settings can't be read, because the database is unavailable or the saved document is invalid, routes that need them fail instead of using the defaults: GET /api/settings and POST /api/auth/register answer 500, and GET /api/auth/registration-status answers { "enabled": false, "message": "Registration is currently unavailable." }. Earlier builds answered with the default settings, which allow registration. See troubleshooting.

Every route that sets an account's name, address, or password applies one set of rules: POST /api/auth/register, POST /api/setup, POST and PUT /api/users, PUT /api/profile, and POST /api/auth/email/reset. A name needs at least one character, and a password needs at least 8 characters and at most 72 UTF-8 bytes whether or not account email is enabled; a longer one answers 400 with Password must use at most 72 bytes. Earlier versions applied that limit at registration and in /api/users only while account email was enabled, and needed two characters for a name outside setup. With account email enabled, an address another account uses in any capitalization is refused, and _ and % in an address are ordinary characters, not wildcards; with it disabled, one another account uses as written is refused, which PUT /api/users answered with 500 in earlier versions. A URL ID or vanity ID that another account uses as either kind of ID is refused with 400; see account contract changes. When the daily email limit stops a new account's verification message, POST /api/auth/register and POST /api/users answer 400 with The daily email sending limit has been reached. Try again tomorrow or contact your administrator., as the email routes do, where earlier versions answered 500.

Maintaining an integration ​

Build new automation against the named-token routes and their OpenAPI schemas. For dashboard behavior, treat route bodies and session flows as application internals that can evolve with Flare. There is currently no named-token administrator API, no general token-authorized file deletion/download API, and no chunk-cancel endpoint.

The route inventory is checked against the source tree when the documentation is validated, so a newly added route prompts a documentation update instead of silently expanding a token's authority.