Overview
The portfolio API assembles complete portfolio data from analyzed projects, including project details, skills, summaries, and resume items. It supports customization through representation preferences.
Generate Portfolio
Generate complete portfolio content for a portfolio ID.
curl -X POST http://127.0.0.1:8000/portfolio/generate \
-H "Content-Type: application/json" \
-d '{
"portfolio_id": "550e8400-e29b-41d4-a716-446655440000"
}'
Request Body:
Portfolio UUID returned by ZIP uploads (min 1 character)
Response:
{
"success" : true ,
"portfolio_id" : "550e8400-e29b-41d4-a716-446655440000" ,
"consent_level" : "local" ,
"generated_at" : "2024-03-05T15:30:00" ,
"preferences" : {
"showcase_project_ids" : [ 1 , 2 , 3 ],
"project_order" : [ 3 , 1 , 2 ],
"skills_to_highlight" : [ 5 , 12 , 8 ],
"hidden_skills" : [],
"chronology_overrides" : [],
"comparison_attributes" : [ "languages" , "frameworks" ],
"custom_rankings" : []
},
"projects" : [
{
"id" : 3 ,
"project_name" : "api-server" ,
"project_path" : "/path/to/api-server" ,
"languages" : [ "Python" ],
"frameworks" : [ "FastAPI" ],
"first_commit" : "2023-06-15T10:00:00" ,
"last_commit" : "2024-03-05T14:30:00" ,
"ranking_score" : 92.5 ,
"health_score" : 88.0 ,
"thumbnail_url" : "/uploads/thumbnails/abc123.png" ,
"user_role" : "Lead Developer" ,
"evidence" : [
{
"id" : 1 ,
"type" : "metric" ,
"content" : "Reduced API response time by 40%" ,
"source" : "Performance testing" ,
"date" : "2024-02-15"
}
]
}
],
"resume_items" : [
{
"id" : 1 ,
"title" : "Built REST API with FastAPI" ,
"content" : "Developed a scalable REST API..." ,
"category" : "Backend Development" ,
"project_name" : "api-server" ,
"created_at" : "2024-03-05T10:00:00"
}
],
"summaries" : [
{
"id" : 1 ,
"repo_path" : "/path/to/api-server" ,
"user_email" : "[email protected] " ,
"summary_text" : "Led development of a FastAPI backend..." ,
"generated_at" : "2024-03-05T12:00:00"
}
],
"skills_chronology" : [
{
"date" : "2023-06-15T10:00:00" ,
"skill" : "Python" ,
"project" : "api-server" ,
"proficiency" : 0.9 ,
"category" : "Programming Languages"
}
],
"errors" : []
}
true when at least one project is included in the portfolio
Consent level used during analysis
Timestamp when the portfolio was generated
Representation preferences applied to the portfolio Show RepresentationPreferences properties
RepoStat IDs to showcase (filters to these projects only)
Manual project ordering as a list of RepoStat IDs
Skill IDs to highlight in portfolio output
Skill IDs to hide from portfolio output
Manual overrides for project chronology dates
Allowed attributes for project comparison: languages, frameworks, skills, total_commits, ranking_score, health_score, primary_language, role
Manual custom rankings for projects
Projects included in the portfolio Show PortfolioProjectItem properties
User contribution score (0-100)
Evidence items for this project
Resume items from all portfolio projects
AI-generated summaries for projects
Chronological skill progression
Non-critical errors during generation (e.g., preference validation warnings)
Errors:
422 - portfolio_id is empty
404 - Portfolio not found
400 - Portfolio has no analyzed ZIPs yet
Before generating a portfolio, you must upload ZIPs and run analysis with POST /analyze/{zip_id}.
Get Portfolio
Retrieve portfolio display data by ID.
GET /portfolio/{portfolio_id}
curl http://127.0.0.1:8000/portfolio/550e8400-e29b-41d4-a716-446655440000
Path Parameters:
Response:
Same structure as POST /portfolio/generate response.
Edit Portfolio Preferences
Customize portfolio content through representation preferences.
POST /portfolio/{portfolio_id}/edit
curl -X POST http://127.0.0.1:8000/portfolio/550e8400-e29b-41d4-a716-446655440000/edit \
-H "Content-Type: application/json" \
-d '{
"showcase_project_ids": [1, 3, 5],
"project_order": [5, 1, 3],
"skills_to_highlight": [2, 7, 12],
"comparison_attributes": ["languages", "frameworks", "ranking_score"]
}'
Path Parameters:
Request Body:
RepoStat IDs to showcase. If provided, filters portfolio to only these projects. Use integer repo_stat IDs
Manual project ordering as a list of RepoStat IDs. Projects not in this list appear after ordered projects
Skill IDs to highlight in portfolio output
Skill IDs to hide from portfolio output
Manual overrides for project chronology. Use date-only values (YYYY-MM-DD). Partial overrides allowed Example: [{"project_id": 1, "first_commit": "2023-01-15", "last_commit": "2024-03-01"}]
Allowed attributes for project comparison. Valid values: languages, frameworks, skills, total_commits, ranking_score, health_score, primary_language, role
Manual custom rankings for projects. Each item has project_id and rank (≥1) Example: [{"project_id": 3, "rank": 1}, {"project_id": 1, "rank": 2}]
Response:
{
"success" : true ,
"portfolio_id" : "550e8400-e29b-41d4-a716-446655440000" ,
"updated_at" : "2024-03-05T16:00:00" ,
"preferences" : {
"showcase_project_ids" : [ 1 , 3 , 5 ],
"project_order" : [ 5 , 1 , 3 ],
"skills_to_highlight" : [ 2 , 7 , 12 ],
"hidden_skills" : [],
"chronology_overrides" : [],
"comparison_attributes" : [ "languages" , "frameworks" , "ranking_score" ],
"custom_rankings" : []
}
}
Get Portfolio Preferences
Retrieve current representation preferences.
GET /views/{portfolio_id}/prefs
curl http://127.0.0.1:8000/views/550e8400-e29b-41d4-a716-446655440000/prefs
Response:
{
"showcase_project_ids" : [ 1 , 3 , 5 ],
"project_order" : [ 5 , 1 , 3 ],
"skills_to_highlight" : [ 2 , 7 , 12 ],
"hidden_skills" : [],
"chronology_overrides" : [],
"comparison_attributes" : [ "languages" , "frameworks" ],
"custom_rankings" : []
}
If no preferences have been set, returns defaults (all empty arrays).
Update Portfolio Preferences
Update representation preferences (alternative to POST /portfolio//edit).
PUT /views/{portfolio_id}/prefs
curl -X PUT http://127.0.0.1:8000/views/550e8400-e29b-41d4-a716-446655440000/prefs \
-H "Content-Type: application/json" \
-d '{
"showcase_project_ids": [2, 4],
"project_order": [4, 2]
}'
Response:
Same as GET /views//prefs response.
Example: Complete Portfolio Workflow
import requests
BASE_URL = 'http://127.0.0.1:8000'
# Step 1: Upload and analyze
with open ( 'projects.zip' , 'rb' ) as f:
upload = requests.post( f ' { BASE_URL } /zip/upload' , files = { 'file' : f}).json()
portfolio_id = upload[ 'portfolio_id' ]
zip_id = upload[ 'zip_id' ]
analysis = requests.post( f ' { BASE_URL } /analyze/ { zip_id } ' ).json()
print ( f "Analyzed { analysis[ 'repos_found' ] } repositories" )
# Step 2: Generate initial portfolio
portfolio = requests.post(
f ' { BASE_URL } /portfolio/generate' ,
json = { 'portfolio_id' : portfolio_id}
).json()
print ( f "Portfolio has { len (portfolio[ 'projects' ]) } projects" )
# Step 3: Get project IDs for customization
project_ids = [p[ 'id' ] for p in portfolio[ 'projects' ]]
top_3 = project_ids[: 3 ]
# Step 4: Customize portfolio
prefs = requests.post(
f ' { BASE_URL } /portfolio/ { portfolio_id } /edit' ,
json = {
'showcase_project_ids' : top_3,
'project_order' : top_3,
'comparison_attributes' : [ 'languages' , 'frameworks' , 'ranking_score' ]
}
).json()
print ( f "Updated preferences for { len (prefs[ 'preferences' ][ 'showcase_project_ids' ]) } projects" )
# Step 5: Regenerate with preferences
final = requests.post(
f ' { BASE_URL } /portfolio/generate' ,
json = { 'portfolio_id' : portfolio_id}
).json()
print ( f "Final portfolio: { len (final[ 'projects' ]) } projects, { len (final[ 'resume_items' ]) } resume items" )