API reference
Databases
Create and manage your free MariaDB and Postgres databases from code.
← API docs7 endpointsUpdated
Browse the docs
Databases
Free MariaDB and Postgres databases that belong to the account rather than to one of its servers. Only available while the feature is switched on; otherwise every endpoint here returns 404.
List the account's databases
GET/databases
Account scope databases.read
Returns, in one response, the account's databases with their connection details (passwords included), how many it may have, and the versions it can create or move to. An account may have 2 databases in total, of any engine or version, each with a hard disk quota of 50 MiB. Engines are mariadb and postgres; which versions exist changes over time, so read them from versions. Returns 404 while databases are switched off.
Example
curl "https://sillydev.co.uk/panel/api/client/databases" \ -H "Authorization: Bearer $SILLYDEV_API_KEY" \ -H "Accept: application/json"
Response 200The databases, the allowance and the versions on offer.
{
"object": "user_database_list",
"attributes": {
"limit": 2,
"owned": 1,
"can_create": true,
"quota_bytes": 52428800,
"versions": [
{
"id": 3,
"engine": "mariadb",
"name": "MariaDB 11.4",
"server_version": "11.4.3",
"label": "recommended",
"status": "active",
"legacy_ends_at": null,
"host": "db.sillydev.co.uk",
"port": 3306
},
{
"id": 5,
"engine": "postgres",
"name": "Postgres 17",
"server_version": "17.2",
"label": "recommended",
"status": "active",
"legacy_ends_at": null,
"host": "db.sillydev.co.uk",
"port": 5432
}
],
"databases": [
{
"object": "user_database",
"attributes": {
"id": 12,
"label": "Discord bot",
"engine": "mariadb",
"name": "discord_bot_k3j9x0",
"username": "u42_p0zt7c1m",
"password": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"host": "db.sillydev.co.uk",
"port": 3306,
"version": {
"id": 3,
"engine": "mariadb",
"name": "MariaDB 11.4",
"server_version": "11.4.3",
"label": "recommended",
"status": "active",
"legacy_ends_at": null,
"host": "db.sillydev.co.uk",
"port": 3306
},
"status": "ready",
"moving_to": null,
"last_move_error": null,
"previous_version": null,
"previous_expires_at": null,
"moved_at": null,
"can_undo_move": false,
"size_bytes": 1310720,
"quota_bytes": 52428800,
"size_checked_at": "2026-10-10T12:00:00+00:00",
"created_at": "2026-10-01T09:30:00+00:00"
}
}
]
}
}Every field in the response
| Name | Type | Description |
|---|---|---|
| objectrequired | string | |
| attributesrequired | object | |
| attributes.limitrequired | integer | How many databases the account may have. |
| attributes.ownedrequired | integer | |
| attributes.can_createrequired | boolean | |
| attributes.quota_bytesrequired | integer | Each database's disk quota in bytes. |
| attributes.versionsrequired | array of object | Active versions, plus any legacy version the account still has a database on. |
| attributes.versions[].idrequired | integer | Send as version_id to create or move a database. |
| attributes.versions[].enginerequired | one of 'mariadb', 'postgres' | |
| attributes.versions[].namerequired | string | |
| attributes.versions[].server_versionrequired | string | |
| attributes.versions[].labelrequired | one of 'recommended', 'older', null | |
| attributes.versions[].statusrequired | one of 'active', 'legacy', 'retired' | Only active versions take new databases. A legacy one is listed only when the account has a database on it; at legacy_ends_at its databases are moved to the engine's recommended version. |
| attributes.versions[].legacy_ends_atrequired | string (date-time) | null | |
| attributes.versions[].hostrequired | string | |
| attributes.versions[].portrequired | integer | |
| attributes.databasesrequired | array of object | |
| attributes.databases[].objectrequired | string | |
| attributes.databases[].attributesrequired | object | |
| attributes.databases[].attributes.idrequired | integer | |
| attributes.databases[].attributes.labelrequired | string | The name the owner gave it. |
| attributes.databases[].attributes.enginerequired | one of 'mariadb', 'postgres' | |
| attributes.databases[].attributes.namerequired | string | The database name to connect to. |
| attributes.databases[].attributes.usernamerequired | string | |
| attributes.databases[].attributes.passwordrequired | string | The current password, in plain text. |
| attributes.databases[].attributes.hostrequired | string | |
| attributes.databases[].attributes.portrequired | integer | |
| attributes.databases[].attributes.versionrequired | object | |
| attributes.databases[].attributes.statusrequired | one of 'ready', 'moving' | |
| attributes.databases[].attributes.moving_torequired | any | |
| attributes.databases[].attributes.last_move_errorrequired | string | null | Why the last move failed, if it did. The database stayed on its old version. |
| attributes.databases[].attributes.previous_versionrequired | any | The version a copy is kept on after a move, until previous_expires_at. |
| attributes.databases[].attributes.previous_expires_atrequired | string (date-time) | null | |
| attributes.databases[].attributes.moved_atrequired | string (date-time) | null | |
| attributes.databases[].attributes.can_undo_moverequired | boolean | |
| attributes.databases[].attributes.size_bytesrequired | integer | null | Disk used, as of size_checked_at. |
| attributes.databases[].attributes.quota_bytesrequired | integer | Hard disk quota. Writes beyond it fail. |
| attributes.databases[].attributes.size_checked_atrequired | string (date-time) | null | |
| attributes.databases[].attributes.created_atrequired | string (date-time) |
Errors
- 401 No API key was sent, or it is wrong, expired or deleted.
- 403 The key is valid but may not do this: it lacks the permission or account scope, it is limited to other servers or IP addresses, or the account may not do it at all.
- 404 There is no such resource, or the key cannot see it. Features that are switched off answer 404 too.
Create a database
POST/databases
Account scope databases.writeLimited to 5 per minute
Creates a database on an active version and returns it with its connection details. The database name is made from the label plus a random suffix, and the username and a 32-character password are generated. Refused with 409 when the account already has 2 databases or another creation is still running. Returns 404 while databases are switched off.
Body
| Name | Type | Description |
|---|---|---|
| labelrequired | string | |
| version_idrequired | integer | The id of an active version. |
Example
curl -X POST "https://sillydev.co.uk/panel/api/client/databases" \
-H "Authorization: Bearer $SILLYDEV_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"label":"Discord bot","version_id":3}'Response 201The new database.
{
"object": "user_database",
"attributes": {
"id": 12,
"label": "Discord bot",
"engine": "mariadb",
"name": "discord_bot_k3j9x0",
"username": "u42_p0zt7c1m",
"password": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"host": "db.sillydev.co.uk",
"port": 3306,
"version": {
"id": 3,
"engine": "mariadb",
"name": "MariaDB 11.4",
"server_version": "11.4.3",
"label": "recommended",
"status": "active",
"legacy_ends_at": null,
"host": "db.sillydev.co.uk",
"port": 3306
},
"status": "ready",
"moving_to": null,
"last_move_error": null,
"previous_version": null,
"previous_expires_at": null,
"moved_at": null,
"can_undo_move": false,
"size_bytes": 0,
"quota_bytes": 52428800,
"size_checked_at": "2026-10-10T12:00:00+00:00",
"created_at": "2026-10-10T12:00:00+00:00"
}
}Every field in the response
| Name | Type | Description |
|---|---|---|
| objectrequired | string | |
| attributesrequired | object | |
| attributes.idrequired | integer | |
| attributes.labelrequired | string | The name the owner gave it. |
| attributes.enginerequired | one of 'mariadb', 'postgres' | |
| attributes.namerequired | string | The database name to connect to. |
| attributes.usernamerequired | string | |
| attributes.passwordrequired | string | The current password, in plain text. |
| attributes.hostrequired | string | |
| attributes.portrequired | integer | |
| attributes.versionrequired | object | |
| attributes.version.idrequired | integer | Send as version_id to create or move a database. |
| attributes.version.enginerequired | one of 'mariadb', 'postgres' | |
| attributes.version.namerequired | string | |
| attributes.version.server_versionrequired | string | |
| attributes.version.labelrequired | one of 'recommended', 'older', null | |
| attributes.version.statusrequired | one of 'active', 'legacy', 'retired' | Only active versions take new databases. A legacy one is listed only when the account has a database on it; at legacy_ends_at its databases are moved to the engine's recommended version. |
| attributes.version.legacy_ends_atrequired | string (date-time) | null | |
| attributes.version.hostrequired | string | |
| attributes.version.portrequired | integer | |
| attributes.statusrequired | one of 'ready', 'moving' | |
| attributes.moving_torequired | any | |
| attributes.last_move_errorrequired | string | null | Why the last move failed, if it did. The database stayed on its old version. |
| attributes.previous_versionrequired | any | The version a copy is kept on after a move, until previous_expires_at. |
| attributes.previous_expires_atrequired | string (date-time) | null | |
| attributes.moved_atrequired | string (date-time) | null | |
| attributes.can_undo_moverequired | boolean | |
| attributes.size_bytesrequired | integer | null | Disk used, as of size_checked_at. |
| attributes.quota_bytesrequired | integer | Hard disk quota. Writes beyond it fail. |
| attributes.size_checked_atrequired | string (date-time) | null | |
| attributes.created_atrequired | string (date-time) |
Errors
- 400 The request could not be carried out as sent.
detailsays why. - 401 No API key was sent, or it is wrong, expired or deleted.
- 403 The key is valid but may not do this: it lacks the permission or account scope, it is limited to other servers or IP addresses, or the account may not do it at all.
- 404 There is no such resource, or the key cannot see it. Features that are switched off answer 404 too.
- 409 The account is at its database limit, or a database is already being created for it.
- 422 Some fields were missing or invalid. There is one error per problem, and
meta.source_fieldnames the field. - 429 Too many requests. Wait for the number of seconds in the
Retry-Afterheader, then try again. - 502 The database server could not be reached or refused the request. Try again in a few minutes.
Rotate a database's password
POST/databases/{database}/rotate-password
Account scope databases.writeLimited to 10 per minute
Gives the database a new random 32-character password and returns the database with it. The old password stops working at once. If a copy is being kept from a recent move it gets the new password too. Refused with 409 while the database is being moved.
Parameters
| Name | Type | Description |
|---|---|---|
| databaserequired | integer | The database's numeric id. |
Example
curl -X POST "https://sillydev.co.uk/panel/api/client/databases/{database}/rotate-password" \
-H "Authorization: Bearer $SILLYDEV_API_KEY" \
-H "Accept: application/json"Response 200The database with its new password.
Every field in the response
| Name | Type | Description |
|---|---|---|
| objectrequired | string | |
| attributesrequired | object | |
| attributes.idrequired | integer | |
| attributes.labelrequired | string | The name the owner gave it. |
| attributes.enginerequired | one of 'mariadb', 'postgres' | |
| attributes.namerequired | string | The database name to connect to. |
| attributes.usernamerequired | string | |
| attributes.passwordrequired | string | The current password, in plain text. |
| attributes.hostrequired | string | |
| attributes.portrequired | integer | |
| attributes.versionrequired | object | |
| attributes.version.idrequired | integer | Send as version_id to create or move a database. |
| attributes.version.enginerequired | one of 'mariadb', 'postgres' | |
| attributes.version.namerequired | string | |
| attributes.version.server_versionrequired | string | |
| attributes.version.labelrequired | one of 'recommended', 'older', null | |
| attributes.version.statusrequired | one of 'active', 'legacy', 'retired' | Only active versions take new databases. A legacy one is listed only when the account has a database on it; at legacy_ends_at its databases are moved to the engine's recommended version. |
| attributes.version.legacy_ends_atrequired | string (date-time) | null | |
| attributes.version.hostrequired | string | |
| attributes.version.portrequired | integer | |
| attributes.statusrequired | one of 'ready', 'moving' | |
| attributes.moving_torequired | any | |
| attributes.last_move_errorrequired | string | null | Why the last move failed, if it did. The database stayed on its old version. |
| attributes.previous_versionrequired | any | The version a copy is kept on after a move, until previous_expires_at. |
| attributes.previous_expires_atrequired | string (date-time) | null | |
| attributes.moved_atrequired | string (date-time) | null | |
| attributes.can_undo_moverequired | boolean | |
| attributes.size_bytesrequired | integer | null | Disk used, as of size_checked_at. |
| attributes.quota_bytesrequired | integer | Hard disk quota. Writes beyond it fail. |
| attributes.size_checked_atrequired | string (date-time) | null | |
| attributes.created_atrequired | string (date-time) |
Errors
- 401 No API key was sent, or it is wrong, expired or deleted.
- 403 The key is valid but may not do this: it lacks the permission or account scope, it is limited to other servers or IP addresses, or the account may not do it at all.
- 404 There is no such resource, or the key cannot see it. Features that are switched off answer 404 too.
- 409 The resource is busy or in a state that does not allow this right now.
- 429 Too many requests. Wait for the number of seconds in the
Retry-Afterheader, then try again. - 502 The database server could not be reached or refused the request. Try again in a few minutes.
Move a database to another version
POST/databases/{database}/move
Account scope databases.writeLimited to 5 per minute
Queues a move of the database to another active version of the same engine on the same database server, and returns at once with status set to moving. Poll the database list until status is ready again: on success version is the new one and the old copy is kept, locked, for 7 days so the move can be undone; on failure the database stays where it was and last_move_error says why. Refused with 409 while a move is running or while a copy from the last move is still kept (undo or keep it first), and with 422 for the same version, another engine, another database server or a version that is not active.
Parameters
| Name | Type | Description |
|---|---|---|
| databaserequired | integer | The database's numeric id. |
Body
| Name | Type | Description |
|---|---|---|
| version_idrequired | integer | The id of another active version of the same engine. |
Example
curl -X POST "https://sillydev.co.uk/panel/api/client/databases/{database}/move" \
-H "Authorization: Bearer $SILLYDEV_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"version_id":4}'Response 202The move is queued; the database is returned with `status` `moving` and `moving_to` set.
Every field in the response
| Name | Type | Description |
|---|---|---|
| objectrequired | string | |
| attributesrequired | object | |
| attributes.idrequired | integer | |
| attributes.labelrequired | string | The name the owner gave it. |
| attributes.enginerequired | one of 'mariadb', 'postgres' | |
| attributes.namerequired | string | The database name to connect to. |
| attributes.usernamerequired | string | |
| attributes.passwordrequired | string | The current password, in plain text. |
| attributes.hostrequired | string | |
| attributes.portrequired | integer | |
| attributes.versionrequired | object | |
| attributes.version.idrequired | integer | Send as version_id to create or move a database. |
| attributes.version.enginerequired | one of 'mariadb', 'postgres' | |
| attributes.version.namerequired | string | |
| attributes.version.server_versionrequired | string | |
| attributes.version.labelrequired | one of 'recommended', 'older', null | |
| attributes.version.statusrequired | one of 'active', 'legacy', 'retired' | Only active versions take new databases. A legacy one is listed only when the account has a database on it; at legacy_ends_at its databases are moved to the engine's recommended version. |
| attributes.version.legacy_ends_atrequired | string (date-time) | null | |
| attributes.version.hostrequired | string | |
| attributes.version.portrequired | integer | |
| attributes.statusrequired | one of 'ready', 'moving' | |
| attributes.moving_torequired | any | |
| attributes.last_move_errorrequired | string | null | Why the last move failed, if it did. The database stayed on its old version. |
| attributes.previous_versionrequired | any | The version a copy is kept on after a move, until previous_expires_at. |
| attributes.previous_expires_atrequired | string (date-time) | null | |
| attributes.moved_atrequired | string (date-time) | null | |
| attributes.can_undo_moverequired | boolean | |
| attributes.size_bytesrequired | integer | null | Disk used, as of size_checked_at. |
| attributes.quota_bytesrequired | integer | Hard disk quota. Writes beyond it fail. |
| attributes.size_checked_atrequired | string (date-time) | null | |
| attributes.created_atrequired | string (date-time) |
Errors
- 401 No API key was sent, or it is wrong, expired or deleted.
- 403 The key is valid but may not do this: it lacks the permission or account scope, it is limited to other servers or IP addresses, or the account may not do it at all.
- 404 There is no such resource, or the key cannot see it. Features that are switched off answer 404 too.
- 409 The resource is busy or in a state that does not allow this right now.
- 422 Some fields were missing or invalid. There is one error per problem, and
meta.source_fieldnames the field. - 429 Too many requests. Wait for the number of seconds in the
Retry-Afterheader, then try again.
Undo a database move
POST/databases/{database}/undo-move
Account scope databases.write
Switches the database back to the copy kept from its last move and deletes the moved copy. Anything written since the move is lost. Only possible while can_undo_move is true, and refused with 409 when the old version has reached its end date.
Parameters
| Name | Type | Description |
|---|---|---|
| databaserequired | integer | The database's numeric id. |
Example
curl -X POST "https://sillydev.co.uk/panel/api/client/databases/{database}/undo-move" \
-H "Authorization: Bearer $SILLYDEV_API_KEY" \
-H "Accept: application/json"Response 200The database, back on its previous version.
Every field in the response
| Name | Type | Description |
|---|---|---|
| objectrequired | string | |
| attributesrequired | object | |
| attributes.idrequired | integer | |
| attributes.labelrequired | string | The name the owner gave it. |
| attributes.enginerequired | one of 'mariadb', 'postgres' | |
| attributes.namerequired | string | The database name to connect to. |
| attributes.usernamerequired | string | |
| attributes.passwordrequired | string | The current password, in plain text. |
| attributes.hostrequired | string | |
| attributes.portrequired | integer | |
| attributes.versionrequired | object | |
| attributes.version.idrequired | integer | Send as version_id to create or move a database. |
| attributes.version.enginerequired | one of 'mariadb', 'postgres' | |
| attributes.version.namerequired | string | |
| attributes.version.server_versionrequired | string | |
| attributes.version.labelrequired | one of 'recommended', 'older', null | |
| attributes.version.statusrequired | one of 'active', 'legacy', 'retired' | Only active versions take new databases. A legacy one is listed only when the account has a database on it; at legacy_ends_at its databases are moved to the engine's recommended version. |
| attributes.version.legacy_ends_atrequired | string (date-time) | null | |
| attributes.version.hostrequired | string | |
| attributes.version.portrequired | integer | |
| attributes.statusrequired | one of 'ready', 'moving' | |
| attributes.moving_torequired | any | |
| attributes.last_move_errorrequired | string | null | Why the last move failed, if it did. The database stayed on its old version. |
| attributes.previous_versionrequired | any | The version a copy is kept on after a move, until previous_expires_at. |
| attributes.previous_expires_atrequired | string (date-time) | null | |
| attributes.moved_atrequired | string (date-time) | null | |
| attributes.can_undo_moverequired | boolean | |
| attributes.size_bytesrequired | integer | null | Disk used, as of size_checked_at. |
| attributes.quota_bytesrequired | integer | Hard disk quota. Writes beyond it fail. |
| attributes.size_checked_atrequired | string (date-time) | null | |
| attributes.created_atrequired | string (date-time) |
Errors
- 401 No API key was sent, or it is wrong, expired or deleted.
- 403 The key is valid but may not do this: it lacks the permission or account scope, it is limited to other servers or IP addresses, or the account may not do it at all.
- 404 There is no such resource, or the key cannot see it. Features that are switched off answer 404 too.
- 409 The resource is busy or in a state that does not allow this right now.
- 502 The database server could not be reached or refused the request. Try again in a few minutes.
Keep a database move
POST/databases/{database}/keep-move
Account scope databases.write
Deletes the copy kept from the database's last move, ending the undo window early so the database can be moved again. Does nothing harmful if there is no kept copy. Refused with 409 while the database is being moved.
Parameters
| Name | Type | Description |
|---|---|---|
| databaserequired | integer | The database's numeric id. |
Example
curl -X POST "https://sillydev.co.uk/panel/api/client/databases/{database}/keep-move" \
-H "Authorization: Bearer $SILLYDEV_API_KEY" \
-H "Accept: application/json"Response 200The database, with `previous_version` cleared.
Every field in the response
| Name | Type | Description |
|---|---|---|
| objectrequired | string | |
| attributesrequired | object | |
| attributes.idrequired | integer | |
| attributes.labelrequired | string | The name the owner gave it. |
| attributes.enginerequired | one of 'mariadb', 'postgres' | |
| attributes.namerequired | string | The database name to connect to. |
| attributes.usernamerequired | string | |
| attributes.passwordrequired | string | The current password, in plain text. |
| attributes.hostrequired | string | |
| attributes.portrequired | integer | |
| attributes.versionrequired | object | |
| attributes.version.idrequired | integer | Send as version_id to create or move a database. |
| attributes.version.enginerequired | one of 'mariadb', 'postgres' | |
| attributes.version.namerequired | string | |
| attributes.version.server_versionrequired | string | |
| attributes.version.labelrequired | one of 'recommended', 'older', null | |
| attributes.version.statusrequired | one of 'active', 'legacy', 'retired' | Only active versions take new databases. A legacy one is listed only when the account has a database on it; at legacy_ends_at its databases are moved to the engine's recommended version. |
| attributes.version.legacy_ends_atrequired | string (date-time) | null | |
| attributes.version.hostrequired | string | |
| attributes.version.portrequired | integer | |
| attributes.statusrequired | one of 'ready', 'moving' | |
| attributes.moving_torequired | any | |
| attributes.last_move_errorrequired | string | null | Why the last move failed, if it did. The database stayed on its old version. |
| attributes.previous_versionrequired | any | The version a copy is kept on after a move, until previous_expires_at. |
| attributes.previous_expires_atrequired | string (date-time) | null | |
| attributes.moved_atrequired | string (date-time) | null | |
| attributes.can_undo_moverequired | boolean | |
| attributes.size_bytesrequired | integer | null | Disk used, as of size_checked_at. |
| attributes.quota_bytesrequired | integer | Hard disk quota. Writes beyond it fail. |
| attributes.size_checked_atrequired | string (date-time) | null | |
| attributes.created_atrequired | string (date-time) |
Errors
- 401 No API key was sent, or it is wrong, expired or deleted.
- 403 The key is valid but may not do this: it lacks the permission or account scope, it is limited to other servers or IP addresses, or the account may not do it at all.
- 404 There is no such resource, or the key cannot see it. Features that are switched off answer 404 too.
- 409 The resource is busy or in a state that does not allow this right now.
- 502 The database server could not be reached or refused the request. Try again in a few minutes.
Delete a database
DELETE/databases/{database}
Account scope databases.write
Permanently deletes the database and its data, along with any copy kept from a move. It is only removed from the account once the database server has dropped it. Refused with 409 while the database is being moved.
Parameters
| Name | Type | Description |
|---|---|---|
| databaserequired | integer | The database's numeric id. |
Example
curl -X DELETE "https://sillydev.co.uk/panel/api/client/databases/{database}" \
-H "Authorization: Bearer $SILLYDEV_API_KEY" \
-H "Accept: application/json"Response 204Done. There is no response body.
Errors
- 401 No API key was sent, or it is wrong, expired or deleted.
- 403 The key is valid but may not do this: it lacks the permission or account scope, it is limited to other servers or IP addresses, or the account may not do it at all.
- 404 There is no such resource, or the key cannot see it. Features that are switched off answer 404 too.
- 409 The resource is busy or in a state that does not allow this right now.
- 502 The database server could not be reached or refused the request. Try again in a few minutes.