Run a schema statement on a site's database
Runs one schema statement through the backend’s sql.run operation. Rails does not read the statement: the backend accepts only the forms that cannot read or rewrite rows and refuses the rest with 422 invalid_statement before it contacts the database. A bearer only: the cookie mount answers 403 whether or not the request carries X-Fluid-Member-Site, so a page’s script cannot drop a table. Every response is private, no-store.
curl --request POST \
--url https://api.fluid.app/api/member/v2026-10/sites/{site_id}/database/sql \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"statement": "CREATE TABLE notes (id serial PRIMARY KEY, title text NOT NULL)"
}
'import requests
url = "https://api.fluid.app/api/member/v2026-10/sites/{site_id}/database/sql"
payload = { "statement": "CREATE TABLE notes (id serial PRIMARY KEY, title text NOT NULL)" }
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({statement: 'CREATE TABLE notes (id serial PRIMARY KEY, title text NOT NULL)'})
};
fetch('https://api.fluid.app/api/member/v2026-10/sites/{site_id}/database/sql', 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.fluid.app/api/member/v2026-10/sites/{site_id}/database/sql",
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([
'statement' => 'CREATE TABLE notes (id serial PRIMARY KEY, title text NOT NULL)'
]),
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.fluid.app/api/member/v2026-10/sites/{site_id}/database/sql"
payload := strings.NewReader("{\n \"statement\": \"CREATE TABLE notes (id serial PRIMARY KEY, title text NOT NULL)\"\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.fluid.app/api/member/v2026-10/sites/{site_id}/database/sql")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"statement\": \"CREATE TABLE notes (id serial PRIMARY KEY, title text NOT NULL)\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.fluid.app/api/member/v2026-10/sites/{site_id}/database/sql")
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 \"statement\": \"CREATE TABLE notes (id serial PRIMARY KEY, title text NOT NULL)\"\n}"
response = http.request(request)
puts response.read_body{
"status": 200,
"data": {
"command": "CREATE TABLE",
"row_count": 0,
"rows": [],
"truncated": false
},
"meta": {
"request_uuid": "0192f4c8-5b6c-7d74-a3e8-0f1a2b3c4d5e",
"timestamp": "2026-09-30T15:08:21Z"
}
}{
"status": 123,
"error": {
"message": "<string>",
"details": {}
},
"meta": {
"request_uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"status": 123,
"error": {
"message": "<string>",
"details": {}
},
"meta": {
"request_uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"status": 123,
"error": {
"message": "<string>",
"details": {}
},
"meta": {
"request_uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"status": 123,
"error": {
"message": "<string>",
"details": {}
},
"meta": {
"request_uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"status": 123,
"error": {
"message": "<string>",
"details": {}
},
"meta": {
"request_uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"status": 123,
"error": {
"message": "<string>",
"details": {}
},
"meta": {
"request_uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"status": 123,
"error": {
"message": "<string>",
"details": {}
},
"meta": {
"request_uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"status": 123,
"error": {
"message": "<string>",
"details": {}
},
"meta": {
"request_uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"status": 123,
"error": {
"message": "<string>",
"details": {}
},
"meta": {
"request_uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"status": 123,
"error": {
"message": "<string>",
"details": {}
},
"meta": {
"request_uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timestamp": "2023-11-07T05:31:56Z"
}
}Authorizations
A member credential in the Authorization: Bearer header: a member
session JWT, a portal JWT whose login is linked to a membership in
that company, an opaque member token, or a verified One Auth identity
access token. The credential alone identifies the member and company.
Member session JWTs, and portal JWTs the server minted read-only, are
refused with 403 on every write.
Path Parameters
Public id of one of the member's sites.
Body
One schema statement to run.
Exactly one statement of a schema form, such as CREATE TABLE, CREATE INDEX, ALTER TABLE with one action, DROP TABLE, DROP INDEX or COMMENT ON. Rails does not read it. The site's backend refuses, with 422, any statement that could read or copy rows (SELECT, INSERT, UPDATE, DELETE, CREATE TABLE ... AS, COPY, WITH, USING and the rest), a second command, a comment, dollar quoting, and a view, function, trigger, extension, role, schema or sequence. It checks for these words anywhere in the text, so a default or comment that holds one is refused too.
1 - 60000curl --request POST \
--url https://api.fluid.app/api/member/v2026-10/sites/{site_id}/database/sql \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"statement": "CREATE TABLE notes (id serial PRIMARY KEY, title text NOT NULL)"
}
'import requests
url = "https://api.fluid.app/api/member/v2026-10/sites/{site_id}/database/sql"
payload = { "statement": "CREATE TABLE notes (id serial PRIMARY KEY, title text NOT NULL)" }
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({statement: 'CREATE TABLE notes (id serial PRIMARY KEY, title text NOT NULL)'})
};
fetch('https://api.fluid.app/api/member/v2026-10/sites/{site_id}/database/sql', 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.fluid.app/api/member/v2026-10/sites/{site_id}/database/sql",
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([
'statement' => 'CREATE TABLE notes (id serial PRIMARY KEY, title text NOT NULL)'
]),
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.fluid.app/api/member/v2026-10/sites/{site_id}/database/sql"
payload := strings.NewReader("{\n \"statement\": \"CREATE TABLE notes (id serial PRIMARY KEY, title text NOT NULL)\"\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.fluid.app/api/member/v2026-10/sites/{site_id}/database/sql")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"statement\": \"CREATE TABLE notes (id serial PRIMARY KEY, title text NOT NULL)\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.fluid.app/api/member/v2026-10/sites/{site_id}/database/sql")
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 \"statement\": \"CREATE TABLE notes (id serial PRIMARY KEY, title text NOT NULL)\"\n}"
response = http.request(request)
puts response.read_body{
"status": 200,
"data": {
"command": "CREATE TABLE",
"row_count": 0,
"rows": [],
"truncated": false
},
"meta": {
"request_uuid": "0192f4c8-5b6c-7d74-a3e8-0f1a2b3c4d5e",
"timestamp": "2026-09-30T15:08:21Z"
}
}{
"status": 123,
"error": {
"message": "<string>",
"details": {}
},
"meta": {
"request_uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"status": 123,
"error": {
"message": "<string>",
"details": {}
},
"meta": {
"request_uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"status": 123,
"error": {
"message": "<string>",
"details": {}
},
"meta": {
"request_uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"status": 123,
"error": {
"message": "<string>",
"details": {}
},
"meta": {
"request_uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"status": 123,
"error": {
"message": "<string>",
"details": {}
},
"meta": {
"request_uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"status": 123,
"error": {
"message": "<string>",
"details": {}
},
"meta": {
"request_uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"status": 123,
"error": {
"message": "<string>",
"details": {}
},
"meta": {
"request_uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"status": 123,
"error": {
"message": "<string>",
"details": {}
},
"meta": {
"request_uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"status": 123,
"error": {
"message": "<string>",
"details": {}
},
"meta": {
"request_uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"status": 123,
"error": {
"message": "<string>",
"details": {}
},
"meta": {
"request_uuid": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"timestamp": "2023-11-07T05:31:56Z"
}
}