---
title: Quickstart
description: Mint a sandbox key, trigger your first cascade and read the decision in under five minutes — with curl, Node, Python, Ruby or an MCP agent.
canonical_url: "https://cascades.crscreditapi.com/docs/quickstart"
doc_version: "1.0.0"
last_updated: "2026-10-08T16:52:14Z"
source: docs/quickstart.md.erb
---

# Quickstart

Five minutes from zero to a completed screening run. Everything below runs in **test mode**: synthetic report data, no bureau calls, no charges — and it works on draft cascades, so you do not need an activated account.


> **Signed in?**
>
> When you are signed in, every `{{API_KEY}}` on this site is replaced with a sandbox key minted for you, and the **Try it** panel on each endpoint runs the request against your own workspace.



### Mint a sandbox key

Open [/api-keys](/api-keys) and click **Generate key** (it reads **Regenerate key** when you already have one, and regenerating revokes the old key). The raw token is shown exactly once — copy it somewhere safe. Sandbox keys carry every scope (`workflows:read`, `workflows:write`, `executions:read`, `executions:read:full`, `executions:write`, `workflow_templates:read`, `webhooks:read`, `webhooks:write`) and expire after 90 days.

Send it as a bearer token on every request:

```http
Authorization: Bearer {{API_KEY}}
```

### Find a cascade to run

List the cascades in your workspace. If you have none yet, build one in the visual builder at [/cascades](/cascades), copy a [template](/docs/api/workflow-templates/list-workflow-templates), or [generate one from a sentence](/docs/guides/ai-generate-a-cascade).


**cURL**

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

**Node.js**

```javascript
const response = await fetch("https://cascades.crscreditapi.com/api/v1/workflows", {
  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",
    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")
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", 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 workflows and summarise the result."
# It will call the `cascades_list_workflows` tool with your key.
```


Note the `id` of the cascade you want — the examples below use `27`.

### Trigger a run

`POST /workflows/{id}/trigger` starts an execution. Three things matter:

- **`Idempotency-Key` is required.** Use something unique to the business event (an application id). Re-sending the same key and body returns the original execution instead of starting a second one.
- **`execution_mode` defaults to `test`.** Leave it there until your account is approved for live runs.
- **`external_reference`** is your own id; it comes back on the execution and on every webhook.


**cURL**

```shell
curl -X POST "https://cascades.crscreditapi.com/api/v1/workflows/27/trigger" \
  -H "Authorization: Bearer {{API_KEY}}" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 3fa85f64-5717-4562-b3fc-2c963f66afa6" \
  -d '{
    "payload": {
      "applicant": {
        "first_name": "Jordan",
        "last_name": "Lee",
        "email": "jordan@example.com"
      }
    },
    "execution_mode": "test",
    "external_reference": "rv-app-20491"
  }'
```

**Node.js**

```javascript
const response = await fetch("https://cascades.crscreditapi.com/api/v1/workflows/27/trigger", {
  method: "POST",
  headers: {
    "Authorization": "Bearer {{API_KEY}}",
    "Content-Type": "application/json",
    "Idempotency-Key": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  },
  body: JSON.stringify({
    "payload": {
      "applicant": {
        "first_name": "Jordan",
        "last_name": "Lee",
        "email": "jordan@example.com"
      }
    },
    "execution_mode": "test",
    "external_reference": "rv-app-20491"
  })
});

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

**Python**

```python
import requests

response = requests.post(
    "https://cascades.crscreditapi.com/api/v1/workflows/27/trigger",
    headers={
        "Authorization": "Bearer {{API_KEY}}",
        "Idempotency-Key": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    },
    json={
      "payload": {
        "applicant": {
          "first_name": "Jordan",
          "last_name": "Lee",
          "email": "jordan@example.com"
        }
      },
      "execution_mode": "test",
      "external_reference": "rv-app-20491"
    },
)
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/trigger")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer {{API_KEY}}"
request["Content-Type"] = "application/json"
request["Idempotency-Key"] = "3fa85f64-5717-4562-b3fc-2c963f66afa6"
request.body = <<~JSON
  {
    "payload": {
      "applicant": {
        "first_name": "Jordan",
        "last_name": "Lee",
        "email": "jordan@example.com"
      }
    },
    "execution_mode": "test",
    "external_reference": "rv-app-20491"
  }
JSON

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 (
	"bytes"
	"fmt"
	"io"
	"net/http"
)

