Create Table
curl --request POST \
--url https://api.sublay.io/v7/:projectId/db/tables \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"tableName": "<string>",
"columns": [
{}
],
"timestamps": true,
"paranoid": true
}
'import requests
url = "https://api.sublay.io/v7/:projectId/db/tables"
payload = {
"tableName": "<string>",
"columns": [{}],
"timestamps": True,
"paranoid": True
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({tableName: '<string>', columns: [{}], timestamps: true, paranoid: true})
};
fetch('https://api.sublay.io/v7/:projectId/db/tables', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.sublay.io/v7/:projectId/db/tables",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'tableName' => '<string>',
'columns' => [
[
]
],
'timestamps' => true,
'paranoid' => true
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.sublay.io/v7/:projectId/db/tables"
payload := strings.NewReader("{\n \"tableName\": \"<string>\",\n \"columns\": [\n {}\n ],\n \"timestamps\": true,\n \"paranoid\": true\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.sublay.io/v7/:projectId/db/tables")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"tableName\": \"<string>\",\n \"columns\": [\n {}\n ],\n \"timestamps\": true,\n \"paranoid\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.sublay.io/v7/:projectId/db/tables")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"tableName\": \"<string>\",\n \"columns\": [\n {}\n ],\n \"timestamps\": true,\n \"paranoid\": true\n}"
response = http.request(request)
puts response.read_body{
"table": "<string>"
}Custom Tables — Management
Create Table
Create a custom table in your project’s schema
Create Table
curl --request POST \
--url https://api.sublay.io/v7/:projectId/db/tables \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"tableName": "<string>",
"columns": [
{}
],
"timestamps": true,
"paranoid": true
}
'import requests
url = "https://api.sublay.io/v7/:projectId/db/tables"
payload = {
"tableName": "<string>",
"columns": [{}],
"timestamps": True,
"paranoid": True
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({tableName: '<string>', columns: [{}], timestamps: true, paranoid: true})
};
fetch('https://api.sublay.io/v7/:projectId/db/tables', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.sublay.io/v7/:projectId/db/tables",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'tableName' => '<string>',
'columns' => [
[
]
],
'timestamps' => true,
'paranoid' => true
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.sublay.io/v7/:projectId/db/tables"
payload := strings.NewReader("{\n \"tableName\": \"<string>\",\n \"columns\": [\n {}\n ],\n \"timestamps\": true,\n \"paranoid\": true\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.sublay.io/v7/:projectId/db/tables")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"tableName\": \"<string>\",\n \"columns\": [\n {}\n ],\n \"timestamps\": true,\n \"paranoid\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.sublay.io/v7/:projectId/db/tables")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"tableName\": \"<string>\",\n \"columns\": [\n {}\n ],\n \"timestamps\": true,\n \"paranoid\": true\n}"
response = http.request(request)
puts response.read_body{
"table": "<string>"
}Creates a new custom table.
Service or master key required. Table management is not reachable with an end-user token, which is why the JS SDK and the React hook are row-only.
Pass the logical name. The server prepends
custom_ exactly once, so orders is stored as custom_orders. A logical name that itself begins with custom_ is not special-cased — custom_x stores as custom_custom_x.Body Parameters
string
required
Logical table name, matching
^[a-zA-Z_][a-zA-Z0-9_]{0,62}$. The physical name is 7 characters longer and must still fit Postgres’s 63-character identifier limit, so an over-long name fails with database/name-too-long.object[]
Column definitions. Defaults to an empty array — a table can be created with only its managed columns and have columns added later.
boolean
Adds managed
createdAt and updatedAt columns. Defaults to true.boolean
Adds a managed
deletedAt column and makes deletes soft by default, so rows can be restored. Defaults to false. Requires timestamps to be enabled — paranoid: true with timestamps: false is rejected.{
"tableName": "orders",
"columns": [
{ "columnName": "status", "dataType": "text", "nullable": false },
{ "columnName": "total", "dataType": "decimal", "nullable": true }
],
"timestamps": true,
"paranoid": true
}
id, createdAt, updatedAt and deletedAt are managed columns — the platform owns them end to end. They are created for you according to the flags above and cannot be declared here.Response
Returns201 Created.
string
The logical name of the created table.
Error Responses
Invalid Body — 400
Invalid Body — 400
A malformed name, an unknown
dataType, or paranoid: true without timestamps.{ "error": "Bad Request", "code": "database/invalid-body" }
Name Too Long — 400
Name Too Long — 400
The physical
custom_-prefixed name exceeds Postgres’s 63-character identifier limit.{ "error": "Bad Request", "code": "database/name-too-long" }
Reserved Column — 400
Reserved Column — 400
A column definition used a managed column name.
{ "error": "Bad Request", "code": "database/reserved-column" }
Invalid Default Value — 400
Invalid Default Value — 400
{ "error": "Bad Request", "code": "database/invalid-default-value" }
Invalid Flags — 400
Invalid Flags — 400
{ "error": "Bad Request", "code": "database/invalid-flags" }
Elevated Auth Required — 403
Elevated Auth Required — 403
{
"error": "Service or master key required.",
"code": "auth/elevated-auth-required"
}
Table Already Exists — 409
Table Already Exists — 409
{ "error": "Conflict", "code": "database/table-already-exists" }
Table Limit Reached — 409
Table Limit Reached — 409
A project may hold at most 100 custom tables.
{ "error": "Conflict", "code": "database/table-limit-reached" }
Server Error — 500
Server Error — 500
{ "error": "Internal Server Error", "code": "database/server-error" }

