EQTY LabDocs

Submit an assessment for review

Freeze an assessment's draft into its next submission for the program's reviewers to review control by control: the pinned configuration and any pinned operating profile, the draft's declarations and its not-applicable claims, registered with the Integrity Service as a governance statement in the assessment's graph, signed by the caller. A pinned profile is first checked by the agent registry against what the agent was seen with in the 30 days before and the permissions in the newest state, from any of the agent's active keys, that gave the pinned configuration (the pinned state when the gateway recorded none); the submission keeps the check as profileCheck for reviewers, and that state as its witness. The submission records the pinned observation, the state and request the starter pinned, and the key that signed it, whichever key witnessed the configuration. No finding blocks submitting, but a check that cannot be made does: 503 while the registry is unavailable, 400 when it cannot use the pinned state. Every file the pinned configuration names, and the pinned request's system prompt, is then read through the pinned state from the agent registry with the caller's token, checked against its CID and frozen with the submission as its files, which whoever may read the assessment reads through the submission's file route; a file the registry says it does not hold, one larger than 5 MiB, or one it serves with other bytes than its CID names is not frozen. A pinned state the registry no longer holds fails the submission with 400, asking for the configuration to be pinned again; the registry refusing the caller (401 or 403) fails it with 403; any other file it cannot serve fails it as the profile check does, 503 while it is unavailable; file storage failing to read or store a file, or freezing taking longer than 30 seconds, fails it with 503 too. The Integrity Service then records, for every control, the evidence it is judged on (its covering declarations, its not-applicable claim and the values of the configuration fields and profile sections it judges), and the submission names each control's evidence CID. The draft must have a pinned configuration, a declaration or not-applicable claim for every control (a control that expects no evidence needs neither when it is judged only against configuration fields the pinned configuration captured and, with a profile pinned, profile sections), and changes since the newest submission, and the starter must still see the agent, which must be active. A newest submission made before controls carried evidence cannot be reviewed, so the draft it froze can be submitted again unchanged. Reviewers judge whether the evidence is enough. Submitting supersedes the newest submission, whose controls can then no longer be reviewed. Pass draftVersion to submit only the draft you reviewed. Only the member who started the assessment may submit; an integration's API key bound to no project acts as its owner with full access or the submit_agent_assessments scope

posthttps://localhost:10001/api/v1/organizations/{orgId}/assessments/{assessmentId}/submissions
bash
curl --request POST \
  --url 'https://localhost:10001/api/v1/organizations/{orgId}/assessments/{assessmentId}/submissions' \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{"draftVersion":0}'
javascript
const response = await fetch("https://localhost:10001/api/v1/organizations/{orgId}/assessments/{assessmentId}/submissions", {
  method: "POST",
  headers: {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "draftVersion": 0
  })
});

const data = await response.json();
typescript
interface AssessmentSubmission {
  agentDid?: string;
  configuration?: Record<string, unknown>;
  controlCount?: number;
  controls?: Record<string, unknown>[];
  declarations?: Record<string, unknown>[];
  document?: Record<string, unknown>;
  documentCid?: string;
  draftVersion?: number;
  evidence?: Record<string, unknown>;
  files?: Record<string, unknown>[];
  notApplicable?: Record<string, unknown>[];
  number?: number;
  observation?: Record<string, unknown>;
  pins?: Record<string, unknown>[];
  profile?: Record<string, unknown>;
  profileCheck?: Record<string, unknown>;
  statementId?: string;
  status?: "in_review" | "passed" | "failed" | "superseded";
  submittedAt?: string;
  submittedBy?: string;
  submittedByDid?: string;
  submittedByUserId?: string;
  uuid?: string;
  witness?: Record<string, unknown>;
}

const response = await fetch("https://localhost:10001/api/v1/organizations/{orgId}/assessments/{assessmentId}/submissions", {
  method: "POST",
  headers: {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "draftVersion": 0
  })
});
if (!response.ok) throw new Error(`${response.status} ${response.statusText}`);

const data: AssessmentSubmission = await response.json();
python
import requests

response = requests.post(
    "https://localhost:10001/api/v1/organizations/{orgId}/assessments/{assessmentId}/submissions",
    headers={
        "Authorization": "Bearer <token>",
        "Content-Type": "application/json",
    },
    json={
        "draftVersion": 0,
    },
)
response.raise_for_status()
print(response.json())
go
package main

import (
	"fmt"
	"io"
	"net/http"
	"strings"
)

