---
title: List sandbox test cases for a workflow — GET /api/v1/workflows/{id}/test_cases
description: The synthetic subjects registered in the CRS Testcase Service for this cascade's product nodes (credit, criminal, eviction …).
canonical_url: "https://cascades.crscreditapi.com/docs/api/workflows/list-workflow-test-cases"
doc_version: "1.0.0"
last_updated: "2026-10-09T18:04:24Z"
source: "public/api-docs/v1/swagger.yaml#listWorkflowTestCases"
---

# List sandbox test cases for a workflow — GET /api/v1/workflows/{id}/test_cases

`GET https://cascades.crscreditapi.com/api/v1/workflows/{id}/test_cases`

- Operation id: `listWorkflowTestCases`
- Scopes: `workflows:read`
- Idempotent: no
- MCP tool: `cascades_list_test_cases`
- OpenAPI: https://cascades.crscreditapi.com/openapi.json · https://cascades.crscreditapi.com/openapi.yaml (operationId `listWorkflowTestCases`)

The synthetic subjects registered in the CRS Testcase Service for
this cascade's product nodes (credit, criminal, eviction …). Each
carries a ready-to-run `payload` shaped for `triggerWorkflow`, so a
test-mode run needs no hand-written applicant data. A test-mode
trigger for a subject registered for every product node in the
cascade replays its authored bureau responses at no charge
(`input_context.sandbox_replay` is `true`); a subject that covers
only some of the products gets schema mocks like any other applicant
(set `payload.scenario` to `fail_path` to exercise decline branches).
Live-mode sandbox runs replay registered subjects too.
A credit case's own criteria carry only name and SSN, so blank
fields (`dob`, the `property` address) are filled from the same
subject's other registry cases, such as its criminal or eviction
case, whichever products the cascade uses. Without them CRS refuses
the credit order.
Only the cases authored for Cascades (`case_name` starts with
`Cascades_`) are listed. The registry's other fixtures mostly lack the
first name and address CRS needs, so their runs would fail at the
credit step.
Best-effort: an unreachable registry yields an empty list, never a
5xx. Results are cached for a few minutes. Requires `workflows:read`.

## Path parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `id` | integer | yes | Workflow id. Only workflows owned by the token's account resolve; a foreign or deleted id returns 404. |

## Responses

### 200 — Test-case list (not paginated)

`application/json`

| Field | Type | Required | Description |
|---|---|---|---|
| `data` | TestCaseList | no |  |
| &nbsp;&nbsp;`object` | string | no |  One of: `"test_case_list"`. |
| &nbsp;&nbsp;`workflow_id` | integer | no |  |
| &nbsp;&nbsp;`test_cases` | array of TestCase | no |  |
| &nbsp;&nbsp;&nbsp;&nbsp;`id` | integer | no | The subject id in the CRS Testcase registry. |
| &nbsp;&nbsp;&nbsp;&nbsp;`case_name` | string | no |  |
| &nbsp;&nbsp;&nbsp;&nbsp;`product_code` | string | no | The billing product code this subject was registered for. |
| &nbsp;&nbsp;&nbsp;&nbsp;`payload` | object | no | Drop-in body for `triggerWorkflow` (`payload.applicant` and, when the subject carries one, `payload.property`). |
| &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`applicant` | ApplicantPayload | no | Free-form applicant data forwarded to the workflow's first node as `context.applicant`. Field names depend on the workflow definition. |
| &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`property` | object | no | Property / tenancy details when the subject was registered with them. |
| `meta` | Meta | no |  |
| &nbsp;&nbsp;`request_id` | string | yes | Correlation id for this request. Also sent as the `X-Request-Id` response header; quote it when contacting support. |

```json
{
  "data": {
    "object": "test_case_list",
    "workflow_id": 27,
    "test_cases": [
      {
        "id": 73,
        "case_name": "Cascades_XProduct_Approve_EFX",
        "product_code": "EQF1003",
        "payload": {
          "applicant": {
            "first_name": "AVERY",
            "last_name": "CLARKSON",
            "middle_name": "",
            "name": "AVERY CLARKSON",
            "email": "avery.clarkson@example.com",
            "phone": "",
            "ssn": "666900001",
            "dob": "1982-01-01"
          },
          "property": {
            "address": "1803 Norma",
            "unit": "",
            "city": "Cottonwood",
            "state": "CA",
            "zip": "91502",
            "full_address": "1803 Norma, Cottonwood, CA 91502"
          }
        }
      }
    ]
  },
  "meta": {
    "request_id": "7d4c2f48-9a1b-4c3d-8e2f-1a2b3c4d5e6f"
  }
}
```

