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

# Functions reference

> Technical reference for C1 functions, including SDK namespaces, runtime constraints, configuration options, and troubleshooting.

<Warning>
  **Early access.** This feature is in early access, which means it's undergoing ongoing testing and development while we gather feedback, validate functionality, and improve outputs. Contact the C1 Support team if you'd like to try it out or share feedback.
</Warning>

## SDK namespaces

The pre-authenticated `sdk` object provides type-safe access to the C1 API through 60+ namespaces organized by resource type.

| Category            | Namespaces                                                                                                                                         |
| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| Users & Identity    | `user`, `userSearch`, `directory`, `attributes`, `attributeSearch`                                                                                 |
| Apps & Entitlements | `apps`, `appSearch`, `appEntitlements`, `appEntitlementSearch`, `appUser`, `appResource`, `appResourceSearch`, `appOwners`, `appEntitlementOwners` |
| Tasks & Access      | `task`, `taskActions`, `taskSearch`, `taskAudit`                                                                                                   |
| Automations         | `automation`, `automationExecution`, `automationSearch`                                                                                            |
| Policies & Catalog  | `policies`, `policySearch`, `requestCatalogManagement`, `requestCatalogSearch`                                                                     |
| Connectors          | `connector`, `connectorCatalog`                                                                                                                    |
| Functions           | `functions`, `functionsSearch`                                                                                                                     |
| Webhooks & Export   | `webhooks`, `webhooksSearch`, `export`, `exportsSearch`, `systemLog`                                                                               |

## Common SDK operations

```typescript theme={"theme":{"light":"css-variables","dark":"css-variables"}}
import { JSONObject, sdk, functions } from "@c1/functions-sdk";

// Users
await sdk.user.list({ pageSize: 100, pageToken });
await sdk.user.get({ id: "user_123" });
await sdk.userSearch.search({ query: "alice@example.com" });

// Apps
await sdk.apps.list();
await sdk.apps.get({ id: "app_456" });
await sdk.appSearch.search({ query: "Slack" });

// Entitlements
await sdk.appEntitlements.list({ appId: "app_456" });
await sdk.appEntitlementSearch.search({ appIds: ["app_456"] });

// Tasks
await sdk.task.get({ id: "task_789" });
await sdk.taskSearch.search({ taskTypes: ["grant", "revoke"] });
await sdk.task.createGrantTask({ appEntitlementId: "ent_456", appUserId: "appuser_123" });
await sdk.task.createRevokeTask({ appEntitlementId: "ent_456", appUserId: "appuser_123" });

// Connectors
await sdk.connector.list();
await sdk.connector.get({ id: "conn_123" });
```

## Pagination

Use the pagination pattern to retrieve all results:

```typescript theme={"theme":{"light":"css-variables","dark":"css-variables"}}
const all = [];
let pageToken: string | undefined;
do {
  const resp = await sdk.user.list({ pageSize: 100, pageToken });
  if (resp.userServiceListResponse?.list) all.push(...resp.userServiceListResponse.list);
  pageToken = resp.userServiceListResponse?.nextPageToken;
} while (pageToken);
```

## Importing external libraries

<Note>
  Dependency versions are pinned when you publish. To pick up newer versions, re-publish your function.
</Note>

The runtime is Deno-based. Import npm packages using the `npm:` specifier:

```typescript theme={"theme":{"light":"css-variables","dark":"css-variables"}}
import { z } from "npm:zod";
import { format, subDays } from "npm:date-fns";
import Stripe from "npm:stripe";
```

Packages are resolved at deploy time. No `package.json` or `node_modules` needed.

`@c1/functions-sdk` and `@c1/test` are pre-configured and available without the `npm:` prefix.

## Configuration options

Configure secrets and network access in the C1 UI:

<Steps>
  <Step>
    Navigate to **Workflows** > **Functions**.
  </Step>

  <Step>
    Click on your function.
  </Step>

  <Step>
    Click **...** (the more actions menu) and select **Edit config**.
  </Step>
</Steps>

