> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cybr.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> These docs cover learner integrations through Hosted Lab Pages, the SDK, and the REST API. Content management is outside this integration scope.
> Read the setup page for the chosen approach before implementing it. Keep organization API keys and hosted mint secrets on the server.
> The public SDK is coming soon. Check the SDK quickstart for current availability. Do not invent installation commands or direct readers to a private package.
> Cybr provides completion tracking and CTF verification. The integrating platform decides whether to award points.

# Labs and deployments

> Named SDK methods, request fields, and matching REST operations.

All methods on this page run on the server. The [terminal browser helper](/reference/terminal) has a separate entry point.

## Labs

| SDK method | Return type | REST operation |
| - | - | - |
| `labs.list()` | `Promise<Lab[]>` | [List labs](/api-reference/list-labs) |
| `labs.get(labId, { learnerId? })` | `Promise<LabDetails>` | [Get lab](/api-reference/get-lab) |
| `labs.submitFlag({ labId, learnerId, flag })` | `Promise<FlagSubmission>` | [Submit flag](/api-reference/submit-flag) |
| `labs.submitGuideAnswer({ labId, taskId, answer, learnerId? })` | `Promise<GuideAnswerResult>` | [Grade answer](/api-reference/grade-answer) |
| `labs.markCompleted({ labId, learnerId })` | `Promise<MarkCompletedResponse>` | [Record completion](/api-reference/record-completion) |
| `labs.listComments({ labId, learnerId, cursor?, limit? })` | `Promise<LabCommentsPage>` | [List comments](/api-reference/list-comments) |
| `labs.createComment({ labId, learnerId, body, displayName?, parentId? })` | `Promise<LabCommentView>` | [Create comment](/api-reference/create-comment) |
| `labs.deleteComment({ labId, commentId, learnerId })` | `Promise<{ ok: true, deletedCount: number }>` | [Delete comment](/api-reference/delete-comment) |

`submitFlag()` and `submitGuideAnswer()` return `{ correct, verdict }`. The REST responses use `{ message }` for those verdicts.

`markCompleted()` returns `{ message: 'COMPLETED' }`. The [completion guide](/guides/completion-and-scoring) explains verification and duplicate results.

## Lab content types

`Lab` contains identity, name, description, provider, time limit, membership tier, and content indicators. `provider` is `aws` or `azure`.

`LabDetails` adds learner completion and the guide, resources, diagrams, videos, and other optional content. List and detail fields can differ.

The package exports `LabGuide`, `GuideTask`, `GuideQuestion`, `LabResourceLink`, `LabDiagram`, and `LabVideo`. The [content guide](/guides/lab-guides-and-ctf) explains their use.

## Discussions

The SDK sends `learnerId` through the `x-cybr-learner-id` header. Your server resolves that ID from the learner session.

```ts theme={null}
const page = await cybr.labs.listComments({ labId, learnerId, limit: 20 })
const comment = await cybr.labs.createComment({
  labId,
  learnerId,
  body: 'How did you approach this step?'
})
await cybr.labs.deleteComment({ labId, learnerId, commentId: comment.id })
```

`nextCursor` is `null` at the last page. Replies use `parentId` from a top-level comment. Delete requires ownership.

Discussion inputs have these limits:

* Comment body: 1 to 2,000 Unicode code points after normalization and trimming.
* Display name: Truncated to 80 Unicode code points after normalization.
* Page size: 20 by default, with a maximum of 50.
* Learner ID: At most 500 Unicode code points after trimming.

Each parent includes at most 50 replies. These replies do not have a separate cursor. Do not treat this response as an unlimited thread export.

## Resource links

`labs.get()` returns available supporting links in `LabDetails.resources`. The value is a plain list or `null`.

Each link includes an `id`, `type`, `title`, and `url`. A link can also include a description.

Your interface can show these links alongside the lab guide. `labs.list()` provides `hasResources` without the full link list.

## Deployments

| SDK method | Return type | REST operation |
| - | - | - |
| `deployments.launch({ labId, learnerId, membership?, sourceIp? })` | `Promise<Deployment>` | [Launch](/api-reference/launch-deployment) |
| `deployments.get(deploymentId)` | `Deployment` | No request |
| `deployments.getStatus(deploymentId)` | `Promise<DeploymentStatusResponse>` | [Status](/api-reference/get-deployment) |
| `deployments.getRuns(deploymentId)` | `Promise<DeploymentRun[]>` | [Runs](/api-reference/get-runs) |
| `deployments.destroy(deploymentId)` | `Promise<DestroyDeploymentResponse>` | [End](/api-reference/end-deployment) |
| `deployments.createTerminalSession(deploymentId, options?)` | `Promise<TerminalSession>` | [Terminal session](/api-reference/create-terminal-session) |

`membership` defaults to `free` in the SDK. `sourceIp` is optional and applies only to labs that use it.

## Deployment handles

Both `launch()` and `get()` return a handle with `id` and `version: 'v2'`. The handle exposes these methods:

```ts theme={null}
await deployment.getStatus()
await deployment.getRuns()
await deployment.createTerminalSession()
await deployment.waitUntilReady()
await deployment.destroy()
```

`get()` makes no network request. It creates a handle for an existing ID.

## Readiness polling

`waitUntilReady()` accepts these fields:

| Field | Default | Purpose |
| - | - | - |
| `pollIntervalMs` | `5000` | Time between status requests |
| `timeoutMs` | `900000` | Deadline checked between status requests |
| `signal` | None | Cancellation signal |
| `onProgress` | None | Callback with each status response |

The result is `{ status: 'complete', outputs }`. A failed or ended deployment throws `deployment_failed`.

The method checks the deadline after each status request. An in-flight request can exceed that deadline.

The signal stops later polls and cancels the sleep between polls. It does not cancel an in-flight status request.

If that request returns ready, the method can resolve despite an abort or elapsed deadline. The cancellation checks before polls and during sleeps throw `aborted`.

Cancellation does not end the deployment. The HTTP client's timeout and retry settings still apply to each status request.

## Status and run types

```ts theme={null}
type DeploymentStatusResponse =
  | { status: 'loading' }
  | { status: 'failed' }
  | { status: 'complete', outputs: Record<string, unknown> }
```

`DeploymentRun` includes `id`, `deploymentId`, `action`, `status`, `exitCode`, `outputs`, `error`, and timestamps.

Run actions are `apply`, `destroy`, or `clean`. Run states are `queued`, `running`, `completed`, or `errored`.

See [errors](/reference/errors) for SDK errors and [terminals](/reference/terminal) for terminal types.