### 401 — Missing, malformed, expired or revoked bearer token. The `WWW-Authenticate` header carries the RFC 6750 challenge.

`application/json` — `ErrorEnvelope`

```json
{
  "error": {
    "code": "unauthorized",
    "message": "A valid bearer token is required.",
    "details": [],
    "request_id": "7d4c2f48-9a1b-4c3d-8e2f-1a2b3c4d5e6f",
    "doc_url": "https://cascades.crscreditapi.com/docs/api/errors/unauthorized"
  }
}
```

### 403 — Token does not hold the required scope. `details` lists the scope(s) that were checked.

`application/json` — `ErrorEnvelope`

```json
{
  "error": {
    "code": "insufficient_scope",
    "message": "This token does not have the required scope.",
    "details": [
      {
        "field": "scope",
        "message": "executions:write"
      }
    ],
    "request_id": "7d4c2f48-9a1b-4c3d-8e2f-1a2b3c4d5e6f",
    "doc_url": "https://cascades.crscreditapi.com/docs/api/errors/insufficient_scope"
  }
}
```

### 404 — Resource does not exist or belongs to another tenant / api_client

`application/json` — `ErrorEnvelope`

```json
{
  "error": {
    "code": "not_found",
    "message": "The requested resource was not found.",
    "details": [],
    "request_id": "7d4c2f48-9a1b-4c3d-8e2f-1a2b3c4d5e6f",
    "doc_url": "https://cascades.crscreditapi.com/docs/api/errors/not_found"
  }
}
```

### 429 — Rate limit exceeded (60 req/min per IP on `/api/v1`, 600 req/hour
per token prefix, or 300 req/5 min per IP globally). The body is the
standard error envelope and `Retry-After` gives the seconds until
the window resets.


`application/json` — `ErrorEnvelope`

```json
{
  "error": {
    "code": "rate_limited",
    "message": "Rate limit exceeded. Retry later.",
    "details": [],
    "request_id": "7d4c2f48-9a1b-4c3d-8e2f-1a2b3c4d5e6f",
    "doc_url": "https://cascades.crscreditapi.com/docs/api/errors/rate_limited"
  }
}
```

## Code samples

### cURL

```shell
curl "https://cascades.crscreditapi.com/api/v1/workflows/27/test_cases" \
  -H "Authorization: Bearer {{API_KEY}}"
```

### Node.js

```javascript
const response = await fetch("https://cascades.crscreditapi.com/api/v1/workflows/27/test_cases", {
  method: "GET",
  headers: {
    "Authorization": "Bearer {{API_KEY}}"
  }
});

const { data, meta } = await response.json();
console.log(response.status, data, meta.request_id);
```

### Python

```python
import requests

response = requests.get(
    "https://cascades.crscreditapi.com/api/v1/workflows/27/test_cases",
    headers={
        "Authorization": "Bearer {{API_KEY}}",
    },
)
response.raise_for_status()
payload = response.json()
print(payload["data"], payload["meta"]["request_id"])
```

### Ruby

```ruby
require "net/http"
require "json"

uri = URI("https://cascades.crscreditapi.com/api/v1/workflows/27/test_cases")
request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer {{API_KEY}}"

response = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") do |http|
  http.request(request)
end
payload = JSON.parse(response.body)
puts payload["data"], payload.dig("meta", "request_id")
```

### Go

```go
package main

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

func main() {
	req, err := http.NewRequest("GET", "https://cascades.crscreditapi.com/api/v1/workflows/27/test_cases", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer {{API_KEY}}")

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

	out, _ := io.ReadAll(resp.Body)
	fmt.Println(resp.StatusCode, string(out))
}
```

### Agent

```shell
claude mcp add cascades \
  -e CASCADES_API_KEY={{API_KEY}} \
  -e CASCADES_PROD_BASE_URL=https://cascades.crscreditapi.com \
  -- npx -y @crscreditapi/cascades-mcp-server

# Then ask your assistant:
#   "List sandbox test cases for a workflow 27 and summarise the result."
# It will call the `cascades_list_test_cases` tool with your key.
```

## Related

- [Test identities](https://cascades.crscreditapi.com/docs/sandbox/test-identities)
- [Your first screening](https://cascades.crscreditapi.com/docs/guides/first-screening)

## Sitemap

See the full [sitemap](https://cascades.crscreditapi.com/sitemap.md) for all pages.