func main() {
	body := strings.NewReader(`{
	  "draftVersion": 0
	}`)
	req, err := http.NewRequest(http.MethodPost, "https://localhost:10001/api/v1/organizations/{orgId}/assessments/{assessmentId}/submissions", body)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer <token>")
	req.Header.Set("Content-Type", "application/json")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	fmt.Println(res.Status, string(data))
}
java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Example {
    public static void main(String[] args) throws Exception {
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://localhost:10001/api/v1/organizations/{orgId}/assessments/{assessmentId}/submissions"))
            .header("Authorization", "Bearer <token>")
            .header("Content-Type", "application/json")
            .method("POST", HttpRequest.BodyPublishers.ofString("""
                {
                  "draftVersion": 0
                }
                """))
            .build();

        HttpResponse<String> response = HttpClient.newHttpClient()
            .send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println(response.statusCode() + " " + response.body());
    }
}
csharp
using System.Net.Http.Headers;
using System.Text;

using var client = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Post, "https://localhost:10001/api/v1/organizations/{orgId}/assessments/{assessmentId}/submissions");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "<token>");
request.Content = new StringContent("""
    {
      "draftVersion": 0
    }
    """, Encoding.UTF8, "application/json");

using var response = await client.SendAsync(request);
Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}");
php
<?php

$ch = curl_init('https://localhost:10001/api/v1/organizations/{orgId}/assessments/{assessmentId}/submissions');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer <token>',
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => <<<'JSON'
    {
      "draftVersion": 0
    }
    JSON,
    CURLOPT_RETURNTRANSFER => true,
]);

$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
echo $status . " " . $response . PHP_EOL;
ruby
require "net/http"

uri = URI("https://localhost:10001/api/v1/organizations/{orgId}/assessments/{assessmentId}/submissions")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer <token>"
request["Content-Type"] = "application/json"
request.body = <<~'JSON'
  {
    "draftVersion": 0
  }
JSON

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
  http.request(request)
end
puts "#{response.code} #{response.body}"
rust
// Cargo.toml dependencies: reqwest (features "json"), serde_json, tokio (features "full")
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let response = reqwest::Client::new()
        .post("https://localhost:10001/api/v1/organizations/{orgId}/assessments/{assessmentId}/submissions")
        .header("Authorization", "Bearer <token>")
        .json(&json!({
            "draftVersion": 0
        }))
        .send()
        .await?;

    println!("{} {}", response.status(), response.text().await?);
    Ok(())
}

Authorizations

  • BearerAuth · API key in header "Authorization" — Type "Bearer" followed by a space and JWT token.

Parameters

Path parameters

NameTypeDescription
orgId
required
string

Organization ID or UUID (urn:uuid optional)

assessmentId
required
string

Assessment UUID (urn:uuid optional)

Request body

The draft version being submitted

application/json
  • draftVersioninteger

    The draft version the caller reviewed; any other refuses the submission with 409

Examplejson
{
  "draftVersion": 0
}

Responses

201Submission

