curl --request POST \
--url https://app.base44.com/api/apps/{app_id}/entities/{entity_name}/aggregate \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"query": {
"status": "paid"
},
"group_by": [
"status"
],
"date_bucket": {
"field": "created_date",
"unit": "month"
},
"count": true,
"sum": [
"amount"
],
"avg": [
"amount"
],
"min": [
"created_date"
],
"max": [
"amount"
],
"count_distinct": "customer_email",
"having": {
"count": {
"$gt": 1
}
},
"sort": "-sum_amount",
"limit": 100
}
'import requests
url = "https://app.base44.com/api/apps/{app_id}/entities/{entity_name}/aggregate"
payload = {
"query": { "status": "paid" },
"group_by": ["status"],
"date_bucket": {
"field": "created_date",
"unit": "month"
},
"count": True,
"sum": ["amount"],
"avg": ["amount"],
"min": ["created_date"],
"max": ["amount"],
"count_distinct": "customer_email",
"having": { "count": { "$gt": 1 } },
"sort": "-sum_amount",
"limit": 100
}
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({
query: {status: 'paid'},
group_by: ['status'],
date_bucket: {field: 'created_date', unit: 'month'},
count: true,
sum: ['amount'],
avg: ['amount'],
min: ['created_date'],
max: ['amount'],
count_distinct: 'customer_email',
having: {count: {$gt: 1}},
sort: '-sum_amount',
limit: 100
})
};
fetch('https://app.base44.com/api/apps/{app_id}/entities/{entity_name}/aggregate', 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://app.base44.com/api/apps/{app_id}/entities/{entity_name}/aggregate",
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([
'query' => [
'status' => 'paid'
],
'group_by' => [
'status'
],
'date_bucket' => [
'field' => 'created_date',
'unit' => 'month'
],
'count' => true,
'sum' => [
'amount'
],
'avg' => [
'amount'
],
'min' => [
'created_date'
],
'max' => [
'amount'
],
'count_distinct' => 'customer_email',
'having' => [
'count' => [
'$gt' => 1
]
],
'sort' => '-sum_amount',
'limit' => 100
]),
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://app.base44.com/api/apps/{app_id}/entities/{entity_name}/aggregate"
payload := strings.NewReader("{\n \"query\": {\n \"status\": \"paid\"\n },\n \"group_by\": [\n \"status\"\n ],\n \"date_bucket\": {\n \"field\": \"created_date\",\n \"unit\": \"month\"\n },\n \"count\": true,\n \"sum\": [\n \"amount\"\n ],\n \"avg\": [\n \"amount\"\n ],\n \"min\": [\n \"created_date\"\n ],\n \"max\": [\n \"amount\"\n ],\n \"count_distinct\": \"customer_email\",\n \"having\": {\n \"count\": {\n \"$gt\": 1\n }\n },\n \"sort\": \"-sum_amount\",\n \"limit\": 100\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://app.base44.com/api/apps/{app_id}/entities/{entity_name}/aggregate")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"query\": {\n \"status\": \"paid\"\n },\n \"group_by\": [\n \"status\"\n ],\n \"date_bucket\": {\n \"field\": \"created_date\",\n \"unit\": \"month\"\n },\n \"count\": true,\n \"sum\": [\n \"amount\"\n ],\n \"avg\": [\n \"amount\"\n ],\n \"min\": [\n \"created_date\"\n ],\n \"max\": [\n \"amount\"\n ],\n \"count_distinct\": \"customer_email\",\n \"having\": {\n \"count\": {\n \"$gt\": 1\n }\n },\n \"sort\": \"-sum_amount\",\n \"limit\": 100\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.base44.com/api/apps/{app_id}/entities/{entity_name}/aggregate")
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 \"query\": {\n \"status\": \"paid\"\n },\n \"group_by\": [\n \"status\"\n ],\n \"date_bucket\": {\n \"field\": \"created_date\",\n \"unit\": \"month\"\n },\n \"count\": true,\n \"sum\": [\n \"amount\"\n ],\n \"avg\": [\n \"amount\"\n ],\n \"min\": [\n \"created_date\"\n ],\n \"max\": [\n \"amount\"\n ],\n \"count_distinct\": \"customer_email\",\n \"having\": {\n \"count\": {\n \"$gt\": 1\n }\n },\n \"sort\": \"-sum_amount\",\n \"limit\": 100\n}"
response = http.request(request)
puts response.read_body{
"rows": [
{
"count": 128,
"status": "paid",
"sum_amount": 20480.5
}
],
"truncated": false
}Aggregate entity records
Computes counts, totals, averages, minimums, maximums and distinct counts over one of the app’s entities, grouped by the fields you choose, without returning the records.
Pick the records with query, group them with group_by, date_bucket, or both, and name the values to compute. For example, {"group_by": "status", "sum": "amount"} returns one row per status with its record count and the total of amount. Leave out group_by and date_bucket to get one row over every matching record. That row is returned even when no record matches, with 0 for counts and totals and null for averages, minimums and maximums, unless having rules it out.
Fields can be any field the entity’s schema declares, or one every record carries, such as created_date or created_by. sum and avg need fields the schema declares as numbers, and min, max and count_distinct need fields it declares as a string, number, integer or boolean. A stored value of another type is skipped. A date_bucket on created_date or updated_date returns the start of each period as a timestamp. On a date field from the schema it returns the matching part of the stored text, such as 2026-06 for a month, and a stored value that isn’t a date is grouped under null.
Deleted records are left out, and row-level security applies, so the values cover only the records the entity’s rls read rule lets your credential see. An aggregate reads every matching record and must finish within 30 seconds, with a response under 256 KB. Narrow query when it doesn’t. The User entity and entities with field-level read rules aren’t supported.
The camelCase spellings groupBy, dateBucket and countDistinct are accepted too.
curl --request POST \
--url https://app.base44.com/api/apps/{app_id}/entities/{entity_name}/aggregate \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"query": {
"status": "paid"
},
"group_by": [
"status"
],
"date_bucket": {
"field": "created_date",
"unit": "month"
},
"count": true,
"sum": [
"amount"
],
"avg": [
"amount"
],
"min": [
"created_date"
],
"max": [
"amount"
],
"count_distinct": "customer_email",
"having": {
"count": {
"$gt": 1
}
},
"sort": "-sum_amount",
"limit": 100
}
'import requests
url = "https://app.base44.com/api/apps/{app_id}/entities/{entity_name}/aggregate"
payload = {
"query": { "status": "paid" },
"group_by": ["status"],
"date_bucket": {
"field": "created_date",
"unit": "month"
},
"count": True,
"sum": ["amount"],
"avg": ["amount"],
"min": ["created_date"],
"max": ["amount"],
"count_distinct": "customer_email",
"having": { "count": { "$gt": 1 } },
"sort": "-sum_amount",
"limit": 100
}
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({
query: {status: 'paid'},
group_by: ['status'],
date_bucket: {field: 'created_date', unit: 'month'},
count: true,
sum: ['amount'],
avg: ['amount'],
min: ['created_date'],
max: ['amount'],
count_distinct: 'customer_email',
having: {count: {$gt: 1}},
sort: '-sum_amount',
limit: 100
})
};
fetch('https://app.base44.com/api/apps/{app_id}/entities/{entity_name}/aggregate', 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://app.base44.com/api/apps/{app_id}/entities/{entity_name}/aggregate",
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([
'query' => [
'status' => 'paid'
],
'group_by' => [
'status'
],
'date_bucket' => [
'field' => 'created_date',
'unit' => 'month'
],
'count' => true,
'sum' => [
'amount'
],
'avg' => [
'amount'
],
'min' => [
'created_date'
],
'max' => [
'amount'
],
'count_distinct' => 'customer_email',
'having' => [
'count' => [
'$gt' => 1
]
],
'sort' => '-sum_amount',
'limit' => 100
]),
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://app.base44.com/api/apps/{app_id}/entities/{entity_name}/aggregate"
payload := strings.NewReader("{\n \"query\": {\n \"status\": \"paid\"\n },\n \"group_by\": [\n \"status\"\n ],\n \"date_bucket\": {\n \"field\": \"created_date\",\n \"unit\": \"month\"\n },\n \"count\": true,\n \"sum\": [\n \"amount\"\n ],\n \"avg\": [\n \"amount\"\n ],\n \"min\": [\n \"created_date\"\n ],\n \"max\": [\n \"amount\"\n ],\n \"count_distinct\": \"customer_email\",\n \"having\": {\n \"count\": {\n \"$gt\": 1\n }\n },\n \"sort\": \"-sum_amount\",\n \"limit\": 100\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://app.base44.com/api/apps/{app_id}/entities/{entity_name}/aggregate")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"query\": {\n \"status\": \"paid\"\n },\n \"group_by\": [\n \"status\"\n ],\n \"date_bucket\": {\n \"field\": \"created_date\",\n \"unit\": \"month\"\n },\n \"count\": true,\n \"sum\": [\n \"amount\"\n ],\n \"avg\": [\n \"amount\"\n ],\n \"min\": [\n \"created_date\"\n ],\n \"max\": [\n \"amount\"\n ],\n \"count_distinct\": \"customer_email\",\n \"having\": {\n \"count\": {\n \"$gt\": 1\n }\n },\n \"sort\": \"-sum_amount\",\n \"limit\": 100\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.base44.com/api/apps/{app_id}/entities/{entity_name}/aggregate")
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 \"query\": {\n \"status\": \"paid\"\n },\n \"group_by\": [\n \"status\"\n ],\n \"date_bucket\": {\n \"field\": \"created_date\",\n \"unit\": \"month\"\n },\n \"count\": true,\n \"sum\": [\n \"amount\"\n ],\n \"avg\": [\n \"amount\"\n ],\n \"min\": [\n \"created_date\"\n ],\n \"max\": [\n \"amount\"\n ],\n \"count_distinct\": \"customer_email\",\n \"having\": {\n \"count\": {\n \"$gt\": 1\n }\n },\n \"sort\": \"-sum_amount\",\n \"limit\": 100\n}"
response = http.request(request)
puts response.read_body{
"rows": [
{
"count": 128,
"status": "paid",
"sum_amount": 20480.5
}
],
"truncated": false
}Authorizations
Personal access token, sent as Authorization: Bearer <token>.
Path Parameters
ID of the app that owns the entity.
Name of the entity, exactly as List entity schemas reports it. Don't pass User here. It doesn't fail, but it reads and writes a separate, disconnected set of records stored under that name, not the app's real user accounts, which are managed through their own endpoints.
Body
The wire body of POST /{entity}/aggregate. Keys are camelCase on the wire (the SDK's vocabulary).
Filter selecting the records to aggregate, in the same form as q on List entity records. Leave it out to aggregate every record you can read.
{ "status": "paid" }
Up to 4 fields to group by, as a list or a single field name. Each row holds one combination of their values. Leave it out, along with date_bucket, for one row over all matching records.
["status"]
Also groups by the period a date falls in, such as the day or month a record was created.
Show child attributes
Show child attributes
Whether each row includes count, the number of records in the group.
true
Number fields to total, as a list or a single field name. Each adds sum_<field> to the rows.
["amount"]
Number fields to average, as a list or a single field name. Each adds avg_<field> to the rows.
["amount"]
Fields whose smallest value to return, as a list or a single field name. Each adds min_<field> to the rows.
["created_date"]
Fields whose largest value to return, as a list or a single field name. Each adds max_<field> to the rows.
["amount"]
One field whose distinct values to count, leaving out null. Adds count_distinct_<field> to the rows.
"customer_email"
Filter on the computed values, applied after grouping. Name count or a computed field such as sum_amount, with a value to match or with $eq, $ne, $gt, $gte, $lt, $lte, $in or $nin.
{ "count": { "$gt": 1 } }
Group field or computed field to sort the rows by, prefixed with - for descending. Without it, the order of the rows isn't defined.
"-sum_amount"
Maximum number of rows to return, from 1 to 1000.
1 <= x <= 1000100
Response
The computed values.
The computed values, one row per group.
One row per group. A row holds each group field and the date_bucket field under its own name, then count and the sum_<field>, avg_<field>, min_<field>, max_<field> and count_distinct_<field> values you asked for. In those computed names, a dot in the field name becomes _. Date values, such as a date_bucket or a min_created_date, are UTC timestamps in ISO 8601 format with an offset.
[
{
"count": 128,
"status": "paid",
"sum_amount": 20480.5
}
]
true when more groups matched than limit, so some were left out.
false
Was this page helpful?