HF PanelDocsv1.0.0

HF Files and HF Studio API

Script a hosting account's files with HF Files and its databases with HF Studio, using hff_ tokens from a normal sign-in.

HF Files (the File Manager) and HF Studio (the database browser) each have their own JSON API under /api/v1. Their interfaces use it in the browser; your scripts can use it too, to upload a site, edit a file or run SQL as one hosting account.

App Address
HF Files https://files.yourdomain.com/api/v1/…, or https://panel.yourdomain.com:8443/files/api/v1/…
HF Studio https://db.yourdomain.com/api/v1/…, or https://panel.yourdomain.com:8443/studio/api/v1/…

GET /api/v1 on either app lists its addresses.

Note: these APIs work for one hosting account at a time and sign in as that account. To manage many accounts, use the token API with an hf_ token instead. hf_ tokens do not work here, and hff_ tokens do not work in the token API.

Signing in with an hff_ token

Scripts sign in with the account's username and password, adding "token": true. The answer holds a token that starts with hff_. Send it as Authorization: Bearer hff_… on every later request. No cookie and no CSRF token are needed.

bash
F=https://files.yourdomain.com
curl -s $F/api/v1/login -H 'Content-Type: application/json' \
     -d '{"username":"sarahbakes","password":"…","token":true}'
json
{
    "ok": true,
    "data": {
        "csrf": "…",
        "expires_in": 7200,
        "token": "hff_…",
        "user": {
            "email": "sarah@example.com",
            "staff": "",
            "username": "sarahbakes"
        }
    }
}

With two-factor login switched on, the first answer is {"twofa": true, "csrf": "…", "token": "hff_…"}. Send the code from the authenticator app (or a backup code) with that token within 5 minutes:

bash
curl -s $F/api/v1/login/2fa -H "Authorization: Bearer hff_xxx" -H 'Content-Type: application/json' \
     -d '{"code":"123456"}'
Rule What it means
Lifetime a token lasts 2 hours without use, and 12 hours at most
Per app an HF Files token works only in HF Files, an HF Studio token only in HF Studio
Restart tokens live in memory; restarting the service signs every token out
Password change changing the account's password ends its tokens
Suspension a suspended or deleted account is signed out within a minute
Same sign-in rules as the panel the same passwords, two-factor codes, lock-outs and activity log

Only hosting customers sign in to HF Files and HF Studio. Sign out with POST /api/v1/logout.

Answers

Every answer is {"ok": true, "data": …} or {"ok": false, "error": "…"}.

Status Means
200 done
400 bad input
401 sign in again ("login": true)
403 not the account's file or database, or (browsers) a missing CSRF token
404 no such file, table or row
409 HF Studio: unlock the PostgreSQL database first ("unlock": true)
413 too big
415 HF Files: a change that is not JSON
422 refused; the message says why
500, 502 trouble on the server

HF Files

path is always relative to the account's home folder, for example /web/example.com/public_html. name, from, to and items are names inside path. Paths cannot leave the home folder, and /web, /logs, /tmp, /.ssh and the home folder itself cannot be deleted or renamed.

Method Path Body or query Answer data
GET /api/v1/files ?path=/web path, parts, up, writable, items[] (name, type, dir, link, size, mtime, perms, writable, editable, image, zip)
GET /api/v1/files/content ?path=<file> path, dir, name, content, writable (text files up to 5 MB)
PUT /api/v1/files/content {"path","content"} path, saved
GET /api/v1/files/download ?path=<file>[&inline=1] the file
GET /api/v1/files/size ?path=<file or folder> bytes
POST /api/v1/files/upload ?path=<folder>, multipart files[] (up to 1 GB per request) uploaded[], count; files of the same name are replaced
POST /api/v1/files/folder {"path","name"} path
POST /api/v1/files/file {"path","name"} path
POST /api/v1/files/rename {"path","from","to"} path
POST /api/v1/files/copy {"path","from","to"} path
POST /api/v1/files/move {"path","items":[…],"dest"} moved, dest
POST /api/v1/files/chmod {"path","name","mode":"644"} mode
POST /api/v1/files/delete {"path","items":[…]} deleted
POST /api/v1/files/zip {"path","items":[…],"name":"archive.zip"} name, path
POST /api/v1/files/unzip {"path","name"} files
GET /api/v1/shares [?path=<file or folder>] shares[], now
POST /api/v1/shares {"path","hours","password","max_downloads"} the new share link
POST /api/v1/shares/revoke {"id"} revoked

