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

# CLR

> CLR API client for Comprehensive Learner Records

## Overview

The `@timeback/clr` package provides a client for the CLR v2.0 API, enabling:

* **Credentials**: Upsert verifiable CLR credentials with platform-signed proofs
* **Discovery**: Retrieve API capabilities via the OpenAPI discovery endpoint

## Installation

<CodeGroup>
  ```bash npm theme={null}
  npm install @timeback/clr
  ```

  ```bash pnpm theme={null}
  pnpm add @timeback/clr
  ```

  ```bash yarn theme={null}
  yarn add @timeback/clr
  ```

  ```bash bun theme={null}
  bun add @timeback/clr
  ```

  ```bash pip theme={null}
  pip install timeback-clr
  ```

  ```bash uv theme={null}
  uv add timeback-clr
  ```
</CodeGroup>

## Quick Start

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { ClrClient } from '@timeback/clr'

  const client = new ClrClient({
  	env: 'staging',
  	auth: {
  		clientId: process.env.CLR_CLIENT_ID!,
  		clientSecret: process.env.CLR_CLIENT_SECRET!,
  	},
  })

  // Upsert a CLR credential
  const credential = await client.credentials.upsert({
  	'@context': [
  		'https://www.w3.org/ns/credentials/v2',
  		'https://purl.imsglobal.org/spec/clr/v2p0/context-2.0.1',
  	],
  	id: 'urn:uuid:example-clr-id',
  	type: ['VerifiableCredential', 'ClrCredential'],
  	issuer: {
  		id: 'https://example.edu',
  		type: ['Profile'],
  		name: 'Example University',
  	},
  	name: 'Student Transcript',
  	validFrom: '2024-01-01T00:00:00Z',
  	credentialSubject: {
  		type: ['ClrSubject'],
  		verifiableCredential: [],
  	},
  })

  // Get API discovery information
  const discovery = await client.discovery.get()
  ```

  ```python Python theme={null}
  from timeback_clr import ClrClient

  client = ClrClient(
      env="staging",
      client_id=os.environ["CLR_CLIENT_ID"],
      client_secret=os.environ["CLR_CLIENT_SECRET"],
  )

  # Upsert a CLR credential
  credential = await client.credentials.upsert({
      "@context": [
          "https://www.w3.org/ns/credentials/v2",
          "https://purl.imsglobal.org/spec/clr/v2p0/context-2.0.1",
      ],
      "id": "urn:uuid:example-clr-id",
      "type": ["VerifiableCredential", "ClrCredential"],
      "issuer": {
          "id": "https://example.edu",
          "type": ["Profile"],
          "name": "Example University",
      },
      "name": "Student Transcript",
      "validFrom": "2024-01-01T00:00:00Z",
      "credentialSubject": {
          "type": ["ClrSubject"],
          "verifiableCredential": [],
      },
  })

  # Get API discovery information
  discovery = await client.discovery.get()
  ```
</CodeGroup>

## Credentials

Create or update verifiable CLR credentials. The platform digitally signs each credential, adding a cryptographic proof to ensure authenticity and integrity. Inputs are validated with Zod schemas before requests.

<CodeGroup>
  ```typescript TypeScript theme={null}
  const result = await client.credentials.upsert({
  	'@context': [
  		'https://www.w3.org/ns/credentials/v2',
  		'https://purl.imsglobal.org/spec/clr/v2p0/context-2.0.1',
  	],
  	id: 'urn:uuid:student-transcript-001',
  	type: ['VerifiableCredential', 'ClrCredential'],
  	issuer: {
  		id: 'https://example.edu',
  		type: ['Profile'],
  		name: 'Example University',
  	},
  	name: 'Student Achievement Record',
  	validFrom: '2024-01-01T00:00:00Z',
  	credentialSubject: {
  		type: ['ClrSubject'],
  		verifiableCredential: [
  			{
  				'@context': ['https://www.w3.org/ns/credentials/v2'],
  				id: 'urn:uuid:achievement-001',
  				type: ['VerifiableCredential', 'AchievementCredential'],
  				issuer: {
  					id: 'https://example.edu',
  					type: ['Profile'],
  					name: 'Example University',
  				},
  				name: 'Algebra I Completion',
  				validFrom: '2024-06-15T00:00:00Z',
  				credentialSubject: {
  					type: ['AchievementSubject'],
  					achievement: {
  						id: 'https://example.edu/achievements/algebra-1',
  						type: ['Achievement'],
  						name: 'Algebra I',
  						criteria: { narrative: 'Completed all units with 80%+ mastery' },
  						achievementType: 'Competency',
  					},
  				},
  			},
  		],
  	},
  })
  ```

  ```python Python theme={null}
  result = await client.credentials.upsert({
      "@context": [
          "https://www.w3.org/ns/credentials/v2",
          "https://purl.imsglobal.org/spec/clr/v2p0/context-2.0.1",
      ],
      "id": "urn:uuid:student-transcript-001",
      "type": ["VerifiableCredential", "ClrCredential"],
      "issuer": {
          "id": "https://example.edu",
          "type": ["Profile"],
          "name": "Example University",
      },
      "name": "Student Achievement Record",
      "validFrom": "2024-01-01T00:00:00Z",
      "credentialSubject": {
          "type": ["ClrSubject"],
          "verifiableCredential": [
              {
                  "@context": ["https://www.w3.org/ns/credentials/v2"],
                  "id": "urn:uuid:achievement-001",
                  "type": ["VerifiableCredential", "AchievementCredential"],
                  "issuer": {
                      "id": "https://example.edu",
                      "type": ["Profile"],
                      "name": "Example University",
                  },
                  "name": "Algebra I Completion",
                  "validFrom": "2024-06-15T00:00:00Z",
                  "credentialSubject": {
                      "type": ["AchievementSubject"],
                      "achievement": {
                          "id": "https://example.edu/achievements/algebra-1",
                          "type": ["Achievement"],
                          "name": "Algebra I",
                          "criteria": {"narrative": "Completed all units with 80%+ mastery"},
                          "achievementType": "Competency",
                      },
                  },
              },
          ],
      },
  })
  ```
</CodeGroup>

| Method     | Returns         | Description                                          |
| ---------- | --------------- | ---------------------------------------------------- |
| `upsert()` | `ClrCredential` | Create or update a credential; returns signed result |

### Credential Structure

A CLR credential follows the W3C Verifiable Credentials v2 model:

| Field               | Type                   | Description                            |
| ------------------- | ---------------------- | -------------------------------------- |
| `@context`          | `string[]`             | JSON-LD context URIs                   |
| `id`                | `string`               | Unique credential identifier (URN/URI) |
| `type`              | `string[]`             | Must include `VerifiableCredential`    |
| `issuer`            | `ClrProfile`           | Issuing organization profile           |
| `name`              | `string`               | Human-readable credential name         |
| `validFrom`         | `string`               | ISO 8601 date when credential is valid |
| `credentialSubject` | `ClrCredentialSubject` | Subject with nested achievements       |

## Discovery

Retrieve API capabilities and the OpenAPI specification.

<CodeGroup>
  ```typescript TypeScript theme={null}
  const discovery = await client.discovery.get()
  ```

  ```python Python theme={null}
  discovery = await client.discovery.get()
  ```
</CodeGroup>

| Method  | Returns             | Description                         |
| ------- | ------------------- | ----------------------------------- |
| `get()` | `DiscoveryResponse` | OpenAPI 3.0 spec for the CLR v2 API |

<Note>
  The CLR v2.0 spec declares the discovery endpoint as public, but the BeyondAI implementation
  requires OAuth authentication. The client handles this transparently.
</Note>

## Standalone vs Composed

The client works standalone or composed into `@timeback/core`:

<CodeGroup>
  ```typescript TypeScript theme={null}
  // Standalone
  import { ClrClient } from '@timeback/clr'
  // Composed
  import { TimebackClient } from '@timeback/core'

  const client = new ClrClient({ env: 'staging', auth })

  const timeback = new TimebackClient({ env: 'staging', auth })

  timeback.clr.credentials.upsert(clrCredential)
  ```

  ```python Python theme={null}
  # Standalone
  from timeback_clr import ClrClient
  client = ClrClient(env="staging", client_id=client_id, client_secret=client_secret)

  # Composed
  from timeback_core import TimebackClient
  timeback = TimebackClient(env="staging", client_id=client_id, client_secret=client_secret)
  await timeback.clr.credentials.upsert(clr_credential)
  ```
</CodeGroup>

## Error Handling

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { ClrError } from '@timeback/clr/errors'

  try {
  	await client.credentials.upsert(invalidCredential)
  } catch (error) {
  	if (error instanceof ClrError) {
  		console.log(error.statusCode)
  		console.log(error.message)
  	}
  }
  ```

  ```python Python theme={null}
  from timeback_clr import ClrError

  try:
      await client.credentials.upsert(invalid_credential)
  except ClrError as error:
      print(error)
  ```
