EQTY LabDocs

Pin an assessment's configuration

Pin the agent's configuration to an assessment's draft: control-plane derives it, with the caller's token, from one observed state in the agent's history, or the latest when stateCid is omitted. With configurationCid instead, it is derived from the newest state, from any of the agent's active keys, that gave that configuration, so the pin is of the configuration rather than of one of the many states Viper signs for it: browse them with control-plane's configurations and preview each with configuration-snapshot?configuration_cid=. At submission the configuration is read from whichever state witnesses it then, so the agent re-signing its state or a key being rotated never asks for a new pin; a configuration pinned before the gateway recorded configurations keeps the state it was pinned from. The snapshot must capture every field the program's scope requires. The configuration may be pinned again at any time; a submission keeps the configuration it froze, and the next draft differs from it. Only the member who started the assessment may pin; an integration's API key bound to no project acts as its owner with full access or the submit_agent_assessments scope

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

const data = await response.json();
typescript
interface Assessment {
  agentDid?: string;
  agentName?: string;
  agentUrn?: string;
  canCertify?: boolean;
  canEdit?: boolean;
  canReview?: boolean;
  configuration?: Record<string, unknown>;
  configurationPinnedAt?: string;
  configurationPinnedByUserId?: string;
  createdAt?: string;
  createdBy?: string;
  createdByDid?: string;
  createdByUserId?: string;
  draftVersion?: number;
  hasUnsubmittedChanges?: boolean;
  latestSubmission?: Record<string, unknown>;
  observation?: Record<string, unknown>;
  organizationId?: number;
  profile?: Record<string, unknown>;
  profilePinnedAt?: string;
  profilePinnedByUserId?: string;
  programManifestCid?: string;
  programSlug?: string;
  programUuid?: string;
  status?: "draft" | "in_review" | "passed" | "failed";
  uuid?: string;
}

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

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

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

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

func main() {
	body := strings.NewReader(`{
	  "configurationCid": "string",
	  "stateCid": "string"
	}`)
	req, err := http.NewRequest(http.MethodPut, "https://localhost:10001/api/v1/organizations/{orgId}/assessments/{assessmentId}/configuration", 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}/configuration"))
            .header("Authorization", "Bearer <token>")
            .header("Content-Type", "application/json")
            .method("PUT", HttpRequest.BodyPublishers.ofString("""
                {
                  "configurationCid": "string",
                  "stateCid": "string"
                }
                """))
            .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.Put, "https://localhost:10001/api/v1/organizations/{orgId}/assessments/{assessmentId}/configuration");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "<token>");
request.Content = new StringContent("""
    {
      "configurationCid": "string",
      "stateCid": "string"
    }
    """, 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}/configuration');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'PUT',
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer <token>',
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => <<<'JSON'
    {
      "configurationCid": "string",
      "stateCid": "string"
    }
    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}/configuration")
request = Net::HTTP::Put.new(uri)
request["Authorization"] = "Bearer <token>"
request["Content-Type"] = "application/json"
request.body = <<~'JSON'
  {
    "configurationCid": "string",
    "stateCid": "string"
  }
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()
        .put("https://localhost:10001/api/v1/organizations/{orgId}/assessments/{assessmentId}/configuration")
        .header("Authorization", "Bearer <token>")
        .json(&json!({
            "configurationCid": "string",
            "stateCid": "string"
        }))
        .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 observed state to pin

application/json
  • configurationCidstring

    A configuration one of the agent's states gave, bare or urn:cid, as the registry's configurations list them; pins it from the newest state any active key sent that gave it. Not with stateCid

  • stateCidstring

    A state from the agent's history; the latest when omitted

Examplejson
{
  "configurationCid": "string",
  "stateCid": "string"
}

Responses

200Assessment with its pinned configuration

