From fbc4fc75a4c80c9778109b479a2e889e0125f32d Mon Sep 17 00:00:00 2001 From: Melinda Moreland Date: Thu, 16 Jul 2026 14:59:18 -0700 Subject: [PATCH 1/5] docs: fix CEL syntax and invalid trigger in functions-automations Step-output references used a nonexistent `steps..output.` form; the automation CEL context is `ctx..` per the workflow execution engine, matching expressions-workflows.mdx. Also swapped the example's "Access request created" trigger, which isn't a real automation trigger type, for "Grant found". --- product/admin/functions-automations.mdx | 32 ++++++++++++------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/product/admin/functions-automations.mdx b/product/admin/functions-automations.mdx index 29bf23f5..b1d37170 100644 --- a/product/admin/functions-automations.mdx +++ b/product/admin/functions-automations.mdx @@ -21,7 +21,7 @@ Functions work as steps in automation workflows, allowing you to add custom logi - Your function doesn't need to know it's called from an automation. It receives JSON in, returns JSON out. - The **automation UI** defines which CEL expressions map to which input keys. -- Your **return value** becomes available to subsequent automation steps via the step name (such as `checkTraining.approved`). +- Your **return value** becomes available to subsequent automation steps via `ctx.` (such as `ctx.checkTraining.approved`). - The function runs with the same security model regardless of trigger source: pre-authenticated SDK, egress allowlist, no filesystem. @@ -55,10 +55,10 @@ In the automation UI, each argument is a CEL expression evaluated against the wo | Variable | Description | |----------|-------------| -| `trigger.user_id` | User ID from the automation trigger | -| `trigger.app_id` | App ID from the trigger event | -| `trigger.entitlement_id` | Entitlement ID from the trigger | -| `previous_step_name.field` | Output field from a previously completed step | +| `ctx.trigger.user_id` | User ID from the automation trigger | +| `ctx.trigger.app_id` | App ID from the trigger event | +| `ctx.trigger.entitlement_id` | Entitlement ID from the trigger | +| `ctx.previous_step_name.field` | Output field from a previously completed step | ### Example inputs @@ -68,8 +68,8 @@ The examples below show how you configure arguments in the automation UI. The le | Key | CEL Expression | |-----|----------------| -| `userId` | `trigger.user_id` | -| `appId` | `trigger.app_id` | +| `userId` | `ctx.trigger.user_id` | +| `appId` | `ctx.trigger.app_id` | | `action` | `"verify"` (literal string) | Your function receives the evaluated values: @@ -86,8 +86,8 @@ Your function receives the evaluated values: | Key | CEL Expression | |-----|----------------| -| `userId` | `steps.getUser.output.id` | -| `department` | `steps.getUser.output.profile.department` | +| `userId` | `ctx.getUser.id` | +| `department` | `ctx.getUser.profile.department` | | `timestamp` | `now()` | **Static values:** @@ -104,9 +104,9 @@ For literal values, wrap strings in quotes within the CEL expression: The output of your function is available in subsequent steps via the step context. If your function step is named `checkTraining`, access its output like this: ``` -steps.checkTraining.output.trainingCompleted -steps.checkTraining.output.eligible -steps.checkTraining.output.userId +ctx.checkTraining.trainingCompleted +ctx.checkTraining.eligible +ctx.checkTraining.userId ``` ## Example: Training verification workflow @@ -151,12 +151,12 @@ export default async function main(input: JSONObject): Promise { ### Automation workflow -1. **Trigger:** Access request created +1. **Trigger:** Grant found (fires when a user is granted access to the app) 2. **Step 1: Run Function** `checkTraining` - - Input: `{ "userId": "trigger.user_id" }` + - Input: `{ "userId": "ctx.trigger.user_id" }` 3. **Step 2: Conditional** - Check if training is completed - - Condition: `steps.checkTraining.output.eligible == true` - - **If true:** Approve the access request + - Condition: `ctx.checkTraining.eligible == true` + - **If true:** No further action needed - **If false:** Send notification to user with training link ## Best practices From 29fb8f8fd8aac5e44ae3f8a79e03cf1ea0912da4 Mon Sep 17 00:00:00 2001 From: Melinda Moreland Date: Thu, 16 Jul 2026 15:54:54 -0700 Subject: [PATCH 2/5] docs: rename copilot section to C1AI, fix stale button labels The function-editor AI entry point now opens the shared C1AI assistant rather than a dedicated copilot, and the actual button labels are "Create with Functions assistant" / "Edit with Functions assistant", not "Create with AI" / "Edit with AI". --- product/admin/functions-create.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/product/admin/functions-create.mdx b/product/admin/functions-create.mdx index 5214bcf2..35db210e 100644 --- a/product/admin/functions-create.mdx +++ b/product/admin/functions-create.mdx @@ -14,11 +14,11 @@ sidebarTitle: "Create and test functions" This guide walks you through creating your first function, from a simple "hello world" to accessing C1 data and calling external APIs. -## Use the copilot to write function code +## Use C1AI to write function code -Not sure where to start with TypeScript or the C1 API? The built-in AI code assistant can generate a working function from a plain-language description of what you want it to do — no TypeScript expertise required. Since functions start as drafts, you can try out the generated code, run it, and iterate safely before publishing. +Not sure where to start with TypeScript or the C1 API? C1AI can generate a working function from a plain-language description of what you want it to do — no TypeScript expertise required. Since functions start as drafts, you can try out the generated code, run it, and iterate safely before publishing. -To get started, click **Create with AI** when creating a new function, or click **Edit with AI** in the code editor of an existing function draft. Describe what you want your function to do, and the AI assistant will generate code to get you started. You can then edit the code as needed, run it with test inputs, and publish when you're ready. +To get started, click **Create with Functions assistant** when creating a new function, or click **Edit with Functions assistant** in the code editor of an existing function draft. Describe what you want your function to do, and C1AI will generate code to get you started. You can then edit the code as needed, run it with test inputs, and publish when you're ready. ## Step 1: Set up a new function From 6775a150720d791bbae509a55f3f8686e5550d22 Mon Sep 17 00:00:00 2001 From: Melinda Moreland Date: Thu, 16 Jul 2026 16:07:11 -0700 Subject: [PATCH 3/5] docs: fix invalid enum value and non-base64 bytes field in functions-api FUNCTION_TYPE_DEFAULT isn't a real FunctionType value; the proto only defines UNSPECIFIED/ANY/CODE_MODE and explicitly calls for ANY on user functions. The Invoke example's `json` field is proto bytes, decoded by the generated gateway via plain protojson.Unmarshal, so it must be base64-encoded rather than a raw JSON string. --- product/admin/functions-api.mdx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/product/admin/functions-api.mdx b/product/admin/functions-api.mdx index 85359bf3..a45e7344 100644 --- a/product/admin/functions-api.mdx +++ b/product/admin/functions-api.mdx @@ -32,7 +32,7 @@ curl -X POST "$C1_TENANT/api/v1/functions" \ -d '{ "displayName": "My Function", "description": "Checks user access", - "functionType": "FUNCTION_TYPE_DEFAULT" + "functionType": "FUNCTION_TYPE_ANY" }' ``` @@ -47,7 +47,7 @@ curl -X POST "$C1_TENANT/api/v1/functions" \ -d '{ "displayName": "My Function", "description": "Checks user access", - "functionType": "FUNCTION_TYPE_DEFAULT", + "functionType": "FUNCTION_TYPE_ANY", "initialContent": { "main.ts": "'$(base64 -w0 main.ts)'" }, @@ -241,12 +241,16 @@ A function cannot be deleted if it is referenced by a hook. Remove or update any ### Invoke a function + +`json` is a `bytes` field, so its value must be base64-encoded — not a raw JSON string. + + ```bash curl -X POST "$C1_TENANT/api/v1/functions/$FUNCTION_ID/invoke" \ -H "Authorization: Bearer $C1_TOKEN" \ -H "Content-Type: application/json" \ -d '{ - "json": "{\"key\": \"value\"}" + "json": "'$(printf '{"key": "value"}' | base64 -w0)'" }' ``` From 5ee9051e52ba8d9f908cbb5c4a69890a4bf6a792 Mon Sep 17 00:00:00 2001 From: Melinda Moreland Date: Fri, 17 Jul 2026 11:55:42 -0700 Subject: [PATCH 4/5] docs: revise functions use cases per SE feedback Training/compliance verification, custom approval routing, and risk scoring aren't good candidates today since functions can't be invoked from provisioning/access-request policies. Ticketing integration should use native connectors instead of functions. Broadened username generation into attribute generation more generally, and added out-of-band API calls as a use case. --- product/admin/functions.mdx | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/product/admin/functions.mdx b/product/admin/functions.mdx index 19150e4a..d3ba3544 100644 --- a/product/admin/functions.mdx +++ b/product/admin/functions.mdx @@ -77,28 +77,16 @@ You can also call functions programmatically via the C1 API for administrative t ## Key use cases for functions -Functions unlock powerful automation scenarios that go beyond standard workflows. Here are some examples of what they can do: +Functions unlock automation scenarios that go beyond standard workflows. Here are some examples of what they can do: -### Training and compliance verification +### Dynamic attribute generation -Verify users have completed required security training, background checks, or compliance certifications before granting access to sensitive apps. Functions can check external training systems via their APIs and automatically approve or reject access requests based on compliance status. - -### Dynamic username generation - -Generate unique usernames across multiple systems using complex naming conventions. Functions can implement your organization's username algorithm, check existing usernames for uniqueness, handle edge cases, and return a guaranteed-unique username. - -### Custom approval routing - -Route access requests to the right approver based on complex business rules. Functions can query your org chart, walk up the management chain to find VPs or specific roles, and determine the appropriate approver based on access sensitivity, user location, and app ownership. - -### Risk scoring and conditional access - -Calculate a risk score for access requests based on multiple factors (user role, data sensitivity, recent security incidents, login location) and auto-approve low-risk requests. Functions can aggregate data from multiple sources and implement your organization's risk-scoring algorithm. - -### Integration with ticketing systems - -Create tickets in Jira, ServiceNow, or other ITSM tools when access is granted, and update them when access is revoked or expires. Functions handle ticket system authentication, API rate limits, and bi-directional communication. +Generate and transform user attributes across systems — usernames, custom domain matching logic, attribute mapping translation tables, and other logic that goes beyond simple field mapping. Functions can implement your organization's naming conventions, check existing values for uniqueness, apply custom domain rules, and return computed values for use in provisioning. ### Custom notification and escalation Send notifications via multiple channels (Slack, Teams, email, SMS) with custom formatting and escalation logic. Functions can format rich notifications with user and access context, implement retry logic, and track delivery. + +### Out-of-band API calls + +Call external APIs for provisioning-related tasks or other integrations that a connector invoked via automation can't handle. Functions manage authentication, rate limits, and response handling for these calls. If a system has an existing ConductorOne connector (such as Jira or ServiceNow), use that connector via automation instead of a function. From 8f699a9a44d833e267e6a3f3688c529f3dda6c44 Mon Sep 17 00:00:00 2001 From: Melinda Moreland Date: Fri, 17 Jul 2026 12:01:17 -0700 Subject: [PATCH 5/5] docs: link C1AI mention to the main assistant doc --- product/admin/functions-create.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/product/admin/functions-create.mdx b/product/admin/functions-create.mdx index 35db210e..4347bae1 100644 --- a/product/admin/functions-create.mdx +++ b/product/admin/functions-create.mdx @@ -16,7 +16,7 @@ This guide walks you through creating your first function, from a simple "hello ## Use C1AI to write function code -Not sure where to start with TypeScript or the C1 API? C1AI can generate a working function from a plain-language description of what you want it to do — no TypeScript expertise required. Since functions start as drafts, you can try out the generated code, run it, and iterate safely before publishing. +Not sure where to start with TypeScript or the C1 API? [C1AI](/product/admin/ai-assistant) can generate a working function from a plain-language description of what you want it to do — no TypeScript expertise required. Since functions start as drafts, you can try out the generated code, run it, and iterate safely before publishing. To get started, click **Create with Functions assistant** when creating a new function, or click **Edit with Functions assistant** in the code editor of an existing function draft. Describe what you want your function to do, and C1AI will generate code to get you started. You can then edit the code as needed, run it with test inputs, and publish when you're ready.