curl --request POST \
--url https://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_resolve \
--header 'Content-Type: application/json' \
--header 'apikey: <api-key>' \
--data '
{
"p_names": [
"<string>"
],
"p_cnpjs": null,
"p_quotas": null,
"p_quota_dates": null
}
'import requests
url = "https://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_resolve"
payload = {
"p_names": ["<string>"],
"p_cnpjs": None,
"p_quotas": None,
"p_quota_dates": None
}
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_names: ['<string>'], p_cnpjs: null, p_quotas: null, p_quota_dates: null})
};
fetch('https://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_resolve', 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_resolve",
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_names' => [
'<string>'
],
'p_cnpjs' => null,
'p_quotas' => null,
'p_quota_dates' => null
]),
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_resolve"
payload := strings.NewReader("{\n \"p_names\": [\n \"<string>\"\n ],\n \"p_cnpjs\": null,\n \"p_quotas\": null,\n \"p_quota_dates\": null\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_resolve")
.header("apikey", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"p_names\": [\n \"<string>\"\n ],\n \"p_cnpjs\": null,\n \"p_quotas\": null,\n \"p_quota_dates\": null\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_resolve")
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_names\": [\n \"<string>\"\n ],\n \"p_cnpjs\": null,\n \"p_quotas\": null,\n \"p_quota_dates\": null\n}"
response = http.request(request)
puts response.read_body[
{
"line_no": 123,
"input_name": "<string>",
"candidate_cnpj": "<string>",
"candidate_name": "<string>",
"matched_name": "<string>",
"matched_period": "2023-12-25",
"entity_type": "<string>",
"match_kind": "<string>",
"similarity": 123,
"rank": 123,
"quota_on_date": 123,
"quota_rel_diff": 123,
"ambiguous": true,
"reason": "<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_resolve
Statement lines to candidate funds. One row per line and candidate (up to 5), ranked: a CNPJ the line carries wins (match_kind cnpj); else a name that is exactly a ticker of SILO’s curated ETF registry (cvm_etf_registry) gives that ETF’s CNPJ (etf_ticker, v56: api.lookup returns no CNPJ for a ticker); else an exact match on any name the fund ever filed, case, accents and whitespace ignored (exact_current: the registry name or the newest CDA name; exact_history: a former name, matched_period = the last CDA month it was filed under); else trigram over the whole name history (CDA DENOM_SOCIAL since 2005 plus the registry), similarity = greatest(similarity, word_similarity), so an abbreviation scores high. With p_quotas and p_quota_dates the candidate’s cvm_fi_diario quota on that exact date is compared, and one within 0.5% ranks first (v72: a FIAGRO has none, so on a month-end date its cvm_fiagro_mensal quota for that month is compared, within half a cent of it plus 0.01%; and a fund whose name scores below the floor only because the line abbreviates its type, FIRF or CrPr, is added as a name hint, scored 0.5 at most, ranked behind the candidates that scored on their own unless its quota matches and theirs does not, and ambiguous unless its quota matches): that is how the XP Bancos master and FIC (same words, quotas 1.952607 and 1.542011 on 2026-09-30) are told apart. ambiguous is TRUE on every row of a line whose top two candidates score within 0.05 and the quota does not separate them: SILO never picks silently, the caller decides. Arrays are parallel, one entry per line. More than 200 lines RAISES 22023; the result is at most one 1000-row page.
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.
curl --request POST \
--url https://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_resolve \
--header 'Content-Type: application/json' \
--header 'apikey: <api-key>' \
--data '
{
"p_names": [
"<string>"
],
"p_cnpjs": null,
"p_quotas": null,
"p_quota_dates": null
}
'import requests
url = "https://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_resolve"
payload = {
"p_names": ["<string>"],
"p_cnpjs": None,
"p_quotas": None,
"p_quota_dates": None
}
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_names: ['<string>'], p_cnpjs: null, p_quotas: null, p_quota_dates: null})
};
fetch('https://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_resolve', 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_resolve",
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_names' => [
'<string>'
],
'p_cnpjs' => null,
'p_quotas' => null,
'p_quota_dates' => null
]),
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_resolve"
payload := strings.NewReader("{\n \"p_names\": [\n \"<string>\"\n ],\n \"p_cnpjs\": null,\n \"p_quotas\": null,\n \"p_quota_dates\": null\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_resolve")
.header("apikey", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"p_names\": [\n \"<string>\"\n ],\n \"p_cnpjs\": null,\n \"p_quotas\": null,\n \"p_quota_dates\": null\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_resolve")
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_names\": [\n \"<string>\"\n ],\n \"p_cnpjs\": null,\n \"p_quotas\": null,\n \"p_quota_dates\": null\n}"
response = http.request(request)
puts response.read_body[
{
"line_no": 123,
"input_name": "<string>",
"candidate_cnpj": "<string>",
"candidate_name": "<string>",
"matched_name": "<string>",
"matched_period": "2023-12-25",
"entity_type": "<string>",
"match_kind": "<string>",
"similarity": 123,
"rank": 123,
"quota_on_date": 123,
"quota_rel_diff": 123,
"ambiguous": true,
"reason": "<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
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?