API and MCP
Portfolios
Named sets of subjects scored together: their scores, the ranked fixes that would move them, the subjects themselves, criticality ratings and accepted risks
List portfolios
GET /api/v1/project/{projectId}/v1/portfolio
Credentials: API token or dashboard sign-in.
Every portfolio in this project. A portfolio is a named set of subjects scored together; each entry carries its portfolio_id, name, members (each with member_type and value) and whether it is the built-in portfolio that holds every subject (is_implicit). Requires project:portfolio:view.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
projectId required | path | string (uuid) | The project's id. |
Responses
| Status | Description | Body |
|---|---|---|
200 | The project's portfolios, under portfolios. | PortfolioList |
401 | The token is missing, expired, revoked or of the wrong kind. | Error |
403 | The token is valid but not allowed to do this. | Error |
404 | Portfolios are not set up for this project yet. | Error |
500 | A fault on our side. | Error |
503 | The project's data is temporarily unreachable; code says why. | Error |
Example
curl -X GET "https://api.spicelabs.io/api/v1/project/<projectId>/v1/portfolio" \
-H "Authorization: Bearer $SPICE_API_TOKEN" Create a portfolio
POST /api/v1/project/{projectId}/v1/portfolio
Credentials: API token or dashboard sign-in.
Creates a portfolio with a name and, optionally, its first members. Scoring begins immediately; until it finishes, the portfolio's state and rank answer 503. Requires project:portfolio:view and project:edit.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
projectId required | path | string (uuid) | The project's id. |
Request body
application/json (required)
Responses
| Status | Description | Body |
|---|---|---|
201 | The new portfolio. | PortfolioResponse |
400 | name is missing or blank, or a member is invalid. | Error |
401 | The token is missing, expired, revoked or of the wrong kind. | Error |
403 | The token is valid but not allowed to do this. | Error |
404 | Portfolios are not set up for this project yet. | Error |
500 | A fault on our side. | Error |
503 | The project's data is temporarily unreachable; code says why. | Error |
Example
curl -X POST "https://api.spicelabs.io/api/v1/project/<projectId>/v1/portfolio" \
-H "Authorization: Bearer $SPICE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '<JSON body>' Get a portfolio
GET /api/v1/project/{projectId}/v1/portfolio/{portfolioId}
Credentials: API token or dashboard sign-in.
One portfolio by id: its name, members and settings. Requires project:portfolio:view.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
projectId required | path | string (uuid) | The project's id. |
portfolioId required | path | string (uuid) | The portfolio ID |
Responses
| Status | Description | Body |
|---|---|---|
200 | The portfolio. | PortfolioResponse |
401 | The token is missing, expired, revoked or of the wrong kind. | Error |
403 | The token is valid but not allowed to do this. | Error |
404 | No portfolio with this id exists in this project, or it has been deleted. | Error |
500 | A fault on our side. | Error |
503 | The project's data is temporarily unreachable; code says why. | Error |
Example
curl -X GET "https://api.spicelabs.io/api/v1/project/<projectId>/v1/portfolio/<portfolioId>" \
-H "Authorization: Bearer $SPICE_API_TOKEN" Update a portfolio
PUT /api/v1/project/{projectId}/v1/portfolio/{portfolioId}
Credentials: API token or dashboard sign-in.
Renames a portfolio and/or replaces its members. name sets the name; members replaces the whole member list, each {"type": "subject" | "package", "value": ...}. A changed membership rescores the portfolio. The built-in portfolio (is_implicit) cannot be edited. Requires project:portfolio:view and project:edit.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
projectId required | path | string (uuid) | The project's id. |
portfolioId required | path | string (uuid) | The portfolio ID |
Request body
application/json (required)
Responses
| Status | Description | Body |
|---|---|---|
200 | The updated portfolio. | PortfolioResponse |
400 | A member is invalid, or this is the built-in portfolio, which cannot be edited. | Error |
401 | The token is missing, expired, revoked or of the wrong kind. | Error |
403 | The token is valid but not allowed to do this. | Error |
404 | No portfolio with this id exists in this project, or it has been deleted. | Error |
500 | A fault on our side. | Error |
503 | The project's data is temporarily unreachable; code says why. | Error |
Example
curl -X PUT "https://api.spicelabs.io/api/v1/project/<projectId>/v1/portfolio/<portfolioId>" \
-H "Authorization: Bearer $SPICE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '<JSON body>' Delete a portfolio
DELETE /api/v1/project/{projectId}/v1/portfolio/{portfolioId}
What it changes: Its scores and history stop being served. The subjects themselves are untouched.
Credentials: API token or dashboard sign-in.
Deletes a portfolio. It leaves the list and its reads answer 404; its subjects and their criticality ratings are untouched. The built-in portfolio (is_implicit) cannot be deleted. Requires project:portfolio:view and project:edit.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
projectId required | path | string (uuid) | The project's id. |
portfolioId required | path | string (uuid) | The portfolio ID |
Responses
| Status | Description | Body |
|---|---|---|
204 | The portfolio is deleted. | |
400 | This is the built-in portfolio, which cannot be deleted. | Error |
401 | The token is missing, expired, revoked or of the wrong kind. | Error |
403 | The token is valid but not allowed to do this. | Error |
404 | No portfolio with this id exists in this project, or it was already deleted. | Error |
500 | A fault on our side. | Error |
503 | The project's data is temporarily unreachable; code says why. | Error |
Example
curl -X DELETE "https://api.spicelabs.io/api/v1/project/<projectId>/v1/portfolio/<portfolioId>" \
-H "Authorization: Bearer $SPICE_API_TOKEN" Get portfolio history
GET /api/v1/project/{projectId}/v1/portfolio/{portfolioId}/history
Credentials: API token or dashboard sign-in.
The portfolio's scores over time: one row per score movement, each with its axis, score, band, what caused the change and when. The axis query parameter limits the rows to one of pqc, vuln or agility. Requires project:portfolio:view.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
projectId required | path | string (uuid) | The project's id. |
portfolioId required | path | string (uuid) | The portfolio ID |
axis | query | string | Only this score axis: pqc, vuln or agility (default: every axis) |
Responses
| Status | Description | Body |
|---|---|---|
200 | The score history, under rows. | ScoreHistory |
400 | axis is not pqc, vuln or agility. | Error |
401 | The token is missing, expired, revoked or of the wrong kind. | Error |
403 | The token is valid but not allowed to do this. | Error |
404 | No portfolio with this id exists in this project, or it has been deleted. | Error |
500 | A fault on our side. | Error |
503 | The project's data is temporarily unreachable; code says why. | Error |
Example
curl -X GET "https://api.spicelabs.io/api/v1/project/<projectId>/v1/portfolio/<portfolioId>/history" \
-H "Authorization: Bearer $SPICE_API_TOKEN" List portfolio members
GET /api/v1/project/{projectId}/v1/portfolio/{portfolioId}/member
Credentials: API token or dashboard sign-in.
The members of a portfolio, each a subject or a package. The built-in portfolio lists every subject in the project. Requires project:portfolio:view.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
projectId required | path | string (uuid) | The project's id. |
portfolioId required | path | string (uuid) | The portfolio ID |
Responses
| Status | Description | Body |
|---|---|---|
200 | The members under members, each with member_type (subject or package) and value. | ModuleMemberList |
401 | The token is missing, expired, revoked or of the wrong kind. | Error |
403 | The token is valid but not allowed to do this. | Error |
404 | No portfolio with this id exists in this project, or it has been deleted. | Error |
500 | A fault on our side. | Error |
503 | The project's data is temporarily unreachable; code says why. | Error |
Example
curl -X GET "https://api.spicelabs.io/api/v1/project/<projectId>/v1/portfolio/<portfolioId>/member" \
-H "Authorization: Bearer $SPICE_API_TOKEN" Add a member to a portfolio
POST /api/v1/project/{projectId}/v1/portfolio/{portfolioId}/member
Credentials: API token or dashboard sign-in.
Adds one member, {"type": "subject" | "package", "value": ...}; a plain string is a subject. Adding a member that is already present changes nothing. The portfolio is rescored. The built-in portfolio (is_implicit) cannot be changed. Requires project:portfolio:view and project:edit.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
projectId required | path | string (uuid) | The project's id. |
portfolioId required | path | string (uuid) | The portfolio ID |
Request body
application/json (required)
Responses
| Status | Description | Body |
|---|---|---|
200 | The members after the addition, under members. | ModuleMemberList |
400 | The member is invalid, or this is the built-in portfolio, which cannot be changed. | Error |
401 | The token is missing, expired, revoked or of the wrong kind. | Error |
403 | The token is valid but not allowed to do this. | Error |
404 | No portfolio with this id exists in this project, or it has been deleted. | Error |
500 | A fault on our side. | Error |
503 | The project's data is temporarily unreachable; code says why. | Error |
Example
curl -X POST "https://api.spicelabs.io/api/v1/project/<projectId>/v1/portfolio/<portfolioId>/member" \
-H "Authorization: Bearer $SPICE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '<JSON body>' Remove a member from a portfolio
DELETE /api/v1/project/{projectId}/v1/portfolio/{portfolioId}/member/{value}
What it changes: The portfolio's scores are worked out again without this member.
Credentials: API token or dashboard sign-in.
Removes one member, named by its value in the path, with its kind in the type query parameter: subject (the default) or package. The portfolio is rescored. The built-in portfolio (is_implicit) cannot be changed. Requires project:portfolio:view and project:edit.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
projectId required | path | string (uuid) | The project's id. |
portfolioId required | path | string (uuid) | The portfolio ID |
value required | path | string | The member value, URL-encoded: a subject name, or a package URL without a version |
type | query | string | subject (default) or package |
Responses
| Status | Description | Body |
|---|---|---|
200 | The members after the removal, under members. | ModuleMemberList |
400 | type is neither subject nor package, or this is the built-in portfolio, which cannot be changed. | Error |
401 | The token is missing, expired, revoked or of the wrong kind. | Error |
403 | The token is valid but not allowed to do this. | Error |
404 | No portfolio with this id exists in this project, or it has no such member. | Error |
500 | A fault on our side. | Error |
503 | The project's data is temporarily unreachable; code says why. | Error |
Example
curl -X DELETE "https://api.spicelabs.io/api/v1/project/<projectId>/v1/portfolio/<portfolioId>/member/<value>" \
-H "Authorization: Bearer $SPICE_API_TOKEN" Get portfolio rank
GET /api/v1/project/{projectId}/v1/portfolio/{portfolioId}/rank
Credentials: API token or dashboard sign-in.
The ranked list of fixes for a portfolio, best first, one page at a time. offset (default 0) and limit (default 50) query parameters choose the page; rows keep their overall rank number. Requires project:portfolio:view.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
projectId required | path | string (uuid) | The project's id. |
portfolioId required | path | string (uuid) | The portfolio ID |
offset | query | integer | Index in the whole list of the first fix to return (default 0) |
limit | query | integer | Page size, 1 to 10000 (default 1000) |
summary | query | boolean | Smaller rows: no items, and at most the 10 most important findings and 10 most important occurrences per row; reach still counts every subject (default false) |
Responses
| Status | Description | Body |
|---|---|---|
200 | A page of ranked fixes under rows, with total, offset and limit. | RankPage |
401 | The token is missing, expired, revoked or of the wrong kind. | Error |
403 | The token is valid but not allowed to do this. | Error |
404 | No portfolio with this id exists in this project, or it has been deleted. | Error |
500 | A fault on our side. | Error |
503 | The portfolio has not been scored yet (code is unscored), is being rescored after a change (code is rescoring), or the project's data is temporarily unreachable; try again shortly. | Error |
Example
curl -X GET "https://api.spicelabs.io/api/v1/project/<projectId>/v1/portfolio/<portfolioId>/rank" \
-H "Authorization: Bearer $SPICE_API_TOKEN" Simulate portfolio fixes
POST /api/v1/project/{projectId}/v1/portfolio/{portfolioId}/simulate
Credentials: API token or dashboard sign-in.
What the portfolio's score would be if the named fixes were applied. The body is one fix, a list of fixes, or {"fixes": [...]}. A fix names a row of the ranked list in item_key; on its own that means fixing everything on the row. Add finding_key to fix one finding of the row, or dependency (a library the row bundles) to upgrade that library, never both; upgrade_to sets the version to upgrade to, and defaults to the known fixed version. The answer holds the current and projected scores, marked as projected; add the rank=true query parameter to get the re-ranked fix list as well. Nothing is changed. Requires project:portfolio:view.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
projectId required | path | string (uuid) | The project's id. |
portfolioId required | path | string (uuid) | The portfolio ID |
rank | query | boolean | Also return the fix list as it would stand after the fixes (default false) |
Request body
The fixes to simulate
application/json (required)
Responses
| Status | Description | Body |
|---|---|---|
200 | The projected scores, marked as projected. | Simulation |
400 | No fix was given, a fix gives both finding_key and dependency, or a fix names a row that is not in the ranked list, a finding or library the row does not carry, or an upgrade that cannot apply to it. | Error |
401 | The token is missing, expired, revoked or of the wrong kind. | Error |
403 | The token is valid but not allowed to do this. | Error |
404 | No portfolio with this id exists in this project, or it has been deleted. | Error |
500 | A fault on our side. | Error |
503 | The project's data is temporarily unreachable; code says why. | Error |
Example
curl -X POST "https://api.spicelabs.io/api/v1/project/<projectId>/v1/portfolio/<portfolioId>/simulate" \
-H "Authorization: Bearer $SPICE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '<JSON body>' Get portfolio state
GET /api/v1/project/{projectId}/v1/portfolio/{portfolioId}/state
Credentials: API token or dashboard sign-in.
The portfolio's current score and its breakdown by axis and by subject, with the time it was computed. The ranked fix list is left out unless the rank=true query parameter asks for it; the rank endpoint serves it in pages. Requires project:portfolio:view.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
projectId required | path | string (uuid) | The project's id. |
portfolioId required | path | string (uuid) | The portfolio ID |
rank | query | boolean | Include the full ranked list of fixes (default false) |
Responses
| Status | Description | Body |
|---|---|---|
200 | The current state. | PortfolioState |
401 | The token is missing, expired, revoked or of the wrong kind. | Error |
403 | The token is valid but not allowed to do this. | Error |
404 | No portfolio with this id exists in this project, or it has been deleted. | Error |
500 | A fault on our side. | Error |
503 | The portfolio has not been scored yet (code is unscored), is being rescored after a change (code is rescoring), or the project's data is temporarily unreachable; try again shortly. | Error |
Example
curl -X GET "https://api.spicelabs.io/api/v1/project/<projectId>/v1/portfolio/<portfolioId>/state" \
-H "Authorization: Bearer $SPICE_API_TOKEN" Regenerate a report
POST /api/v1/project/{projectId}/v1/report/{jobId}/regenerate
Credentials: API token or dashboard sign-in.
Asks for a new version of a report under the current report version. A posture report is rebuilt from the same data as of the same date. A survey's report is rebuilt by a new survey that reuses the analysis the survey already has, with no new upload. The old version stays readable. The answer's job_id is the job to follow: the new posture report, or for a survey's report the new survey; supersedes names the posture report or survey it replaces. A report is regenerated once: while its new version is being produced, and after it is ready, a further request answers 409. If the new version fails, or is still waiting to start after 30 minutes, you may ask again. Requires project:edit.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
projectId required | path | string (uuid) | The project's id. |
jobId required | path | string (uuid) | The report's job ID: a survey's report step, or a posture report |
Idempotency-Key | header | string or null | Optional; repeating a key returns the first answer for a survey's report |
Responses
| Status | Description | Body |
|---|---|---|
202 | Regeneration requested: job_id is the job to follow and supersedes names what it replaces. | RegenerateReportResponse |
400 | The report belongs to a survey that has no upload to rebuild from. | Error |
401 | The token is missing, expired, revoked or of the wrong kind. | Error |
403 | The token is valid but not allowed to do this. | Error |
404 | No report with this job id exists in this project, or its portfolio has been deleted. | Error |
409 | This report was already regenerated, or a new version is already being produced. | Error |
500 | A fault on our side. | Error |
503 | The project's data is temporarily unreachable; code says why. | Error |
Example
curl -X POST "https://api.spicelabs.io/api/v1/project/<projectId>/v1/report/<jobId>/regenerate" \
-H "Authorization: Bearer $SPICE_API_TOKEN" List subjects
GET /api/v1/project/{projectId}/v1/subject
Credentials: API token or dashboard sign-in.
Every subject in this project. A subject is a thing being scored, such as an application or a component; each carries its current criticality and when it was first and last seen. Requires project:portfolio:view.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
projectId required | path | string (uuid) | The project's id. |
Responses
| Status | Description | Body |
|---|---|---|
200 | The subjects, under subjects. | SubjectList |
401 | The token is missing, expired, revoked or of the wrong kind. | Error |
403 | The token is valid but not allowed to do this. | Error |
404 | Portfolios are not set up for this project yet. | Error |
500 | A fault on our side. | Error |
503 | The project's data is temporarily unreachable; code says why. | Error |
Example
curl -X GET "https://api.spicelabs.io/api/v1/project/<projectId>/v1/subject" \
-H "Authorization: Bearer $SPICE_API_TOKEN" List a subject's contents
GET /api/v1/project/{projectId}/v1/subject/{subject}/content
Credentials: API token or dashboard sign-in.
The items currently inside a subject, one page at a time. offset (default 0) and limit query parameters choose the page. Requires project:portfolio:view.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
projectId required | path | string (uuid) | The project's id. |
subject required | path | string | The subject's name |
offset | query | integer | Index of the first item to return (default 0) |
limit | query | integer | Page size, 1 to 10000 (default 1000) |
Responses
| Status | Description | Body |
|---|---|---|
200 | A page of the subject's current contents. | SubjectContents |
401 | The token is missing, expired, revoked or of the wrong kind. | Error |
403 | The token is valid but not allowed to do this. | Error |
404 | No subject with this name exists in this project. | Error |
500 | A fault on our side. | Error |
503 | The project's data is temporarily unreachable; code says why. | Error |
Example
curl -X GET "https://api.spicelabs.io/api/v1/project/<projectId>/v1/subject/<subject>/content" \
-H "Authorization: Bearer $SPICE_API_TOKEN" Rate a subject's criticality
PUT /api/v1/project/{projectId}/v1/subject/{subject}/criticality
Credentials: Dashboard sign-in only. API tokens are refused.
Records how important a subject is. The body carries value, one of high, medium, low or unclassified, and an optional rationale. The caller is recorded as the rater. Ratings are kept as a history and never overwritten, and every portfolio holding the subject is rescored. Only a dashboard session may call this, never an API token. Requires project:portfolio:rate.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
projectId required | path | string (uuid) | The project's id. |
subject required | path | string | The subject's name |
Request body
application/json (required)
Responses
| Status | Description | Body |
|---|---|---|
200 | The recorded rating: its value, the prior_value, the rater and when. | CriticalityRating |
400 | value is missing, or is not one of high, medium, low or unclassified. | Error |
401 | The token is missing, expired, revoked or of the wrong kind. | Error |
403 | The token is valid but not allowed to do this. | Error |
404 | No subject with this name exists in this project. | Error |
500 | A fault on our side. | Error |
503 | The project's data is temporarily unreachable; code says why. | Error |
Example
curl -X PUT "https://api.spicelabs.io/api/v1/project/<projectId>/v1/subject/<subject>/criticality" \
-H "Authorization: Bearer $SPICE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '<JSON body>' Get criticality history
GET /api/v1/project/{projectId}/v1/subject/{subject}/criticality/history
Credentials: API token or dashboard sign-in.
Every criticality rating a subject has received, each with its value, the prior_value it replaced, who rated it, the rationale and when. A subject that has never been rated gives an empty list. Requires project:portfolio:view.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
projectId required | path | string (uuid) | The project's id. |
subject required | path | string | The subject's name |
Responses
| Status | Description | Body |
|---|---|---|
200 | The subject's ratings. | array of CriticalityEventResponse |
401 | The token is missing, expired, revoked or of the wrong kind. | Error |
403 | The token is valid but not allowed to do this. | Error |
404 | Portfolios are not set up for this project yet. | Error |
500 | A fault on our side. | Error |
503 | The project's data is temporarily unreachable; code says why. | Error |
Example
curl -X GET "https://api.spicelabs.io/api/v1/project/<projectId>/v1/subject/<subject>/criticality/history" \
-H "Authorization: Bearer $SPICE_API_TOKEN"