</CodeGroup>

## Configuration

<CodeGroup>
  ```typescript TypeScript theme={null}
  new ClrClient({
  	// Environment mode (Timeback APIs)
  	env: 'staging' | 'production',
  	auth: {
  		clientId: string,
  		clientSecret: string,
  	},

  	// OR Explicit mode (custom API)
  	baseUrl: string,
  	auth: {
  		clientId: string,
  		clientSecret: string,
  		authUrl: string,
  	},

  	// OR Provider mode (shared auth across clients)
  	provider: TimebackProvider,

  	// Optional
  	timeout?: number, // Request timeout in ms (default: 30000)
  })
  ```

  ```python Python theme={null}
  # Environment mode (Timeback APIs)
  client = ClrClient(
      env="staging",  # or "production"
      client_id="...",
      client_secret="...",
  )

  # Explicit mode (custom API)
  client = ClrClient(
      base_url="https://custom.example.com",
      auth_url="https://auth.example.com/oauth2/token",
      client_id="...",
      client_secret="...",
  )

  # Provider mode (shared auth)
  from timeback_common import TimebackProvider
  provider = TimebackProvider(env="staging", client_id="...", client_secret="...")
  client = ClrClient(provider=provider)

  # Optional
  # timeout: float = 30.0 (request timeout in seconds)
  ```
</CodeGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="CASE" icon="sitemap" href="/beta/build-on-timeback/clients/case">
    Competencies and standards
  </Card>

  <Card title="Caliper" icon="chart-line" href="/beta/build-on-timeback/clients/caliper">
    Learning event tracking
  </Card>

  <Card title="Types" icon="brackets-curly" href="/beta/api-reference/overview">
    CLR type definitions
  </Card>
</CardGroup>
