Skip to content

Quickstart

Getting started

Start with the customer Organization and ServicePrincipal credential Cantora issued. These requests create a Project and Test Environment, publish one immutable Agent Version, provision its Agent, and activate the first Test Agent Release.

Before you begin

Install curl and jq. You need the identifier of your existing Organization and an API key whose ServicePrincipal has authority to create the resources below. This customer workflow begins after Cantora has provisioned both; it does not run platform bootstrap.

These commands use Bash. Start a Bash session in this terminal and keep it open for every command below. Then enter the credential at a hidden prompt so its literal value does not enter shell history. Keep the key out of source code, Agent Configuration, command output, and logs.

TerminalStart and retain a Bash session
bash
Terminal
read -rsp "Cantora API key: " CANTORA_API_KEY
printf '\n'
read -rp "Cantora Organization ID: " CANTORA_ORGANIZATION_ID
export CANTORA_API_KEY CANTORA_ORGANIZATION_ID
export CANTORA_API_ORIGIN="https://api.cantora.ai"
TerminalConfirm the ServicePrincipal and Organization before writing
curl --fail-with-body --silent --show-error \
  "${CANTORA_API_ORIGIN}/v1/identity" \
  --header "Authorization: Bearer ${CANTORA_API_KEY}" | jq

1. Create a Project and Test Environment

A Project owns the Agent Definition and its immutable versions. The environments field creates the Test Environment in the same authorized operation.

Terminal201 Created; saves projectId
PROJECT_RESPONSE=$(curl --fail-with-body --silent --show-error \
  "${CANTORA_API_ORIGIN}/v1/organizations/${CANTORA_ORGANIZATION_ID}/projects" \
  --header "Authorization: Bearer ${CANTORA_API_KEY}" \
  --header "Content-Type: application/json" \
  --data @- <<'JSON'
{
  "name": "Customer support",
  "environments": [
    "test"
  ]
}
JSON
)
export CANTORA_PROJECT_ID=$(printf '%s' "${PROJECT_RESPONSE}" | jq -er '.projectId')
printf '%s\n' "${PROJECT_RESPONSE}" | jq

List the Project's Environments to capture the generated Test identifier. The response is an array; select the member whose name is test.

Terminal200 OK; saves environmentId
ENVIRONMENTS_RESPONSE=$(curl --fail-with-body --silent --show-error \
  "${CANTORA_API_ORIGIN}/v1/organizations/${CANTORA_ORGANIZATION_ID}/projects/${CANTORA_PROJECT_ID}/environments" \
  --header "Authorization: Bearer ${CANTORA_API_KEY}")
export CANTORA_ENVIRONMENT_ID=$(printf '%s' "${ENVIRONMENTS_RESPONSE}" | \
  jq -er '.[] | select(.name == "test") | .environmentId')
printf '%s\n' "${ENVIRONMENTS_RESPONSE}" | jq

2. Create the Agent Definition

The key is stable across Environments and versions. The response records ApiManaged as the configuration authority and returns the Agent Definition identifier used by every later step.

Terminal201 Created; saves agentDefinitionId
DEFINITION_RESPONSE=$(curl --fail-with-body --silent --show-error \
  "${CANTORA_API_ORIGIN}/v1/organizations/${CANTORA_ORGANIZATION_ID}/projects/${CANTORA_PROJECT_ID}/agent-definitions" \
  --header "Authorization: Bearer ${CANTORA_API_KEY}" \
  --header "Content-Type: application/json" \
  --data @- <<'JSON'
{
  "key": "support-agent",
  "displayName": "Support Agent"
}
JSON
)
export CANTORA_AGENT_DEFINITION_ID=$(printf '%s' "${DEFINITION_RESPONSE}" | jq -er '.agentDefinitionId')
printf '%s\n' "${DEFINITION_RESPONSE}" | jq

3. Publish an immutable Agent Version

The manifest declares complete behavior and finite budgets. The source object is visibly synthetic in this example; replace it with your repository, reviewed commit, configuration path, workflow, and run identifiers. It contains provenance, never a credential.

