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

# Sample Scripts

> Runnable TypeScript and Python scripts that sign a client assertion, exchange it for an access token, and call a metadata endpoint.

These scripts match the samples in your onboarding pack. Each one runs the full flow end to end:

1. Sign a JWT client assertion with your ES256 **private** key.
2. Exchange it for a short-lived access token.
3. Call a metadata endpoint with the access token.

Both expect your private key (`private_key.pem`) next to the script. Replace `<OAuthClientId>` and `<KID>` with the values from your onboarding pack. See [Request an access token](/api-reference/authentication/request-token) for what each step does.

**TypeScript**

Requires Node.js 18 or later for the global `fetch`.

```bash theme={null}
npm install jsonwebtoken
npm install --save-dev typescript tsx @types/jsonwebtoken @types/node
npx tsx sample_request.ts
```

```typescript sample_request.ts theme={null}
import { randomUUID } from 'node:crypto';
import { readFileSync } from 'node:fs';
import jwt from 'jsonwebtoken';

// ---------------------------------------------------------------------------
// Configuration — fill these in for your environment.
// ---------------------------------------------------------------------------

const OAUTH_CLIENT_ID = '<OAuthClientId>'; // Your OAuth Client Id (from your onboarding pack)
const KID = '<KID>'; // The Kid whose PRIVATE key you're using to sign below
const PRIVATE_KEY_PATH = './private_key.pem'; // Path to the PRIVATE key matching that Kid's public key

const GATEWAY_BASE_URL = 'https://gateway.creditbenchmark.com';
const TOKEN_URL = 'https://gateway.creditbenchmark.com/api/security/token';
const AUDIENCE = 'cb-gateway-m2m-blue';

// Any of the metadata endpoints below — change as needed.
const METADATA_ENDPOINT = '/beta/metadata/columns';

/** Builds and signs the RFC 7523 JWT bearer client assertion. */
function buildClientAssertion(): string {
  const privateKeyPem = readFileSync(PRIVATE_KEY_PATH, 'utf8');
  const now = Math.floor(Date.now() / 1000);

  return jwt.sign(
    {
      iss: OAUTH_CLIENT_ID,
      sub: OAUTH_CLIENT_ID,
      aud: AUDIENCE,
      jti: randomUUID(),
      iat: now,
      exp: now + 120,
    },
    privateKeyPem,
    { algorithm: 'ES256', keyid: KID }
  );
}

/** Exchanges the signed client assertion for a short-lived access token. */
async function getAccessToken(): Promise<string> {
  const clientAssertion = buildClientAssertion();

  const body = new URLSearchParams({
    grant_type: 'client_credentials',
    client_assertion_type: 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
    client_assertion: clientAssertion,
    OAuthClientId: OAUTH_CLIENT_ID,
  });

  const response = await fetch(TOKEN_URL, {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body,
  });

  if (!response.ok) {
    throw new Error(`Token request failed: ${response.status} ${await response.text()}`);
  }

  const data = (await response.json()) as { accessToken: string };
  return data.accessToken;
}

/** Calls a metadata API using the access token. Swap 'endpoint' for any of
 * the other metadata endpoints. */
async function callMetadataEndpoint(accessToken: string, endpoint: string = METADATA_ENDPOINT): Promise<unknown> {
  const response = await fetch(`${GATEWAY_BASE_URL}${endpoint}`, {
    headers: {
      Authorization: `Bearer ${accessToken}`,
      'Content-Type': 'application/json',
      Accept: 'application/json',
    },
  });

  if (!response.ok) {
    throw new Error(`Metadata request failed: ${response.status} ${await response.text()}`);
  }

  return response.json();
}

(async () => {
  const token = await getAccessToken();
  console.log('Access token acquired.');

  const data = await callMetadataEndpoint(token);
  console.log(`Response from ${METADATA_ENDPOINT}:`);
  console.log(data);
})().catch((err) => {
  console.error(err);
  process.exitCode = 1;
});
```

**Python**

Requires Python 3.8 or later.

```bash theme={null}
pip install "requests>=2.31.0" "PyJWT>=2.8.0" "cryptography>=41.0.0"
python sample_request.py
```

```python sample_request.py theme={null}
import time
import uuid

import jwt  # PyJWT
import requests

# ---------------------------------------------------------------------------
# Configuration — fill these in for your environment.
# ---------------------------------------------------------------------------

OAUTH_CLIENT_ID = "<OAuthClientId>"  # Your OAuth Client Id (from your onboarding pack)
KID = "<KID>"  # The Kid whose PRIVATE key you're using to sign below
PRIVATE_KEY_PATH = "private_key.pem"  # Path to the PRIVATE key matching that Kid's public key

GATEWAY_BASE_URL = "https://gateway.creditbenchmark.com"
TOKEN_URL = "https://gateway.creditbenchmark.com/api/security/token"
AUDIENCE = "cb-gateway-m2m-blue"

# Any of the metadata endpoints below — change as needed.
METADATA_ENDPOINT = "/beta/metadata/columns"


def build_client_assertion() -> str:
    """Builds and signs the RFC 7523 JWT bearer client assertion."""
    with open(PRIVATE_KEY_PATH, "r", encoding="utf-8") as f:
        private_key_pem = f.read()

    now = int(time.time())
    payload = {
        "iss": OAUTH_CLIENT_ID,
        "sub": OAUTH_CLIENT_ID,
        "aud": AUDIENCE,
        "jti": str(uuid.uuid4()),
        "iat": now,
        "exp": now + 120,
    }
    headers = {"kid": KID}

    return jwt.encode(payload, private_key_pem, algorithm="ES256", headers=headers)


def get_access_token() -> str:
    """Exchanges the signed client assertion for a short-lived access token."""
    client_assertion = build_client_assertion()

    response = requests.post(
        TOKEN_URL,
        data={
            "grant_type": "client_credentials",
            "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
            "client_assertion": client_assertion,
            "OAuthClientId": OAUTH_CLIENT_ID,
        },
        headers={"Content-Type": "application/x-www-form-urlencoded"},
        timeout=30,
    )
    response.raise_for_status()
    return response.json()["accessToken"]


def call_metadata_endpoint(access_token: str, endpoint: str = METADATA_ENDPOINT) -> dict:
    """Calls a metadata API using the access token. Swap 'endpoint' for any
    of the other metadata endpoints."""
    response = requests.get(
        f"{GATEWAY_BASE_URL}{endpoint}",
        headers={
            "Authorization": f"Bearer {access_token}",
            "Content-Type": "application/json",
            "Accept": "application/json",
        },
        timeout=30,
    )
    response.raise_for_status()
    return response.json()


if __name__ == "__main__":
    token = get_access_token()
    print("Access token acquired.")

    data = call_metadata_endpoint(token)
    print(f"Response from {METADATA_ENDPOINT}:")
    print(data)
```

## Metadata endpoints

Set `METADATA_ENDPOINT` to any of these. All are `GET` requests.

| Endpoint | Returns |
| - | - |
| `/beta/metadata/columns` | Available input columns with type, scopeable, facetable, and entitlement |
| `/beta/metadata/available-dates` | Latest effective date and latest finalised effective date |
| `/beta/metadata/geography-schema` | Region group, region, and country hierarchy |
| `/beta/metadata/rating-scales` | Supported rating scales and their grade mappings |

> [!WARNING]
>
> Never share your private key with anyone, including Credit Benchmark. Generate a new client assertion for every token request, and if a private key is ever compromised, follow [key rotation](/api-reference/authentication/key-pair-setup#key-rotation).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.