Documentation Index
Fetch the complete documentation index at: /llms.txt
Use this file to discover all available pages before exploring further.
curl --request POST \
--url https://api.chicago.global/v1/portfolioreport \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"portfolio_data": {},
"format": "pdf"
}
'import requests
url = "https://api.chicago.global/v1/portfolioreport"
payload = {
"portfolio_data": {},
"format": "pdf"
}
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({portfolio_data: {}, format: 'pdf'})
};
fetch('https://api.chicago.global/v1/portfolioreport', 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.chicago.global/v1/portfolioreport",
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([
'portfolio_data' => [
],
'format' => 'pdf'
]),
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.chicago.global/v1/portfolioreport"
payload := strings.NewReader("{\n \"portfolio_data\": {},\n \"format\": \"pdf\"\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.chicago.global/v1/portfolioreport")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"portfolio_data\": {},\n \"format\": \"pdf\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.chicago.global/v1/portfolioreport")
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 \"portfolio_data\": {},\n \"format\": \"pdf\"\n}"
response = http.request(request)
puts response.read_body{
"job_id": "port-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "pending",
"format": "pdf",
"check_url": "/v1/jobs/port-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"estimated_duration_seconds": 60,
"message": "Portfolio report generation started. Poll the check_url to get results."
}{
"detail": "<string>"
}Generate a PDF or HTML portfolio report from the output of the /v1/portfolio/analyze endpoint. This endpoint uses async job processing.
curl --request POST \
--url https://api.chicago.global/v1/portfolioreport \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"portfolio_data": {},
"format": "pdf"
}
'import requests
url = "https://api.chicago.global/v1/portfolioreport"
payload = {
"portfolio_data": {},
"format": "pdf"
}
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({portfolio_data: {}, format: 'pdf'})
};
fetch('https://api.chicago.global/v1/portfolioreport', 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.chicago.global/v1/portfolioreport",
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([
'portfolio_data' => [
],
'format' => 'pdf'
]),
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.chicago.global/v1/portfolioreport"
payload := strings.NewReader("{\n \"portfolio_data\": {},\n \"format\": \"pdf\"\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.chicago.global/v1/portfolioreport")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"portfolio_data\": {},\n \"format\": \"pdf\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.chicago.global/v1/portfolioreport")
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 \"portfolio_data\": {},\n \"format\": \"pdf\"\n}"
response = http.request(request)
puts response.read_body{
"job_id": "port-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "pending",
"format": "pdf",
"check_url": "/v1/jobs/port-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"estimated_duration_seconds": 60,
"message": "Portfolio report generation started. Poll the check_url to get results."
}{
"detail": "<string>"
}/v1/portfolio/analyze endpoint.
/v1/portfolio/analyze and wait for completion/v1/portfolioreport/v1/jobs/{job_id} until status is completed| Field | Type | Required | Default | Description |
|---|---|---|---|---|
portfolio_data | object | Yes | — | The complete result from the /v1/portfolio/analyze endpoint |
format | string | No | pdf | Output format: pdf, html, or both |
{
"portfolio_data": { ... },
"format": "pdf"
}
portfolio_data field must contain the full analysis result object — the result field from a completed /v1/portfolio/analyze job.{
"job_id": "port-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "pending",
"format": "pdf",
"check_url": "/v1/jobs/port-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"estimated_duration_seconds": 60,
"message": "Portfolio report generation started. Poll the check_url to get results."
}
GET /v1/jobs/{job_id} returns:
{
"job_id": "port-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "completed",
"result": {
"success": true,
"report_id": "f3a1b2c3",
"pdf_url": "https://your-supabase-url.supabase.co/storage/v1/object/public/portfolio-reports/pdf/2026/04/01/f3a1b2c3-report.pdf",
"html_url": null,
"expires_at": "2026-04-02T12:00:00"
}
}
| Field | Description |
|---|---|
success | Whether the report was generated successfully |
report_id | Unique identifier for this report |
pdf_url | Download URL for the PDF report (if format is pdf or both) |
html_url | Download URL for the HTML report (if format is html or both) |
expires_at | ISO 8601 timestamp when the report URLs expire (24 hours) |
| Page | Contents |
|---|---|
| Executive Summary | Key metrics, portfolio value vs benchmark chart, factor scores, investment thesis |
| Performance Analysis | Portfolio vs benchmark comparison table, period returns (YTD, 1W, 1M, 3M, 6M, 1Y, 3Y, 5Y) |
| Charts & Visuals | Growth of $100 chart, drawdown analysis, rolling Sharpe ratio |
| Allocations | Sector allocation pie chart, market allocation pie chart, top holdings bar chart |
| Returns | Monthly returns heatmap, annual returns comparison |
// Step 1: Run portfolio analysis
const analyzeResponse = await fetch('https://api.chicago.global/v1/portfolio/analyze', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
portfolio: [
{ date: '2024-01-01', symbol: 'AAPL.O', weight: 0.25 },
{ date: '2024-01-01', symbol: 'MSFT.O', weight: 0.25 },
{ date: '2024-01-01', symbol: '2330.TW', weight: 0.25 },
{ date: '2024-01-01', symbol: '7203.T', weight: 0.25 }
],
start_date: '2024-01-01',
end_date: '2024-12-31',
benchmark: 'ACWI'
})
});
const { job_id: analyzeJobId } = await analyzeResponse.json();
// Step 2: Wait for analysis to complete
let analysisResult;
while (true) {
const status = await fetch(
`https://api.chicago.global/v1/jobs/${analyzeJobId}`,
{ headers: { 'Authorization': `Bearer ${API_KEY}` } }
).then(r => r.json());
if (status.status === 'completed') {
analysisResult = status.result;
break;
} else if (status.status === 'failed') {
throw new Error(status.error);
}
await new Promise(r => setTimeout(r, 3000));
}
// Step 3: Generate report from analysis result
const reportResponse = await fetch('https://api.chicago.global/v1/portfolioreport', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
portfolio_data: analysisResult,
format: 'pdf'
})
});
const { job_id: reportJobId, check_url } = await reportResponse.json();
// Step 4: Wait for report and get download URL
const interval = setInterval(async () => {
const status = await fetch(
`https://api.chicago.global${check_url}`,
{ headers: { 'Authorization': `Bearer ${API_KEY}` } }
).then(r => r.json());
if (status.status === 'completed') {
clearInterval(interval);
console.log('PDF URL:', status.result.pdf_url);
console.log('Expires:', status.result.expires_at);
} else if (status.status === 'failed') {
clearInterval(interval);
console.error('Failed:', status.error);
}
}, 3000);
# Step 1: Start analysis
ANALYZE_JOB=$(curl -s -X POST "https://api.chicago.global/v1/portfolio/analyze" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"portfolio": [
{"date": "2024-01-01", "symbol": "AAPL.O", "weight": 0.5},
{"date": "2024-01-01", "symbol": "MSFT.O", "weight": 0.5}
],
"start_date": "2024-01-01",
"end_date": "2024-12-31"
}')
JOB_ID=$(echo $ANALYZE_JOB | jq -r '.job_id')
# Step 2: Poll until complete, then get result
RESULT=$(curl -s "https://api.chicago.global/v1/jobs/$JOB_ID" \
-H "Authorization: Bearer YOUR_API_KEY" | jq '.result')
# Step 3: Generate report
curl -X POST "https://api.chicago.global/v1/portfolioreport" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"portfolio_data\": $RESULT, \"format\": \"pdf\"}"
API key passed as Bearer token
Job created successfully. Poll the check_url for results.
Unique job identifier
Initial job status
pending Requested output format
URL to poll for job status
Estimated processing time in seconds
Human-readable status message