application/json
  • agentDidstringread-only

    The agent key that signed the pinned state; absent until a configuration is pinned

  • agentNamestringread-only

    The name the agent registry gave the agent, read when the assessment was started and on every submission; a label for those who cannot see the agent, never evidence. Absent when the registry gave none

  • agentUrnstringread-only

    The agent's control-plane registry ID, whose UUID is the root of the assessment's integrity graph

  • canCertifybooleanread-only

    Whether the caller may ask for the certification its passed newest submission earned: nothing is recorded for it yet, certified or revoked, they neither started the assessment nor made the submission, and they administer programs, or still review its program and made one of the reviews it rests on. False until the assessment passes. Only a single assessment's response works it out; lists leave it false

  • canEditbooleanread-only

    Whether the caller may change and submit the draft: they started the assessment

  • canReviewbooleanread-only

    Whether the caller may review its submissions: they review its program and did not start it

  • configurationobjectread-only

    Pinned to the draft; a submission keeps its own copy, which a later pin does not change

    Show properties
    • 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
  • configurationPinnedAtstring<date-time>read-only
  • configurationPinnedByUserIdstringread-only
  • createdAtstring<date-time>read-only
  • createdBystringread-only
  • createdByDidstringread-only
  • createdByUserIdstringread-only

    Who started it, the only member who may change its draft; absent on assessments started before it was recorded

  • draftVersionintegerread-only

    Increases with every change to the draft; submitting with it freezes exactly the draft the caller saw

  • hasUnsubmittedChangesbooleanread-only

    The draft changed since its newest submission, or was never submitted

  • latestSubmissionobjectread-only

    Absent until the first submission

    Show properties
    • controlCountinteger

      The program's controls, each of which is reviewed

    • draftVersioninteger

      The draft version it froze

    • lastReviewedAtstring<date-time>
    • numberinteger
    • reviewedCountinteger

      Controls with at least one review

    • statusobject

      One ofin_reviewpassedfailed

      Show properties

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

    • submittedAtstring<date-time>
    • uuidstring

      urn:uuid form

  • observationobjectread-only
    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

  • organizationIdintegerread-only
  • profileobjectread-only

    Pinned to the draft, optionally; a submission keeps its own copy, which a later pin does not change

    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

  • profilePinnedAtstring<date-time>read-only
  • profilePinnedByUserIdstringread-only
  • programManifestCidstringread-only

    The requirements the agent is judged against

  • programSlugstringread-only

    The program the version belongs to, which its reviewers are assigned to

  • programUuidstringread-only

    urn:uuid form

  • statusobjectread-only

    One ofdraftin_reviewpassedfailed

    Show properties

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

  • uuidstringread-only

    urn:uuid form

Examplejson
{
  "agentDid": "string",
  "agentName": "string",
  "agentUrn": "string",
  "canCertify": true,
  "canEdit": true,
  "canReview": true,
  "configuration": {
    "cid": "string",
    "document": {},
    "schemaVersion": "string"
  },
  "configurationPinnedAt": "2025-01-01T00:00:00Z",
  "configurationPinnedByUserId": "string",
  "createdAt": "2025-01-01T00:00:00Z",
  "createdBy": "string",
  "createdByDid": "string",
  "createdByUserId": "string",
  "draftVersion": 0,
  "hasUnsubmittedChanges": true,
  "latestSubmission": {
    "controlCount": 0,
    "draftVersion": 0,
    "lastReviewedAt": "2025-01-01T00:00:00Z",
    "number": 0,
    "reviewedCount": 0,
    "status": "in_review",
    "submittedAt": "2025-01-01T00:00:00Z",
    "uuid": "string"
  },
  "observation": {
    "correlationId": "string",
    "observedAt": "2025-01-01T00:00:00Z",
    "request": {
      "model": "string",
      "provider": "string",
      "systemPromptCid": "string",
      "tools": [
        "string"
      ]
    },
    "stateCid": "string",
    "subAgent": "string",
    "viperVersion": "string"
  },
  "organizationId": 0,
  "profile": {
    "cid": "string",
    "document": {},
    "version": 0
  },
  "profilePinnedAt": "2025-01-01T00:00:00Z",
  "profilePinnedByUserId": "string",
  "programManifestCid": "string",
  "programSlug": "string",
  "programUuid": "string",
  "status": "draft",
  "uuid": "string"
}

400Bad request - Invalid request, or the agent's state cannot be pinned

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"
}

500Internal server error

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

503The agent registry is unavailable

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