portfolio_fee_peers
curl --request POST \
--url https://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_fee_peers \
--header 'Content-Type: application/json' \
--header 'apikey: <api-key>' \
--data '
{
"p_cnpjs": [
"<string>"
],
"p_as_of": "2023-12-25"
}
'import requests
url = "https://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_fee_peers"
payload = {
"p_cnpjs": ["<string>"],
"p_as_of": "2023-12-25"
}
headers = {
"apikey": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {apikey: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({p_cnpjs: ['<string>'], p_as_of: '2023-12-25'})
};
fetch('https://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_fee_peers', 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://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_fee_peers",
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([
'p_cnpjs' => [
'<string>'
],
'p_as_of' => '2023-12-25'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"apikey: <api-key>"
],
]);
$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://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_fee_peers"
payload := strings.NewReader("{\n \"p_cnpjs\": [\n \"<string>\"\n ],\n \"p_as_of\": \"2023-12-25\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("apikey", "<api-key>")
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://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_fee_peers")
.header("apikey", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"p_cnpjs\": [\n \"<string>\"\n ],\n \"p_as_of\": \"2023-12-25\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_fee_peers")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["apikey"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"p_cnpjs\": [\n \"<string>\"\n ],\n \"p_as_of\": \"2023-12-25\"\n}"
response = http.request(request)
puts response.read_body[
{
"cnpj": "<string>",
"classe_anbima": "<string>",
"fundo_cotas": "<string>",
"tp_fundo_classe": "<string>",
"taxa_adm": 123,
"fee_as_of": "2023-12-25",
"comparison_as_of": "2023-12-25",
"activity_from": "2023-12-25",
"activity_to": "2023-12-25",
"n_peers": 123,
"n_excluded": 123,
"peer_fee_oldest": "2023-12-25",
"peer_fee_newest": "2023-12-25",
"p25_pct_year": 123,
"median_pct_year": 123,
"p75_pct_year": 123,
"percentile_pct": 123,
"difference_pp": 123,
"status": "<string>",
"reason_code": "<string>",
"n_fund_peers": 123,
"n_etf_peers": 123,
"n_etf_excluded": 123,
"etf_peer_tickers": [
"<string>"
],
"etf_peer_fee_oldest": "2023-12-25",
"etf_peer_fee_newest": "2023-12-25",
"etf_peer_fee_source": "<string>"
}
]{
"code": "22023",
"message": "<string>",
"details": "<string>",
"hint": "<string>"
}{
"code": "22023",
"message": "<string>",
"details": "<string>",
"hint": "<string>"
}{
"code": "22023",
"message": "<string>",
"details": "<string>",
"hint": "<string>"
}Portfolio
portfolio_fee_peers
Administration fee comparison (catalog v63; ETF peers v66), one row per distinct input CNPJ. Latest CVM Extrato only, not a historical backtest: p_as_of (default today) dates the comparison, excludes future documents and fees older than 36 months. Fund peers have a FI quota in the three reference months ending in p_as_of month, the SAME filed ANBIMA class, FUNDO_COTAS S/N and TP_FUNDO_CLASSE FI/CLASSES - FIF. ETF peers (v66, #609): CVM files no ANBIMA class for an ETF, so an active ETF (cvm_etf_registry.is_active) joins a class only when its underlying_index is mapped to that class in public.portfolio_class_index (the owner-reviewed src/portfolio/rules/equivalents/class_index.yaml, never inferred from a name); it is a peer of every FUNDO_COTAS and scope cell of the class, once per CNPJ. Its fee is the third-party etfsbrasil.com.br value (etf_market_snapshot.taxa_adm_pct, the newest snapshot with a fee dated no later than p_as_of, as portfolio_fees serves etf_site_taxa_adm), never a CVM-disclosed fee; the same 0 < fee <= 5 and 36-month rules apply. n_peers = n_fund_peers + n_etf_peers; at least 30 usable FUND fees (the target included when eligible), and ETFs never make a group qualify (owner, #609 Q18): they join a group that already has 30 funds; no broader fallback. n_excluded counts unusable fund fees, n_etf_excluded mapped ETFs with no usable fee; peer_fee_oldest/newest date the usable fund documents, etf_peer_fee_oldest/newest the ETF snapshots; etf_peer_tickers and etf_peer_fee_source name the ETFs and say their fee is third-party. p25/median/p75 are annual administration fees over the combined group, percentile is midrank (half weight for ties), difference_pp is target minus median. No performance fee, expense ratio, alternative or saving estimate. not_compared carries a reason_code and NULL comparison statistics. Source values are never rescaled. 1 to 200 CNPJs per call, punctuation stripped and padded to 14 digits; invalid input or more than 200 raises 22023; one page, never trimmed.
**Row cap.** A window producing more than 1000 rows raises SQLSTATE `22023` naming this function. Nothing is trimmed to fit — PostgREST would silently cut the response at 1000 and a cut-short series is indistinguishable from one that simply ends. This function does not page — narrow the window instead.
POST
/
rpc
/
portfolio_fee_peers
portfolio_fee_peers
curl --request POST \
--url https://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_fee_peers \
--header 'Content-Type: application/json' \
--header 'apikey: <api-key>' \
--data '
{
"p_cnpjs": [
"<string>"
],
"p_as_of": "2023-12-25"
}
'import requests
url = "https://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_fee_peers"
payload = {
"p_cnpjs": ["<string>"],
"p_as_of": "2023-12-25"
}
headers = {
"apikey": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {apikey: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({p_cnpjs: ['<string>'], p_as_of: '2023-12-25'})
};
fetch('https://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_fee_peers', 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://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_fee_peers",
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([
'p_cnpjs' => [
'<string>'
],
'p_as_of' => '2023-12-25'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"apikey: <api-key>"
],
]);
$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://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_fee_peers"
payload := strings.NewReader("{\n \"p_cnpjs\": [\n \"<string>\"\n ],\n \"p_as_of\": \"2023-12-25\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("apikey", "<api-key>")
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://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_fee_peers")
.header("apikey", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"p_cnpjs\": [\n \"<string>\"\n ],\n \"p_as_of\": \"2023-12-25\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_fee_peers")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["apikey"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"p_cnpjs\": [\n \"<string>\"\n ],\n \"p_as_of\": \"2023-12-25\"\n}"
response = http.request(request)
puts response.read_body[
{
"cnpj": "<string>",
"classe_anbima": "<string>",
"fundo_cotas": "<string>",
"tp_fundo_classe": "<string>",
"taxa_adm": 123,
"fee_as_of": "2023-12-25",
"comparison_as_of": "2023-12-25",
"activity_from": "2023-12-25",
"activity_to": "2023-12-25",
"n_peers": 123,
"n_excluded": 123,
"peer_fee_oldest": "2023-12-25",
"peer_fee_newest": "2023-12-25",
"p25_pct_year": 123,
"median_pct_year": 123,
"p75_pct_year": 123,
"percentile_pct": 123,
"difference_pp": 123,
"status": "<string>",
"reason_code": "<string>",
"n_fund_peers": 123,
"n_etf_peers": 123,
"n_etf_excluded": 123,
"etf_peer_tickers": [
"<string>"
],
"etf_peer_fee_oldest": "2023-12-25",
"etf_peer_fee_newest": "2023-12-25",
"etf_peer_fee_source": "<string>"
}
]{
"code": "22023",
"message": "<string>",
"details": "<string>",
"hint": "<string>"
}{
"code": "22023",
"message": "<string>",
"details": "<string>",
"hint": "<string>"
}{
"code": "22023",
"message": "<string>",
"details": "<string>",
"hint": "<string>"
}Authorizations
The publishable key (sb_publishable_…), on every request. It is NOT a JWT — sending it as Authorization: Bearer is rejected as an invalid JWT. It identifies the project, not you, and maps to the Postgres anon role.
Body
application/json
Response
The result set, oldest first. An unknown id is an empty array, not a 404 and never a guessed value.
Was this page helpful?