Skip to main content

Overview

The Preclinical API enables programmatic access to:
  • Start and monitor test runs
  • Manage AI agents
  • Retrieve detailed test results
  • Integrate with CI/CD pipelines

Base URL

https://app.preclinical.dev/api/v1
All API endpoints are relative to this base URL.

Authentication

All API requests require authentication using an API key. Include your key in the Authorization header:
Authorization: Bearer sk_live_your_api_key_here
Create API keys in Settings > API Keys. See the API Keys guide for details.

Example Request

curl -X GET https://app.preclinical.dev/api/v1/runs \
  -H "Authorization: Bearer sk_live_your_api_key_here"

Endpoints

Runs

MethodEndpointDescription
POST/runsStart a new test run
GET/runsList all test runs
GET/runs/{id}Get run status and summary
GET/runs/{id}/resultsGet detailed results with scenarios
POST/runs/{id}/cancelCancel an in-progress run

Agents

MethodEndpointDescription
GET/agentsList all agents
POST/agentsCreate a new agent
GET/agents/{id}Get agent details
PUT/agents/{id}Update an agent
DELETE/agents/{id}Delete an agent
POST/agents/{id}/validateValidate agent connectivity

Test Suites

MethodEndpointDescription
GET/test-suitesList all test suites
POST/test-suitesCreate a new test suite

Response Format

All responses are JSON. Successful responses return the requested data directly:
{
  "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "status": "completed",
  "pass_rate": 85.0
}

Error Responses

Errors return a consistent format:
{
  "error": "Agent not found",
  "code": "AGENT_NOT_FOUND"
}

Common Error Codes

HTTP StatusDescription
400Bad request - validation failed
401Unauthorized - invalid or missing API key
403Forbidden - access denied
404Not found - resource doesn’t exist
409Conflict - resource state conflict
429Rate limited - too many requests
500Server error

Pagination

List endpoints support pagination using limit and offset query parameters.

Example

# Get items 21-40
curl "https://app.preclinical.dev/api/v1/runs?limit=20&offset=20" \
  -H "Authorization: Bearer $API_KEY"

Quick Example

Start a test run and poll for results:
# Start a test run
RESPONSE=$(curl -s -X POST https://app.preclinical.dev/api/v1/runs \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"agent_id": "your-agent-uuid"}')

RUN_ID=$(echo $RESPONSE | jq -r '.id')
echo "Started run: $RUN_ID"

# Poll for completion
while true; do
  STATUS=$(curl -s "https://app.preclinical.dev/api/v1/runs/$RUN_ID" \
    -H "Authorization: Bearer $API_KEY" | jq -r '.status')

  echo "Status: $STATUS"

  if [ "$STATUS" = "completed" ] || [ "$STATUS" = "failed" ]; then
    break
  fi

  sleep 5
done

# Get detailed results
curl -s "https://app.preclinical.dev/api/v1/runs/$RUN_ID/results" \
  -H "Authorization: Bearer $API_KEY" | jq

SDKs

JavaScript/TypeScript

const API_KEY = process.env.PRECLINICAL_API_KEY;
const BASE_URL = 'https://app.preclinical.dev/api/v1';

async function startRun(agentId: string) {
  const response = await fetch(`${BASE_URL}/runs`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ agent_id: agentId }),
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.error);
  }

  return response.json();
}

async function getRun(runId: string) {
  const response = await fetch(`${BASE_URL}/runs/${runId}`, {
    headers: { 'Authorization': `Bearer ${API_KEY}` },
  });

  return response.json();
}

Python

import requests
import os

API_KEY = os.environ['PRECLINICAL_API_KEY']
BASE_URL = 'https://app.preclinical.dev/api/v1'

def start_run(agent_id: str) -> dict:
    response = requests.post(
        f'{BASE_URL}/runs',
        headers={'Authorization': f'Bearer {API_KEY}'},
        json={'agent_id': agent_id}
    )
    response.raise_for_status()
    return response.json()

def get_run(run_id: str) -> dict:
    response = requests.get(
        f'{BASE_URL}/runs/{run_id}',
        headers={'Authorization': f'Bearer {API_KEY}'}
    )
    response.raise_for_status()
    return response.json()

Next Steps