Skip to main content

API Reference

TestPlanIt provides a comprehensive RESTful API for programmatic access to all test management functionality. The API uses ZenStack-generated endpoints with built-in type safety, authentication, and row-level security.

Interactive API Documentation​

TestPlanIt includes interactive Swagger UI documentation for exploring and testing the API:

Access the API documentation at: /docs/api in your TestPlanIt instance

The interactive documentation is organized into categories:

CategoryDescription
Custom API EndpointsAuthentication, file uploads, JUnit imports, search, and admin endpoints
Projects & FoldersProject and folder management
Test Cases & RepositoryTest case management, steps, templates, and custom fields
Test Runs & ExecutionTest run management, sessions, and execution tracking
Planning & OrganizationMilestones, configurations, tags, workflows, and statuses
Users & AccountsUser management, roles, groups, and account settings
Integrations & SSOExternal integrations, SSO, and AI/LLM features
Attachments & OtherFile attachments, comments, and imports

Overview​

The API provides:

  • RESTful endpoints for all entities and operations
  • Type-safe requests with automatic validation
  • Row-level security based on user permissions
  • Authentication via NextAuth.js sessions
  • Rate limiting and security measures
  • OpenAPI 3.0 specification for documentation and client generation

OpenAPI Specification​

The OpenAPI specification is available programmatically:

# Get list of API categories
curl https://your-domain.com/api/docs

# Get OpenAPI spec for a specific category
curl https://your-domain.com/api/docs?category=custom
curl https://your-domain.com/api/docs?category=projects
curl https://your-domain.com/api/docs?category=testCases
curl https://your-domain.com/api/docs?category=testRuns
curl https://your-domain.com/api/docs?category=planning
curl https://your-domain.com/api/docs?category=users
curl https://your-domain.com/api/docs?category=integrations
curl https://your-domain.com/api/docs?category=other

You can use these specifications to:

  • Generate API clients in any language
  • Import into tools like Postman or Insomnia
  • Build custom integrations

Authentication​

TestPlanIt supports two authentication methods:

  1. API Tokens - For programmatic access (CLI, CI/CD, scripts)
  2. Session-Based - For browser-based requests

API tokens provide persistent authentication for server-to-server integrations, CLI tools, and automated workflows.

curl -G "https://your-domain.com/api/model/projects/findMany" \
-H "Authorization: Bearer tpi_your_token_here" \
--data-urlencode 'q={"where": {"isDeleted": false}}'
const q = encodeURIComponent(JSON.stringify({ where: { isDeleted: false } }));
const response = await fetch(`/api/model/projects/findMany?q=${q}`, {
headers: {
'Authorization': 'Bearer tpi_your_token_here'
}
});

To create and manage API tokens, see the API Tokens documentation.

Session-Based Authentication​

For browser-based requests, TestPlanIt uses NextAuth.js session cookies. Authentication is handled automatically:

// Fetch with automatic session handling
const q = encodeURIComponent(JSON.stringify({ where: { isDeleted: false } }));
const response = await fetch(`/api/model/projects/findMany?q=${q}`, {
credentials: 'include' // Include session cookies
});

Base URL and Endpoints​

Base URL: https://your-domain.com/api

ZenStack Model Endpoints​

ZenStack generates RESTful endpoints for all data models:

Model names are camelCase and match the schema (for example projects, repositoryCases, testRuns, issue). Read operations are GET requests with a URL-encoded q query parameter; write operations send a JSON body.

GET /api/model/{model}/findMany - List records with filtering
GET /api/model/{model}/findUnique - Get a single record by unique key
GET /api/model/{model}/findFirst - Get the first matching record
GET /api/model/{model}/count - Count records
GET /api/model/{model}/aggregate - Aggregate operations
GET /api/model/{model}/groupBy - Group records by fields
POST /api/model/{model}/create - Create a record
POST /api/model/{model}/createMany - Create several records
POST /api/model/{model}/upsert - Create or update a record
PATCH /api/model/{model}/update - Update a record (PUT also accepted)
PATCH /api/model/{model}/updateMany - Update matching records
DELETE /api/model/{model}/delete - Delete a record
DELETE /api/model/{model}/deleteMany - Delete matching records

Custom Endpoints​

Additional endpoints for specialized operations:

