API Quickstart
The AutoCISO REST API lets you push software composition data into your compliance workspace from CI/CD pipelines and internal tools. This guide walks you through your first authenticated request.
Prerequisites
- An API token — see Obtaining an API Token
- The token needs
sbom:readto read andsbom:writeto upload - Your plan must include the
supply_chain_securityfeature
Set your token as an environment variable so you don’t hard-code credentials:
export AUTOCISO_API_TOKEN="aci_your_token_here"
Base URL
All REST endpoints are under:
https://api.autociso.io/api/v1
Use api.autociso.io for every integration. It carries only the API, so it is
unaffected by changes to the marketing site or the web console.
The apex host autociso.io routes to the same backend and stays supported, so
older integrations keep working unchanged. Every example on this site uses
api.autociso.io.
Authentication
Every request must include your token in the Authorization header:
Authorization: Bearer aci_your_token_here
Example 1 — List your SBOMs
A simple GET that returns the Software Bills of Materials registered in your organisation. Pass q to filter by name.
curl -s \
-H "Authorization: Bearer $AUTOCISO_API_TOKEN" \
"https://api.autociso.io/api/v1/sscs/sboms" const API_BASE = 'https://api.autociso.io/api/v1';
const token = process.env.AUTOCISO_API_TOKEN!;
const res = await fetch(`${API_BASE}/sscs/sboms`, {
headers: { Authorization: `Bearer ${token}` },
});
if (!res.ok) {
throw new Error(`API error ${res.status}: ${await res.text()}`);
}
const { data } = await res.json();
console.log(`Found ${data.length} SBOMs:`, data); package main
import (
"encoding/json"
"fmt"
"net/http"
"os"
)
func main() {
token := os.Getenv("AUTOCISO_API_TOKEN")
apiURL := "https://api.autociso.io/api/v1/sscs/sboms"
req, _ := http.NewRequest(http.MethodGet, apiURL, nil)
req.Header.Set("Authorization", "Bearer "+token)
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
var result map[string]any
json.NewDecoder(resp.Body).Decode(&result)
fmt.Printf("%+v\n", result)
} import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class ListSboms {
private static final String API_BASE = "https://api.autociso.io/api/v1";
private static final String TOKEN = System.getenv("AUTOCISO_API_TOKEN");
public static void main(String[] args) throws Exception {
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder()
.uri(URI.create(API_BASE + "/sscs/sboms"))
.header("Authorization", "Bearer " + TOKEN)
.GET()
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() != 200) {
throw new RuntimeException("API error " + response.statusCode()
+ ": " + response.body());
}
System.out.println(response.body());
}
} A successful response looks like:
{
"data": [
{
"id": "sbom_1hgyun41rx48",
"name": "payment-service",
"version": "1.4.2",
"source": "cyclonedx",
"componentCount": 412,
"createdAt": "2026-03-01T09:00:00Z"
}
],
"error": null,
"meta": null
}
Example 2 — Upload an SBOM
Upload a Software Bill of Materials file so AutoCISO can scan it for vulnerabilities and track software composition. Requires the sbom:write scope.
curl -s -X POST \
-H "Authorization: Bearer $AUTOCISO_API_TOKEN" \
-F "file=@sbom.cyclonedx.json" \
-F "name=payment-service" \
-F "version=1.4.2" \
"https://api.autociso.io/api/v1/sscs/sboms/upload" import { readFileSync } from 'node:fs';
const API_BASE = 'https://api.autociso.io/api/v1';
const token = process.env.AUTOCISO_API_TOKEN!;
const form = new FormData();
form.append(
'file',
new Blob([readFileSync('sbom.cyclonedx.json')], { type: 'application/json' }),
'sbom.cyclonedx.json',
);
form.append('name', 'payment-service');
form.append('version', '1.4.2');
const res = await fetch(`${API_BASE}/sscs/sboms/upload`, {
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
body: form,
});
const { data, error } = await res.json();
if (error) throw new Error(error.message);
console.log('Uploaded SBOM:', data.id); package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"mime/multipart"
"net/http"
"os"
"path/filepath"
)
func main() {
token := os.Getenv("AUTOCISO_API_TOKEN")
uploadSBOM(token, "sbom.cyclonedx.json", "payment-service", "1.4.2")
}
func uploadSBOM(token, filePath, name, version string) {
f, err := os.Open(filePath)
if err != nil {
panic(err)
}
defer f.Close()
var body bytes.Buffer
w := multipart.NewWriter(&body)
fw, _ := w.CreateFormFile("file", filepath.Base(filePath))
io.Copy(fw, f)
w.WriteField("name", name)
w.WriteField("version", version)
w.Close()
req, _ := http.NewRequest(http.MethodPost,
"https://api.autociso.io/api/v1/sscs/sboms/upload", &body)
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", w.FormDataContentType())
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
var result map[string]any
json.NewDecoder(resp.Body).Decode(&result)
fmt.Printf("%+v\n", result)
} import java.io.IOException;
import java.net.URI;
import java.net.http.*;
import java.nio.file.*;
public class UploadSBOM {
private static final String API_BASE = "https://api.autociso.io/api/v1";
private static final String TOKEN = System.getenv("AUTOCISO_API_TOKEN");
public static void main(String[] args) throws Exception {
uploadSBOM(
Path.of("sbom.cyclonedx.json"),
"payment-service",
"1.4.2"
);
}
static void uploadSBOM(Path sbomFile, String name, String version)
throws IOException, InterruptedException {
var boundary = "----AutoCISOBoundary" + System.currentTimeMillis();
var fileBytes = Files.readAllBytes(sbomFile);
// Build multipart/form-data body manually
var body = new StringBuilder();
body.append("--").append(boundary).append("\r\n");
body.append("Content-Disposition: form-data; name=\"name\"\r\n\r\n");
body.append(name).append("\r\n");
body.append("--").append(boundary).append("\r\n");
body.append("Content-Disposition: form-data; name=\"version\"\r\n\r\n");
body.append(version).append("\r\n");
body.append("--").append(boundary).append("\r\n");
body.append("Content-Disposition: form-data; name=\"file\"; filename=\"")
.append(sbomFile.getFileName()).append("\"\r\n");
body.append("Content-Type: application/json\r\n\r\n");
var prefix = body.toString().getBytes();
var suffix = ("\r\n--" + boundary + "--\r\n").getBytes();
var full = new byte[prefix.length + fileBytes.length + suffix.length];
System.arraycopy(prefix, 0, full, 0, prefix.length);
System.arraycopy(fileBytes, 0, full, prefix.length, fileBytes.length);
System.arraycopy(suffix, 0, full, prefix.length + fileBytes.length, suffix.length);
var request = HttpRequest.newBuilder()
.uri(URI.create(API_BASE + "/sscs/sboms/upload"))
.header("Authorization", "Bearer " + TOKEN)
.header("Content-Type", "multipart/form-data; boundary=" + boundary)
.POST(HttpRequest.BodyPublishers.ofByteArray(full))
.build();
var response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
} Error handling
All responses use the same envelope. On failure, data is null and error carries a machine-readable code:
{
"data": null,
"error": { "code": "MISSING_FILE", "message": "multipart field 'file' is required" }
}
| Status | Code | Meaning |
|---|---|---|
| 400 | INVALID_REQUEST | Malformed multipart form |
| 400 | MISSING_FILE | The file field was absent |
| 400 | UNSUPPORTED_FORMAT | File extension is not a recognised SBOM format |
| 400 | PARSE_ERROR | The file could not be parsed as an SBOM |
| 400 | VALIDATION_FAILED | A JSON body failed schema validation |
| 401 | INVALID_TOKEN | Token is malformed, revoked, or expired |
| 403 | FORBIDDEN | Endpoint does not accept API tokens, or the plan lacks supply_chain_security |
| 403 | INSUFFICIENT_SCOPE | Token is valid but missing the required scope |
| 500 | DB_ERROR | Contact support |
Next steps
Was this page helpful?