Terminal200 OK; saves version.agentVersionId
VERSION_RESPONSE=$(curl --fail-with-body --silent --show-error \
  "${CANTORA_API_ORIGIN}/v1/organizations/${CANTORA_ORGANIZATION_ID}/projects/${CANTORA_PROJECT_ID}/agent-definitions/${CANTORA_AGENT_DEFINITION_ID}/versions" \
  --header "Authorization: Bearer ${CANTORA_API_KEY}" \
  --header "Content-Type: application/json" \
  --data @- <<'JSON'
{
  "manifest": {
    "schemaVersion": "config.cantora.ai/agent-version/v1alpha2",
    "instructions": "Answer support questions using the approved knowledge sources and cite the evidence used.",
    "model": {
      "provider": "googleVertex",
      "model": "gemini-3.6-flash",
      "settings": {
        "thinkingLevel": "low"
      }
    },
    "tools": [],
    "requiredBindings": [],
    "budgets": {
      "maxModelSteps": 12,
      "maxToolCalls": 0,
      "totalWallTimeMs": 240000,
      "modelStepTimeMs": 90000,
      "streamStallTimeMs": 15000,
      "maxInputTokens": 100000,
      "maxOutputTokens": 16000,
      "maxReasoningTokens": 32000,
      "maxTotalTokens": 140000,
      "maxToolResultBytes": 1000000,
      "maxEstimatedCostMicros": 5000000
    }
  },
  "source": {
    "repository": "example.invalid/acme/support-agent",
    "commit": "0000000000000000000000000000000000000000",
    "path": "cantora/support-agent.json",
    "workflow": "publish-support-agent",
    "run": "example-1"
  }
}
JSON
)
export CANTORA_AGENT_VERSION_ID=$(printf '%s' "${VERSION_RESPONSE}" | jq -er '.version.agentVersionId')
printf '%s\n' "${VERSION_RESPONSE}" | jq

The response outcome is created for new content or reused when the normalized manifest already exists. Both outcomes return the exact immutable version.

4. Provision the Test Agent

The Environment Agent is the runtime principal for this Agent Definition in Test. It begins at release generation zero with no current Agent Release, and the response includes the ETag required for activation.

Terminal201 Created; saves principalId and releaseEtag
AGENT_RESPONSE=$(curl --fail-with-body --silent --show-error \
  "${CANTORA_API_ORIGIN}/v1/organizations/${CANTORA_ORGANIZATION_ID}/projects/${CANTORA_PROJECT_ID}/environments/${CANTORA_ENVIRONMENT_ID}/agents" \
  --header "Authorization: Bearer ${CANTORA_API_KEY}" \
  --header "Content-Type: application/json" \
  --data @- <<JSON
{
  "agentDefinitionId": "${CANTORA_AGENT_DEFINITION_ID}"
}
JSON
)
export CANTORA_AGENT_PRINCIPAL_ID=$(printf '%s' "${AGENT_RESPONSE}" | jq -er '.principalId')
export CANTORA_AGENT_RELEASE_ETAG=$(printf '%s' "${AGENT_RESPONSE}" | jq -er '.releaseEtag')
printf '%s\n' "${AGENT_RESPONSE}" | jq

5. Activate the first Test Agent Release

Activation is an optimistic-concurrency-protected operation. If-Match carries the current ETag, and the body selects the immutable Agent Version with a durable reason and source record.

Terminal200 OK; returns release generation 1
RELEASE_RESPONSE=$(curl --fail-with-body --silent --show-error \
  "${CANTORA_API_ORIGIN}/v1/organizations/${CANTORA_ORGANIZATION_ID}/projects/${CANTORA_PROJECT_ID}/environments/${CANTORA_ENVIRONMENT_ID}/agents/${CANTORA_AGENT_PRINCIPAL_ID}/releases" \
  --header "Authorization: Bearer ${CANTORA_API_KEY}" \
  --header "Content-Type: application/json" \
  --header "If-Match: ${CANTORA_AGENT_RELEASE_ETAG}" \
  --data @- <<JSON
{
  "agentVersionId": "${CANTORA_AGENT_VERSION_ID}",
  "reason": "Activate the first tested support Agent Version.",
  "source": {
    "repository": "example.invalid/acme/support-agent",
    "commit": "0000000000000000000000000000000000000000",
    "path": "cantora/support-agent.json",
    "workflow": "publish-support-agent",
    "run": "example-1"
  }
}
JSON
)
printf '%s\n' "${RELEASE_RESPONSE}" | jq

The returned release is append-only and affects new work only. This quickstart stops after Test activation; it does not claim or execute a Live promotion.

Next steps

  • Read Agent Configuration before changing the manifest or activating another version.
  • Use the API reference for complete schemas, constraints, and responses.
  • Follow Errors when a request returns a validation, authority, conflict, or precondition failure.

Remove the key from the local environment when finished: unset CANTORA_API_KEY.