/api/junit/import - Import JUnit XML test results
/api/test-results/import - Import JUnit/TestNG/xUnit/NUnit/MSTest/Mocha/Cucumber results
/api/test-runs/{id}/automation-plan - Plan of a run's automated cases (GET)
/api/test-runs/{id}/execute - Dispatch a run's automated cases to a target (POST)
/api/test-runs/{id}/executions - Dispatch history (GET); /{eid}/cancel, /{eid}/finish (POST)
/api/projects/{id}/execute-cases - Ad-hoc execution of automated cases (POST)
/api/projects/{id}/execution-targets - Sanitized list of a project's execution targets (GET)
/api/search - Full-text search
/api/files/upload - File uploads
/api/admin/* - Administrative operations

Common Operations​

Querying Data​

All ZenStack endpoints support Prisma-style query parameters:

// Find all projects with filtering and includes
const query = {
where: {
name: { contains: 'Test' }
},
include: {
repositories: true,
assignedUsers: {
include: { user: true }
}
},
orderBy: { createdAt: 'desc' },
take: 10,
skip: 0
};
const response = await fetch(
`/api/model/projects/findMany?q=${encodeURIComponent(JSON.stringify(query))}`,
{ credentials: 'include' }
);

Creating Records​

// Create a new test case
const response = await fetch('/api/model/repositoryCases/create', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({
data: {
name: 'Login Test',
project: { connect: { id: projectId } },
repository: { connect: { id: repositoryId } },
folder: { connect: { id: folderId } },
template: { connect: { id: templateId } },
state: { connect: { id: stateId } },
creator: { connect: { id: userId } }
}
})
});

Updating Records​

// Update a test case
const response = await fetch('/api/model/repositoryCases/update', {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({
where: { id: caseId },
data: {
name: 'Updated Name'
}
})
});

Deleting Records​

// Delete a test case
const q = encodeURIComponent(JSON.stringify({ where: { id: caseId } }));
const response = await fetch(`/api/model/repositoryCases/delete?q=${q}`, {
method: 'DELETE',
credentials: 'include'
});

JUnit Import API​

Import JUnit XML test results to create test runs with test cases:

curl -X POST "https://your-domain.com/api/junit/import" \
-H "Authorization: Bearer tpi_your_token_here" \
-F "name=My Test Run" \
-F "projectId=1" \
-F "files=@/path/to/junit-results.xml" \
-F "stateId=5" \
-F "parentFolderId=10" \
-F "configId=2" \
-F "milestoneId=3" \
-F "tagIds=1" \
-F "tagIds=2"

Parameters:

ParameterRequiredDescription
nameYesName for the test run
projectIdYesProject ID
filesYesOne or more JUnit XML files
stateIdNoWorkflow state ID for the test run
parentFolderIdNoFolder ID for storing test cases
testRunIdNoExisting test run ID to append results to
configIdNoConfiguration ID
milestoneIdNoMilestone ID
tagIdsNoTag IDs (repeat for multiple)

Response:

The API returns a Server-Sent Events (SSE) stream with progress updates:

data: {"progress": 10, "status": "Validating input..."}
data: {"progress": 50, "status": "Processing test case 25 of 50..."}
data: {"progress": 100, "status": "Import completed!"}
data: {"complete": true, "testRunId": 456}

Error Handling​

All API endpoints return consistent error responses:

{
"error": "Error message",
"code": "ERROR_CODE",
"details": {}
}

Common HTTP Status Codes​

StatusDescription
200Success
201Created
400Bad Request - Invalid parameters
401Unauthorized - Not authenticated
403Forbidden - Insufficient permissions
404Not Found
500Internal Server Error

Rate Limiting​

TestPlanIt enforces a global hourly rate limit on all authenticated API requests. The limit applies per instance (not per token or per user) and resets on the hour.

Tier Limits​

The TIER environment variable selects the hourly limit:

TierHourly LimitTypical Use
essentials1,000 requests/hourSmall teams, light CI/CD integration
team5,000 requests/hourMid-size teams with moderate automation
professional (default)10,000 requests/hourMost production deployments
dedicated25,000 requests/hourHeavy CI/CD workloads, large organizations

When the limit is exceeded, requests return HTTP 429 with a Retry-After header indicating seconds until the window resets.

Custom Limit (Self-Hosted)​

Self-hosted instances aren't bound by the tier presets. Set API_RATE_LIMIT to an explicit hourly limit (a positive integer) to override TIER:

API_RATE_LIMIT=100000

When set, it takes precedence over TIER. Invalid values (non-integers, zero, or negative numbers) are ignored with a warning and the TIER preset applies instead. To remove rate limiting entirely, see Disabling Rate Limiting below.

Response Headers​

Every API response includes the following headers:

HeaderDescription
X-RateLimit-LimitMaximum requests allowed in the current hour
X-RateLimit-RemainingRequests remaining in the current window
X-RateLimit-ResetUnix timestamp (seconds) when the window resets

Implementation​

Rate limiting uses a Valkey-backed fixed-window counter aligned to hourly boundaries. If Valkey is unavailable, TestPlanIt falls back to in-memory counting (per-instance).

Disabling Rate Limiting (Load Testing Only)​

For isolated load-testing or development environments, you can disable rate limiting entirely by setting:

DISABLE_API_RATE_LIMIT=true
warning

Never enable DISABLE_API_RATE_LIMIT in production. This bypasses a key protection against abuse and accidental resource exhaustion. It is intended only for isolated test environments where you're intentionally probing throughput limits.

When set, all authenticated requests are allowed through regardless of request volume. The X-RateLimit-* headers still report the configured tier's limit, but the counter never increments and 429 responses are never returned.

Further Resources​

  • Interactive Documentation: Access /docs/api in your TestPlanIt instance
  • OpenAPI Spec: Available at /api/docs?category={category}
  • CLI Tool: See the CLI documentation for importing test results from CI/CD pipelines
  • API Tokens: See the API Tokens documentation for managing programmatic access
  • ZenStack Documentation (v2): zenstack.dev