curl --request GET \
--url https://{tenant}.earnie.dev/v1/scans/projects/{projectId}/summary/crypto \
--header 'Authorization: Bearer <token>'import requests
url = "https://{tenant}.earnie.dev/v1/scans/projects/{projectId}/summary/crypto"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://{tenant}.earnie.dev/v1/scans/projects/{projectId}/summary/crypto', 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://{tenant}.earnie.dev/v1/scans/projects/{projectId}/summary/crypto",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://{tenant}.earnie.dev/v1/scans/projects/{projectId}/summary/crypto"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://{tenant}.earnie.dev/v1/scans/projects/{projectId}/summary/crypto")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://{tenant}.earnie.dev/v1/scans/projects/{projectId}/summary/crypto")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"project_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"source_scan_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"crypto": {
"findings_total": 123,
"assets_total": 123,
"reachable_weak_count": 123,
"reachability": {
"reachable": 123,
"unreachable": 123,
"unknown": 123
},
"quantum_vulnerable": 123,
"quantum_unknown": 123,
"attribution": {
"first_party": 123,
"dependency": 123
},
"top_algorithms": [
{
"family": "<string>",
"count": 123,
"severity": "info",
"quantum_safe": true,
"reachable": true
}
],
"asset_composition": {
"algorithm": 123,
"protocol": 123,
"certificate": 123,
"related_crypto_material": 123
},
"export_readiness": {
"ready": true,
"state": "ready",
"stale_findings": 123,
"unresolved_findings": 123,
"resolved_findings": 123,
"total_findings": 123
},
"triaged": {
"total": 123,
"confirmed_usage": 123,
"accepted_risk": 123,
"false_positive": 123,
"reachable_weak": 123,
"quantum_vulnerable_assets": 123
},
"datasets": {
"risk_table_version": "<string>",
"risk_table_reviewed_at": "<string>",
"export_dataset_id": "<string>",
"export_dataset_reviewed_at": "<string>"
}
},
"last_crypto_scan_at": "2023-11-07T05:31:56Z"
}{
"code": "<string>",
"message": "<string>"
}{
"code": "<string>",
"message": "<string>"
}{
"code": "<string>",
"message": "<string>"
}Project crypto posture rollup
Returns the crypto rollup for the project’s posture source scan, resolved by the same rule as GET /v1/scans/projects/{projectId}/summary. Split out of that response because it reads every active crypto finding in the project; a client fetches both at once and renders the crypto section when this one arrives.
crypto is absent when crypto never ran for the project and it holds no active crypto findings, or when the caller’s organization does not have the crypto scanner enabled.
curl --request GET \
--url https://{tenant}.earnie.dev/v1/scans/projects/{projectId}/summary/crypto \
--header 'Authorization: Bearer <token>'import requests
url = "https://{tenant}.earnie.dev/v1/scans/projects/{projectId}/summary/crypto"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://{tenant}.earnie.dev/v1/scans/projects/{projectId}/summary/crypto', 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://{tenant}.earnie.dev/v1/scans/projects/{projectId}/summary/crypto",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://{tenant}.earnie.dev/v1/scans/projects/{projectId}/summary/crypto"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://{tenant}.earnie.dev/v1/scans/projects/{projectId}/summary/crypto")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://{tenant}.earnie.dev/v1/scans/projects/{projectId}/summary/crypto")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"project_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"source_scan_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"crypto": {
"findings_total": 123,
"assets_total": 123,
"reachable_weak_count": 123,
"reachability": {
"reachable": 123,
"unreachable": 123,
"unknown": 123
},
"quantum_vulnerable": 123,
"quantum_unknown": 123,
"attribution": {
"first_party": 123,
"dependency": 123
},
"top_algorithms": [
{
"family": "<string>",
"count": 123,
"severity": "info",
"quantum_safe": true,
"reachable": true
}
],
"asset_composition": {
"algorithm": 123,
"protocol": 123,
"certificate": 123,
"related_crypto_material": 123
},
"export_readiness": {
"ready": true,
"state": "ready",
"stale_findings": 123,
"unresolved_findings": 123,
"resolved_findings": 123,
"total_findings": 123
},
"triaged": {
"total": 123,
"confirmed_usage": 123,
"accepted_risk": 123,
"false_positive": 123,
"reachable_weak": 123,
"quantum_vulnerable_assets": 123
},
"datasets": {
"risk_table_version": "<string>",
"risk_table_reviewed_at": "<string>",
"export_dataset_id": "<string>",
"export_dataset_reviewed_at": "<string>"
}
},
"last_crypto_scan_at": "2023-11-07T05:31:56Z"
}{
"code": "<string>",
"message": "<string>"
}{
"code": "<string>",
"message": "<string>"
}{
"code": "<string>",
"message": "<string>"
}Authorizations
An Earnie API key, sent as Authorization: Bearer sk_earnie_.... Create one under Settings > API keys. The key's scopes decide which operations it may call.
Path Parameters
Response
Project crypto posture rollup.
The project's crypto posture rollup, split out of ProjectSummary because it reads every active crypto finding in the project. Its posture source scan is resolved by the same rule as GET /v1/scans/projects/{projectId}/summary; a scan completing between the two requests can make them differ, which source_scan_id shows.
The posture source scan, resolved by the same rule as ProjectSummary's.
Crypto posture rollup. OPTIONAL, and its presence is the not-scanned discriminator: ABSENT means crypto has never run to completion for this project AND the project holds no active crypto findings (or its findings store was unreachable); PRESENT with all-zero counts means scanned and clean. Clients must never read zero counts as "not scanned" nor absence as "clean".
Presence is a UNION of two facts, because the counts are project-scoped while the scan is not: the posture source scan ran crypto to completion, OR the project still holds active crypto findings. A project whose latest scan skipped crypto but whose findings are still live used to render "not scanned" over real data. When only the second half holds, last_crypto_scan_at says how fresh the numbers are.
Show child attributes
Show child attributes
finished_at of the project's most recent COMPLETED scan that ran the crypto stage to completion, or null when no scan of this project ever did.
It is project-scoped, not scan-scoped: the answer is about the project's crypto history, not about the scan this posture happens to be anchored on. Null while crypto is PRESENT means the section is rendering findings that outlived the scan that produced them — clients should say so rather than imply the numbers are as fresh as the rest of the page.