For share links, hours is 1–720 (0 = never expires), an empty password means none, and max_downloads 0 means no limit. Anyone can open a share link at https://files.yourdomain.com/s/<token> without signing in.

Example: upload and unpack a site

bash
F=https://files.yourdomain.com
T=hff_xxx
P=/web/example.com/public_html

curl -s -H "Authorization: Bearer $T" -F 'files[]=@site.zip' "$F/api/v1/files/upload?path=$P"
curl -s -H "Authorization: Bearer $T" -H 'Content-Type: application/json' $F/api/v1/files/unzip \
     -d "{\"path\":\"$P\",\"name\":\"site.zip\"}"
curl -s -H "Authorization: Bearer $T" "$F/api/v1/files?path=$P" | jq '.data.items[].name'
curl -s -H "Authorization: Bearer $T" -X POST $F/api/v1/logout

HF Studio

HF Studio opens only the account's own databases: MySQL/MariaDB (e=my), PostgreSQL (e=pg) and MongoDB (e=mg), named <username>_…, and only kinds the account's plan includes. Any other database answers 403 "You can’t open that database."

Method Path Body or query Answer data
GET /api/v1/databases dbs[] (id, name, engine, size), pgReady, mgReady, limits, remote
GET /api/v1/database ?e=&db= engine, name, id, tables[], and error or password
GET /api/v1/table/rows ?e=&db=&t=[&p&n&s&d&q&fc&fo&fv] the table and one page of rows (browse)
GET /api/v1/table/structure ?e=&db=&t= the table with indexes, fks, create
POST /api/v1/sql {"e","db","sql","limit"} results[], failed
POST /api/v1/row {"e","db","t","key":{…}} cols, vals, long
POST /api/v1/row/save, /row/add, /row/delete {"e","db","t","key":{…},"vals":{…}} {}
POST /api/v1/unlock {"e":"pg","db","password"} {}
POST /api/v1/import ?e=&db=, multipart file (.sql or .sql.gz) file, done
GET /api/v1/export ?what=table|db&e=&db=[&t=]&fmt=sql|csv the download
GET /api/v1/mongo/docs ?db=&c=[&p&n&f&s&pr] the collection, docs[], fields, total, page, per
POST /api/v1/mongo/doc, /doc/save, /doc/add, /doc/delete {"db","c","id","doc"} the document, or {"id"}
GET /api/v1/mongo/indexes ?db=&c= indexes[]
POST /api/v1/mongo/query {"db","c","kind":"find|aggregate",…,"limit"} docs[], fields, more, error
POST /api/v1/mongo/collection, /collection/drop {"db","name"} or {"db","c"} {"name"} or {}
POST /api/v1/mongo/import ?db=&c=, multipart file (.json, .jsonl, .csv, .gz) file, done
GET /api/v1/mongo/export ?db=&c=&fmt=json|jsonl|csv, or ?db=&what=db the download

Limits: 30 seconds per statement, 1,000 rows per result, 200 statements per run, 1 MB of SQL text per run, and imports up to the server's import limit (128 MB unless the administrator changed it). A failed SQL statement is not an HTTP error: it is that result's error, with the line where the statement starts.

Example: run SQL

bash
S=https://db.yourdomain.com
T=$(curl -s $S/api/v1/login -H 'Content-Type: application/json' \
      -d '{"username":"sarahbakes","password":"…","token":true}' | jq -r .data.token)

curl -s -H "Authorization: Bearer $T" -H 'Content-Type: application/json' $S/api/v1/sql \
     -d '{"e":"my","db":"sarahbakes_shop","sql":"SELECT id, name FROM products LIMIT 5;","limit":5}'
json
{
    "ok": true,
    "data": {
        "results": [
            {
                "n": 1,
                "line": 1,
                "sql": "SELECT id, name FROM products LIMIT 5",
                "ms": 2,
                "cols": [
                    {"name": "id", "type": "INT", "bin": false},
                    {"name": "name", "type": "VARCHAR", "bin": false}
                ],
                "rows": [
                    ["1", "Sourdough loaf"],
                    ["2", "Lemon drizzle"]
                ],
                "more": false
            }
        ],
        "failed": false
    }
}

Every change made through HF Files or HF Studio is written to the account's activity log.