The config drawer has two sections: **Secrets** and **Outbound network access**. API access is configured separately by linking a service principal — see [API access](#api-access) below.

### Secrets

Store API keys and configuration values as key/value pairs. Secrets are encrypted at rest and decrypted at runtime.

To access secrets in code:

```typescript theme={"theme":{"light":"css-variables","dark":"css-variables"}}
import { functions } from "@c1/functions-sdk";

const config = await functions.getConfig();
const webhookUrl = config.secrets["SLACK_WEBHOOK_URL"];
const threshold = parseInt(config.secrets["THRESHOLD"], 10);
```

`functions.getConfig()` returns `{ secrets: Record<string, string> }`. Keys and values match what you defined in the UI.

### Outbound network access

<Warning>
  External domains must be added to the **Outbound network access** section in your function's config or the request will be blocked. All outbound network traffic is routed through an egress proxy that enforces your allowlist.
</Warning>

Add allowed domains to your function's config. This ensures functions can only communicate with endpoints you've explicitly approved, preventing unauthorized data exfiltration or unintended external calls.

Here's an example external API call:

```typescript theme={"theme":{"light":"css-variables","dark":"css-variables"}}
import { JSONObject, functions } from "@c1/functions-sdk";

export default async function main(input: JSONObject): Promise<JSONObject> {
  const config = await functions.getConfig();
  const apiKey = config.secrets["EXTERNAL_API_KEY"];

  const resp = await fetch("https://api.example.com/data", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": `Bearer ${apiKey}`,
    },
    body: JSON.stringify({ query: input.query }),
  });

  if (!resp.ok) {
    return { success: false, error: `API returned ${resp.status}` };
  }

  return { success: true, data: await resp.json() };
}
```

### API access

Functions authenticate to the C1 API as a linked [service principal](/product/admin/service-principals/overview). The service principal's role bindings determine what the function can do — every SDK call is authorized against those roles, and calls outside the granted permissions are denied.

To link or change a function's service principal, open the function and click **...** > **Link service principal**. To change what the function can do, edit the service principal's roles in **Directory** > **Service principals** — no function redeploy needed.

<Note>
  Functions created before this change were migrated automatically and linked to a service principal with read-only access. To grant write access, link the function to a service principal that holds write-capable roles.
</Note>

## Testing with @c1/test

New functions are scaffolded with a `main.test.ts` file alongside `main.ts`. The test file exports a `registerTests` function that receives your `main` function as `handler`, so each test can invoke it with different inputs.

```typescript theme={"theme":{"light":"css-variables","dark":"css-variables"}}
// main.test.ts
import { JSONObject } from "@c1/functions-sdk";
import { test } from "@c1/test";

export default function registerTests({handler}: {handler: (input: JSONObject) => Promise<JSONObject>}) {
  test("validates required fields", async ({ equal }) => {
    const result = await handler({});
    equal(result.success, false);
    equal(result.error, "Missing required fields");
  });

  test("dry run returns without side effects", async ({ equal, ok }) => {
    const result = await handler({ userId: "u1", action: "revoke", appId: "a1", dryRun: true });
    equal(result.success, true);
    ok(result.dryRun);
  });
}
```

### Assertions

Each `test()` callback receives an assertion object with these methods:

| Method                    | Description                   |
| ------------------------- | ----------------------------- |
| `equal(actual, expected)` | Strict equality check (`===`) |
| `ok(value)`               | Truthy check                  |
| `fail(message)`           | Force a test failure          |

### Test options

Pass an options object as the third argument to `test()`:

```typescript theme={"theme":{"light":"css-variables","dark":"css-variables"}}
test("work in progress", async ({ ok }) => {
  // ...
}, { skip: true });

test("debug this one", async ({ equal }) => {
  // ...
}, { only: true });
```

### Running tests

Click **Test draft** when viewing a draft, or **Run tests** when viewing published code. Each `test()` call becomes an individual result in the test dialog, displayed with a pass/fail status chip. Click on a result to expand assertion details and logs.

## Runtime constraints

| Constraint   | Detail                                                                           |
| ------------ | -------------------------------------------------------------------------------- |
| Runtime      | Deno (V8-based). Native TS, ES modules, web standard APIs (`fetch`, `URL`, etc.) |
| Filesystem   | None. Functions are stateless.                                                   |
| Network      | Egress allowlist only. C1 API subdomains pre-approved.                           |
| State        | No persistence between invocations. Each call starts fresh.                      |
| Auth         | OAuth2 + DPoP auto-injected. Never handle tokens.                                |
| Dependencies | `@c1/functions-sdk` auto-available. Other npm packages resolved at publish time. |
| Logging      | `console.log/error/warn` captured. Retained 30 days. Don't log secrets.          |

## Troubleshooting functions

Common issues and how to resolve them.

### Function times out

* Check for infinite loops
* Verify external domains are in your allowlist
* Break large operations into smaller batches

### External API calls fail

* Ensure domain is in the outbound network allowlist
* Verify API credentials in secrets
* Check console logs for detailed error messages

### API returns 403 Forbidden

* Check the linked service principal's roles — the function authenticates as that SP, and the call is authorized against its role bindings
* If the function isn't linked to a service principal yet, link one (see [API access](#api-access))

### Cannot deploy function

* Verify you have admin access
* Check for TypeScript syntax errors
* Ensure all imports are valid
