# Hep.gg Database Management API Provision and list user databases (MariaDB, Postgres, MongoDB) over a simple HTTP/JSON API, without the dashboard. This is the control plane only: it creates databases and returns their connection details. Your actual SQL/Mongo queries run against the database host, not against this API. Base URL: https://hep.gg Management API path: /api/v1/db Auth: Authorization: Bearer hepgg_db_ (a "Token " prefix, or the raw key with no prefix, are also accepted) Keys are created in the dashboard at /dashboard/database/api-keys. There is no public endpoint to create a key. A key can list, create, reveal the password of, and rotate the password of your databases. It cannot DELETE a database (that stays dashboard-only). Passwords are stored AES-256-GCM-encrypted, so "reveal" decrypts the stored password rather than resetting it. Disabling a key (or a suspension of the account) stops it authenticating immediately, with no per-request account lookup needed. Database CONNECTIONS (not this API) are made to host db.teamhydra.dev using the per-database username and password returned at create time. ## Endpoints ### GET /api/v1/db/databases List every database owned by the key's account, oldest first. No secrets are returned (reveal or rotate passwords from the dashboard). Response 200: { "ok": true, "data": { "databases": [ { "id": "01HV...", "name": "my-app", "engine": "mariadb", "dbName": "um_0a1b2c3d4e_1", "dbUser": "dum_0a1b2c3d4e_1", "sizeBytes": 1048576, "sizeRefreshedAt": "2026-05-28T12:00:00.000Z", "status": "active", "createdAt": "2026-05-20T09:30:00.000Z" } ] } } Fields: id Stable database identifier. name Friendly label chosen at creation. engine "mariadb" | "postgres" | "mongo". dbName Connection-level database name (auto-generated). dbUser Connection-level database user. sizeBytes Last measured on-disk size (refreshed by the quota watcher). sizeRefreshedAt ISO 8601 of the last size measurement, or null if never. status "active" | "over_quota" | "disabled". createdAt ISO 8601 creation timestamp. ### POST /api/v1/db/databases Provision a new database and its dedicated user. The password and connection string are returned ONLY in this response and never again by the API. Store them immediately; you can still reveal or rotate the password in the dashboard. Request body (JSON): name string required. 1-63 chars: letters, digits, underscore, dash; must start with a letter or digit; unique within your account. engine string optional. "mariadb" (default), "postgres", or "mongo". Response 201: { "ok": true, "data": { "id": "01HV...", "name": "my-app", "engine": "mariadb", "dbName": "um_0a1b2c3d4e_1", "dbUser": "dum_0a1b2c3d4e_1", "password": "shown once - store it now", "connectionString": "mysql://dum_0a1b2c3d4e_1:...@db.teamhydra.dev:3306/um_0a1b2c3d4e_1" } } connectionString scheme + port by engine: mariadb mysql://USER:PASS@db.teamhydra.dev:3306/DBNAME postgres postgresql://USER:PASS@db.teamhydra.dev:5432/DBNAME mongo mongodb://USER:PASS@db.teamhydra.dev:27017/DBNAME?authSource=admin MongoDB connection strings MUST keep ?authSource=admin (the user lives in the admin auth database). The new database counts against your account-wide slot and storage quota, the same quota the dashboard enforces. ### GET /api/v1/db/databases/:id Reveal one database, including its current password and connection string. Same data the dashboard shows on the database card. Owner-scoped: a database id that isn't yours returns 404. Response 200: same object shape as the create response (id, name, engine, dbName, dbUser, password, connectionString) plus sizeBytes, sizeRefreshedAt, status, createdAt. ### POST /api/v1/db/databases/:id/rotate Set a new password on the database's user and return it. The old password stops working immediately; update anything that connects. Owner-scoped (404 if the id isn't yours). Response 200: { "ok": true, "data": { "id": "01HV...", "name": "my-app", "engine": "mariadb", "dbName": "um_0a1b2c3d4e_1", "dbUser": "dum_0a1b2c3d4e_1", "password": "", "connectionString": "mysql://dum_0a1b2c3d4e_1:...@db.teamhydra.dev:3306/um_0a1b2c3d4e_1" } } ### Examples List: curl https://hep.gg/api/v1/db/databases \ -H "Authorization: Bearer $DB_KEY" Create: curl -X POST https://hep.gg/api/v1/db/databases \ -H "Authorization: Bearer $DB_KEY" \ -H "Content-Type: application/json" \ -d '{"name":"my-app","engine":"mariadb"}' ## Errors Standard envelope: { "ok": false, "error": "", "code"?: "" }. 400 (no code) name failed validation (length, characters, first char). 400 ENGINE_DISABLED requested engine is not available on this deployment. 401 NO_KEY missing Authorization header, or empty token. 401 BAD_KEY token matches no key. 401 KEY_DISABLED key exists but is disabled (by you or a suspension). 402 OUT_OF_SLOTS no free database slots; buy a pack or upgrade to Prime. 403 (no code) owning account is suspended or not allowed the app. 409 (no code) you already have a database with that name. The reveal and rotate endpoints add: 404 NOT_FOUND when the database id is not one of yours. Deleting a database is intentionally NOT exposed on the bearer API; do that from the dashboard. ## Hep.gg dashboard endpoints (cookie auth - not for programmatic use) Listed for completeness; these require an active Hep.gg session and are mounted under /api/v1/database (note: distinct from the bearer API at /api/v1/db): GET /api/v1/database/usage (overview + your databases) POST /api/v1/database/databases { name, engine? } GET /api/v1/database/databases/:id DELETE /api/v1/database/databases/:id POST /api/v1/database/databases/:id/rotate (rotate password) GET /api/v1/database/packs POST /api/v1/database/purchases/trade (buy slots / storage with credits) GET /api/v1/database/keys POST /api/v1/database/keys { label? } PATCH /api/v1/database/keys/:id { label?, disabled? } POST /api/v1/database/keys/:id/rotate DELETE /api/v1/database/keys/:id