Download a site's database
Downloads every table and row of one site’s database as a file, from the sites gateway, which reads the database as the request is served. It serves any site of the company, a member’s included. The answer is NDJSON, the contract’s DumpV1: a first line with the format, its version and the schema ({"format":"fluid-site-db","version":1,"schema":{...}}), then one line for each row ({"table":"notes","row":{...}}). The same bytes import into any driver. It is sent as it is read, so it begins at once and no copy is held, however large the database is; the Content-Disposition header names the file site-database-<site id>.ndjson. It is not cached.
A failure before the first byte is a normal error answer (502, or 504 when the gateway did not begin in time). A failure after it cannot change the status, which is already 200, so the dump ends with one more line, {"error":"export_interrupted"}, which is neither a header nor a row and has no newline after it. A dump is whole only when the response ends cleanly and every line, the last included, is a header or a row and ends with a newline. A connection that is cut gives an HTTP error (a missing final chunk) or a last line without its newline. Download again.
Needs member_site_data.view, the permission to read what members wrote, because a dump holds every row of the site, whoever wrote it, application_themes.view, the permission of the site detail page, and a signed-in admin. An admin who edits themes but was never given member_site_data.view is refused with 403; a company grants it to the roles that moderate. A droplet installation token and an OAuth client token are refused with 403. It answers 404 for every caller that passes those checks until the sites gateway is released to the company, and for a site with no active database.
curl --request GET \
--url https://api.fluid.app/api/company/v2026-10/member-sites/{id}/database-export \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.fluid.app/api/company/v2026-10/member-sites/{id}/database-export"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.fluid.app/api/company/v2026-10/member-sites/{id}/database-export', 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/company/v2026-10/member-sites/{id}/database-export",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.fluid.app/api/company/v2026-10/member-sites/{id}/database-export"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.fluid.app/api/company/v2026-10/member-sites/{id}/database-export")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.fluid.app/api/company/v2026-10/member-sites/{id}/database-export")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body"{\"format\":\"fluid-site-db\",\"version\":1,\"schema\":{\"tables\":{}}}\n{\"table\":\"notes\",\"row\":{\"id\":\"1\",\"body\":\"first\"}}\n{\"table\":\"notes\",\"row\":{\"id\":\"2\",\"body\":\"second\"}}\n"{}{}{
"error": {
"message": "<string>",
"details": {}
},
"status": 123,
"meta": {
"request_uuid": "<string>",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"error": {
"message": "<string>",
"details": {}
},
"status": 123,
"meta": {
"request_uuid": "<string>",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"error": {
"message": "<string>",
"details": {}
},
"status": 123,
"meta": {
"request_uuid": "<string>",
"timestamp": "2023-11-07T05:31:56Z"
}
}Authorizations
A company admin credential for your company, or a droplet installation token with the website scope for reads, except on the share routes, which refuse a droplet token.
Path Parameters
The site's id.
Response
The database as a DumpV1 file, streamed.
NDJSON. The first line is the header, format, version and schema; each other line is a row, table and row. A last line {"error":"export_interrupted"} with no newline after it means the dump failed after it began and is not whole.
curl --request GET \
--url https://api.fluid.app/api/company/v2026-10/member-sites/{id}/database-export \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.fluid.app/api/company/v2026-10/member-sites/{id}/database-export"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.fluid.app/api/company/v2026-10/member-sites/{id}/database-export', 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/company/v2026-10/member-sites/{id}/database-export",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.fluid.app/api/company/v2026-10/member-sites/{id}/database-export"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.fluid.app/api/company/v2026-10/member-sites/{id}/database-export")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.fluid.app/api/company/v2026-10/member-sites/{id}/database-export")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body"{\"format\":\"fluid-site-db\",\"version\":1,\"schema\":{\"tables\":{}}}\n{\"table\":\"notes\",\"row\":{\"id\":\"1\",\"body\":\"first\"}}\n{\"table\":\"notes\",\"row\":{\"id\":\"2\",\"body\":\"second\"}}\n"{}{}{
"error": {
"message": "<string>",
"details": {}
},
"status": 123,
"meta": {
"request_uuid": "<string>",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"error": {
"message": "<string>",
"details": {}
},
"status": 123,
"meta": {
"request_uuid": "<string>",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"error": {
"message": "<string>",
"details": {}
},
"status": 123,
"meta": {
"request_uuid": "<string>",
"timestamp": "2023-11-07T05:31:56Z"
}
}