application/json
  • agentDidstring

    The agent key that signed the pinned state

  • configurationcore.AssessmentConfiguration
    Show core.AssessmentConfiguration
    • cidstring

      urn:cid of Document, registered with the Integrity Service

    • documentobject

      The AgentConfigurationV1 document, including its coverage. Returned as stored, so its bytes are not canonical: cid is over its JCS (RFC 8785) form, which a verifier recomputes before hashing

    • schemaVersionstring
  • controlCountinteger
  • controlscore.SubmissionControl[]

    Every control reviewed, by control, with its reviews

    Show properties

    Array of core.SubmissionControl

    • controlCodestring
    • outcomeobject

      The newest review's

      One ofsatisfiednot_satisfiednot_applicable

      Show properties

      object (enum) — The newest review's · one of satisfied, not_satisfied, not_applicable

    • reviewscore.ControlReview[]

      Oldest first

      Show properties

      Array of core.ControlReview

      • controlCodestring
      • documentCidstring

        urn:cid of the review document the Integrity Service stored

      • evidenceCidstring

        urn:cid of the control's evidence the review judged; absent on reviews made before controls carried evidence

      • outcomeobject

        One ofsatisfiednot_satisfiednot_applicable

        Show properties

        object (enum) · one of satisfied, not_satisfied, not_applicable

      • reviewedAtstring<date-time>
      • reviewedBystring
      • reviewedByDidstring
      • reviewedByUserIdstring
      • statementstring
      • statementIdstring

        urn:cid of the governance statement it registered as

      • uuidstringread-only

        urn:uuid form

  • declarationscore.AssessmentDeclaration[]

    The declarations it stands on, oldest first

    Show properties

    Array of core.AssessmentDeclaration

    • attachmentscore.AssessmentAttachment[]
      Show properties

      Array of core.AssessmentAttachment

      • cidstring

        urn:cid of the bytes, registered with the Integrity Service

      • contentTypestring
      • fileNamestring
      • idinteger

        The file, for its assessment's declaration file routes

      • sizeBytesinteger
    • controlsstring[]

      The control codes it covers, in the program's order

    • documentCidstringread-only

      urn:cid of the declaration document the Integrity Service stored

    • statementstring
    • statementIdstringread-only

      urn:cid of the governance statement it registered as

    • submittedAtstring<date-time>read-only
    • submittedBystringread-only
    • submittedByDidstringread-only
    • submittedByUserIdstringread-only
    • uuidstringread-only

      urn:uuid form

  • documentobject

    The submission document, as registered

  • documentCidstring

    urn:cid of the document

  • draftVersioninteger

    The draft version it froze

  • evidenceobject

    Control code -> urn:cid of the evidence the Integrity Service recorded the control is judged on; empty for a submission made before controls carried evidence, which cannot be reviewed

    Show properties

    Map of string

  • filescore.SubmissionFile[]

    Every configuration file the configuration names and the observed system prompt, by path, as the agent registry served them to the submitter, sorted by path; each is read through the submission's file route by whoever may read the assessment. A file the registry did not hold, or larger than 5 MiB, was not frozen. Empty for a submission made before files were frozen

    Show properties

    Array of core.SubmissionFile

    • cidstring

      urn:cid of the BLAKE3 CID of its bytes, which the submission's file route reads it by

    • pathstring

      As the configuration names it, host:/abs/path or project:relative/path, or request:systemPrompt for the observed system prompt

    • sizeBytesinteger
  • notApplicablecore.AssessmentNotApplicable[]

    The claims it froze, by control

    Show properties

    Array of core.AssessmentNotApplicable

    • controlCodestring
    • justificationstring
    • submittedAtstring<date-time>
    • submittedBystring
    • submittedByDidstring
    • submittedByUserIdstring
  • numberinteger

    Numbered from 1 within the assessment

  • observationobject

    The pinned observation: the state, and the request the starter pinned, as the starter saw them

    Show properties
    • correlationIdstring

      The exchange's correlation ID

    • observedAtstring<date-time>

      When the gateway verified the exchange carrying it

    • requestobject

      Per-request detail, evidence rather than configuration

      Show properties
      • modelstring
      • providerstring
      • systemPromptCidstring
      • toolsstring[]
    • stateCidstring

      The observed state in the gateway's store

    • subAgentstring

      The custom agent's sub-agent that made the request, /-separated when nested; it shares the agent's configuration

    • viperVersionstring

      The Viper version that captured it

  • pinscore.AssessmentPin[]

    Each pin and unpin made after the submission before it, or since the start, up to this one, oldest first; empty where none was recorded, as before pins were kept

    Show properties

    Array of core.AssessmentPin

    • cidstring

      urn:cid of what was pinned; absent when the profile was unpinned

    • documentobject

      The configuration or profile document pinned; absent when the profile was unpinned

    • draftVersioninteger

      The draft version the pin made, which orders pins and places each in the submission that froze it

    • kindobject

      One ofconfigurationprofile

      Show properties

      object (enum) · one of configuration, profile

    • pinnedAtstring<date-time>
    • pinnedBystring

      Who pinned it, as the assessment names its starter

    • pinnedByUserIdstring

      Absent on a pin recorded before it was

    • profileVersioninteger

      The agent's version number of a pinned profile

    • requestobject

      The request a pinned configuration was seen with, evidence its CID doesn't cover

      Show properties
      • modelstring
      • providerstring
      • systemPromptCidstring
      • toolsstring[]
  • profileobject

    Absent when no operating profile was pinned

    Show properties
    • cidstring

      urn:cid of Document, registered with the Integrity Service

    • documentobject

      The AgentOperatingProfileV1 document, as the agent registry stores it. cid is over its JCS (RFC 8785) form

    • versioninteger

      The agent's version number of it, as the agent registry numbers them

  • profileCheckobject

    The agent registry's check of the profile when it was submitted, as returned by its profile/check route: what the agent was seen with in the 30 days before that the profile does not declare or excludes, what it declares that went unseen, and what could not be checked. Absent with the profile

  • statementIdstring

    urn:cid of the governance statement it registered as

  • statusobject

    One ofin_reviewpassedfailedsuperseded

    Show properties

    object (enum) · one of in_review, passed, failed, superseded

  • submittedAtstring<date-time>
  • submittedBystring
  • submittedByDidstring
  • submittedByUserIdstring
  • uuidstringread-only

    urn:uuid form

  • witnessobject

    The state the profile was checked against at submission; absent on a submission made before it was recorded

    Show properties
    • observedAtstring<date-time>

      When the gateway verified the exchange carrying it

    • signerDidstring

      The agent key that signed it

    • stateCidstring

      The witnessing state in the gateway's store

