Management API
List, create, reveal, and rotate the passwords of databases programmatically over a bearer-key HTTP API at hep.gg/api/v1/db, with the full request and response shapes, status codes, and error catalog.
Management API
The management API lets you list and create databases, and reveal or rotate their passwords, from a script or CI, without the dashboard. It is separate from the database connection itself: it speaks HTTP/JSON over https://hep.gg/api/v1/db and is authenticated with a bearer key, while your actual queries run against your databases at db.teamhydra.dev (see Connecting).
Authentication
Every request needs an Authorization header carrying a bearer key from the dashboard.
Authorization: Bearer hepgg_db_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxThe header also accepts a Token prefix, or the raw key with no prefix; Bearer is the conventional form. Keys are minted in the dashboard under Database, API Keys; there is no public endpoint to create one. A key can list and create databases, reveal a database's current password, and rotate it. It cannot delete a database; that stays dashboard-only.
Keys carry your account entitlements and are revoked instantly on suspension. Disabling a key (yourself, or via the suspension cascade) makes it stop authenticating immediately, no per-request lookup of your account state is needed.
Response envelope
All responses use a JSON envelope. Success:
{ "ok": true, "data": { } }Errors carry a human message and, where applicable, a machine code:
{ "ok": false, "error": "human-readable message", "code": "MACHINE_CODE" }Endpoints at a glance
| Method | Path | Auth | Purpose |
|---|---|---|---|
| GET | /api/v1/db/databases | Bearer key | List databases |
| POST | /api/v1/db/databases | Bearer key | Create a database |
| GET | /api/v1/db/databases/:id | Bearer key | Reveal a database |
| POST | /api/v1/db/databases/:id/rotate | Bearer key | Rotate a password |
Deleting a database is deliberately not exposed over the bearer API; do that from the dashboard.
List databases
https://hep.gg/api/v1/db/databasesAuth requiredReturns every database owned by the key's account, ordered by creation time. Passwords are never returned here; use Reveal a database to fetch one.
curl https://hep.gg/api/v1/db/databases \
-H "Authorization: Bearer $DB_KEY"const res = await fetch("https://hep.gg/api/v1/db/databases", {
headers: { Authorization: `Bearer ${process.env.DB_KEY}` },
});
const body = await res.json();
console.log(body.data.databases);{
"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"
}
]
}
}Each entry's fields:
idnameenginemariadb, postgres, mongo.dbNamedbUsersizeBytessizeRefreshedAtnull if never measured.statuscreatedAtCreate a database
https://hep.gg/api/v1/db/databasesAuth requiredProvisions a new database and its dedicated user. The password and connection string are returned in this response. Store them immediately; if you lose the password you can fetch it again with Reveal a database or replace it with Rotate a password (and the dashboard can do both too).
nameenginemariadbmariadb, postgres, mongo. Defaults to mariadb.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"}'const res = await fetch("https://hep.gg/api/v1/db/databases", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.DB_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ name: "my-app", engine: "mariadb" }),
});
const body = await res.json();
// Store body.data.password now: it is not returned again.
console.log(body.data.connectionString);A successful create returns HTTP 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"
}
}The connectionString scheme matches the engine: mysql:// for MariaDB, postgresql:// for Postgres, and mongodb://...?authSource=admin for MongoDB. The new database counts against your account-wide slot and storage quota, the same quota the dashboard uses.
Reveal a database
https://hep.gg/api/v1/db/databases/:idAuth requiredReturns a single database you own, including its current password and a ready-to-use connection string. Passwords are stored encrypted, so this decrypts the stored value; it does not reset it. A database id that is not yours returns 404.
curl https://hep.gg/api/v1/db/databases/$DB_ID \
-H "Authorization: Bearer $DB_KEY"const res = await fetch(`https://hep.gg/api/v1/db/databases/${dbId}`, {
headers: { Authorization: `Bearer ${process.env.DB_KEY}` },
});
const body = await res.json();
console.log(body.data.password, body.data.connectionString);The 200 body is the create-response shape plus the size and status fields from the list:
{
"ok": true,
"data": {
"id": "01HV...",
"name": "my-app",
"engine": "mariadb",
"dbName": "um_0a1b2c3d4e_1",
"dbUser": "dum_0a1b2c3d4e_1",
"password": "current password",
"connectionString": "mysql://dum_0a1b2c3d4e_1:...@db.teamhydra.dev:3306/um_0a1b2c3d4e_1",
"sizeBytes": 1048576,
"sizeRefreshedAt": "2026-05-28T12:00:00.000Z",
"status": "active",
"createdAt": "2026-05-20T09:30:00.000Z"
}
}Rotate a password
https://hep.gg/api/v1/db/databases/:id/rotateAuth requiredGenerates a new password, applies it to the database user on the engine, and returns it. The old password stops working immediately, so update anything that connects. A database id that is not yours returns 404. No request body.
curl -X POST https://hep.gg/api/v1/db/databases/$DB_ID/rotate \
-H "Authorization: Bearer $DB_KEY"const res = await fetch(`https://hep.gg/api/v1/db/databases/${dbId}/rotate`, {
method: "POST",
headers: { Authorization: `Bearer ${process.env.DB_KEY}` },
});
const body = await res.json();
// Store body.data.password now and reconnect with body.data.connectionString.{
"ok": true,
"data": {
"id": "01HV...",
"name": "my-app",
"engine": "mariadb",
"dbName": "um_0a1b2c3d4e_1",
"dbUser": "dum_0a1b2c3d4e_1",
"password": "the new password",
"connectionString": "mysql://dum_0a1b2c3d4e_1:...@db.teamhydra.dev:3306/um_0a1b2c3d4e_1"
}
}Errors and status codes
Errors use the standard envelope { "ok": false, "error": "...", "code": "..." }. The code is present on the machine-readable cases below; the duplicate-name and name-validation cases return a message without a code.
| Status | Code | When |
|---|---|---|
400 | (none) | The name failed validation (length, allowed characters, or first character). |
400 | ENGINE_DISABLED | The requested engine is not available on this deployment. |
401 | NO_KEY | No Authorization header, or an empty token. |
401 | BAD_KEY | The token does not match any key. |
401 | KEY_DISABLED | The key exists but is disabled (by you, or by a suspension cascade). |
402 | OUT_OF_SLOTS | No free database slots. Buy a pack or upgrade to Premium. |
403 | (none) | The owning account is suspended or not allowed to use the app. |
404 | NOT_FOUND | Reveal or rotate against a database id that is not one you own. |
409 | (none) | You already have a database with that name. |
Slot and storage limits are account-wide and shared with the dashboard. To add slots or storage, see the dashboard Top Up tab.