func main() {
	body := []byte(`{
	  "payload": {
	    "applicant": {
	      "first_name": "Jordan",
	      "last_name": "Lee",
	      "email": "jordan@example.com"
	    }
	  },
	  "execution_mode": "test",
	  "external_reference": "rv-app-20491"
	}`)
	req, err := http.NewRequest("POST", "https://cascades.crscreditapi.com/api/v1/workflows/27/trigger", bytes.NewBuffer(body))
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer {{API_KEY}}")
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Idempotency-Key", "3fa85f64-5717-4562-b3fc-2c963f66afa6")

	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:
#   "Trigger a workflow 27 and summarise the result."
# It will call the `cascades_trigger_workflow` tool with your key.
```


The response is `202 Accepted` with the new execution — `status` will be `pending`, not the final answer.


> Try it in the browser: https://cascades.crscreditapi.com/docs/api/workflows/trigger-workflow — a signed-in sandbox key runs `POST /workflows/{id}/trigger` against the test identities.



### Poll for the decision

Cascades are asynchronous. Poll `GET /executions/{id}` every second or two until `status` leaves `pending` / `running` / `waiting` (`queued` only appears on batch child rows — see [Batches](/docs/concepts/batches)). Terminal statuses are `completed`, `failed`, `cancelled` and `skipped`; `awaiting_review` means a person has to decide (see [Handle human review](/docs/guides/handle-human-review)).


**cURL**

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

**Node.js**

```javascript
const response = await fetch("https://cascades.crscreditapi.com/api/v1/executions/1842", {
  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/executions/1842",
    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/executions/1842")
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/executions/1842", 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:
#   "Show an execution 1842 and summarise the result."
# It will call the `cascades_get_execution` tool with your key.
```


With `executions:read:full` the payload also carries `step_outputs` — the per-node results, including the report data the decision was made on — and `failed_steps`.

### Stop polling: subscribe to webhooks

Polling is fine for a first run; in production subscribe once and let Cascades call you. `POST /webhook_subscriptions` returns a `signing_secret` exactly once. Every delivery is signed; verify it before trusting the payload.


**cURL**

```shell
curl -X POST "https://cascades.crscreditapi.com/api/v1/webhook_subscriptions" \
  -H "Authorization: Bearer {{API_KEY}}" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://hooks.partner.example/cascades",
    "event_filter": [
      "execution.completed",
      "execution.failed",
      "adverse_action.completed"
    ]
  }'
```

**Node.js**

```javascript
const response = await fetch("https://cascades.crscreditapi.com/api/v1/webhook_subscriptions", {
  method: "POST",
  headers: {
    "Authorization": "Bearer {{API_KEY}}",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "url": "https://hooks.partner.example/cascades",
    "event_filter": [
      "execution.completed",
      "execution.failed",
      "adverse_action.completed"
    ]
  })
});

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

**Python**

```python
import requests

response = requests.post(
    "https://cascades.crscreditapi.com/api/v1/webhook_subscriptions",
    headers={
        "Authorization": "Bearer {{API_KEY}}",
    },
    json={
      "url": "https://hooks.partner.example/cascades",
      "event_filter": [
        "execution.completed",
        "execution.failed",
        "adverse_action.completed"
      ]
    },
)
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/webhook_subscriptions")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer {{API_KEY}}"
request["Content-Type"] = "application/json"
request.body = <<~JSON
  {
    "url": "https://hooks.partner.example/cascades",
    "event_filter": [
      "execution.completed",
      "execution.failed",
      "adverse_action.completed"
    ]
  }
JSON

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 (
	"bytes"
	"fmt"
	"io"
	"net/http"
)

func main() {
	body := []byte(`{
	  "url": "https://hooks.partner.example/cascades",
	  "event_filter": [
	    "execution.completed",
	    "execution.failed",
	    "adverse_action.completed"
	  ]
	}`)
	req, err := http.NewRequest("POST", "https://cascades.crscreditapi.com/api/v1/webhook_subscriptions", bytes.NewBuffer(body))
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer {{API_KEY}}")
	req.Header.Set("Content-Type", "application/json")

	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:
#   "Create a webhook subscription using the Cascades API."
# No MCP tool covers this endpoint yet; the assistant can call POST /webhook_subscriptions with curl.
```


See [Webhooks](/docs/concepts/webhooks) for the event catalog and [Verify webhook signatures](/docs/guides/verify-webhooks) for drop-in verifiers.


## Prefer to let an agent do it?

Install the MCP server and ask your assistant in plain English. The server wraps the same endpoints with the same key and scopes.



```bash
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: *"List my cascades, run cascade 27 for a registered test subject in test mode, and explain the decision."* Details and per-client install pages are under [MCP server](/docs/mcp).

## What next?

- [Your first screening](/docs/guides/first-screening) — the full flow with a test identity, a chosen mock outcome, human review and adverse action.
- [Sandbox vs live](/docs/concepts/sandbox-vs-live) — what changes when you flip `execution_mode`.
- [API reference](/docs/api) — every endpoint with request and response schemas.

## Sitemap

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