Examplejson
{
  "agentDid": "string",
  "configuration": {
    "cid": "string",
    "document": {},
    "schemaVersion": "string"
  },
  "controlCount": 0,
  "controls": [
    {
      "controlCode": "string",
      "outcome": "satisfied",
      "reviews": [
        {
          "controlCode": "string",
          "documentCid": "string",
          "evidenceCid": "string",
          "outcome": "satisfied",
          "reviewedAt": "2025-01-01T00:00:00Z",
          "reviewedBy": "string",
          "reviewedByDid": "string",
          "reviewedByUserId": "string",
          "statement": "string",
          "statementId": "string"
        }
      ]
    }
  ],
  "declarations": [
    {
      "attachments": [
        {
          "cid": "string",
          "contentType": "string",
          "fileName": "string",
          "id": 0,
          "sizeBytes": 0
        }
      ],
      "controls": [
        "string"
      ],
      "statement": "string"
    }
  ],
  "document": {},
  "documentCid": "string",
  "draftVersion": 0,
  "evidence": {
    "key": "string"
  },
  "files": [
    {
      "cid": "urn:cid:bafkr4ihkgmcaa4xvn6xvtgdqi4h3hl7p5gqrlbe3rxyqwcq3t5mfaj6awi",
      "path": "string",
      "sizeBytes": 0
    }
  ],
  "notApplicable": [
    {
      "controlCode": "string",
      "justification": "string",
      "submittedAt": "2025-01-01T00:00:00Z",
      "submittedBy": "string",
      "submittedByDid": "string",
      "submittedByUserId": "string"
    }
  ],
  "number": 0,
  "observation": {
    "correlationId": "string",
    "observedAt": "2025-01-01T00:00:00Z",
    "request": {
      "model": "string",
      "provider": "string",
      "systemPromptCid": "string",
      "tools": [
        "string"
      ]
    },
    "stateCid": "string",
    "subAgent": "string",
    "viperVersion": "string"
  },
  "pins": [
    {
      "cid": "string",
      "document": {},
      "draftVersion": 0,
      "kind": "configuration",
      "pinnedAt": "2025-01-01T00:00:00Z",
      "pinnedBy": "string",
      "pinnedByUserId": "string",
      "profileVersion": 0,
      "request": {
        "model": "string",
        "provider": "string",
        "systemPromptCid": "string",
        "tools": [
          "string"
        ]
      }
    }
  ],
  "profile": {
    "cid": "string",
    "document": {},
    "version": 0
  },
  "profileCheck": {},
  "statementId": "string",
  "status": "in_review",
  "submittedAt": "2025-01-01T00:00:00Z",
  "submittedBy": "string",
  "submittedByDid": "string",
  "submittedByUserId": "string",
  "uuid": "string",
  "witness": {
    "observedAt": "2025-01-01T00:00:00Z",
    "signerDid": "string",
    "stateCid": "string"
  }
}

400Bad request - Invalid request, the draft is incomplete or unchanged, or the agent registry can no longer use the pinned state

application/json
  • errorstring
Examplejson
{
  "error": "Invalid request body"
}

401Unauthorized - Authentication required

application/json
  • errorstring
Examplejson
{
  "error": "Invalid request body"
}

403Forbidden - Not the assessment's starter, an API key with neither full access nor submit_agent_assessments, a project-bound key, or the agent registry refuses the caller

application/json
  • errorstring
Examplejson
{
  "error": "Invalid request body"
}

404Assessment or agent not found

application/json
  • errorstring
Examplejson
{
  "error": "Invalid request body"
}

409The draft changed since draftVersion, or another submission happened at once

application/json
  • errorstring
Examplejson
{
  "error": "Invalid request body"
}

500Internal server error

application/json
  • errorstring
Examplejson
{
  "error": "Invalid request body"
}

503The agent registry or file storage is unavailable

application/json
  • errorstring
Examplejson
{
  "error": "Invalid request body"
}