> ## Documentation Index
> Fetch the complete documentation index at: https://tbd-6fc993ce-hypeship-webmcp-control-telemetry.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Credential Items

> Collect and update encrypted credentials, then fill selected fields in a vault-attached browser

use a `credential` item for usernames, passwords, totp generators, and other non-payment credentials. it belongs directly to a [vault](/vaults); you don't need a wallet or an external credential provider.

<Warning>
  use `wallet` and `card` items for credit card numbers, security codes, and expiration dates. don't store, collect, or fill payment-card data through credential items.
</Warning>

credential items store values and support explicit [browser fill](/vaults/fill). your application or agent still handles navigation, submission, and the site's response. choose [managed auth](/auth/overview) instead when you want KERNEL to run login flows and maintain authenticated sessions.

## Define an item

create a vault for each end user, then define their credential item. keep your api key and credential writes in your trusted backend.

<CodeGroup>
  ```typescript TypeScript theme={null}
  import Kernel from "@onkernel/sdk";

  const kernel = new Kernel({
    projectID: process.env.KERNEL_PROJECT_ID,
  });
  const vault = await kernel.vaults.upsert({ name: "user-12345" });
  const item = await kernel.vaults.items.upsert("portal-login", {
    id_or_name: vault.id,
    type: "credential",
    spec: {
      description: "Account Portal",
      fields: {
        username: { type: "email", required: true, sensitive: false },
        password: { type: "password", required: true, sensitive: true },
      },
    },
  });
  ```

  ```python Python theme={null}
  import os

  from kernel import Kernel

  kernel = Kernel(
      project_id=os.environ["KERNEL_PROJECT_ID"],
  )
  vault = kernel.vaults.upsert(name="user-12345")
  item = kernel.vaults.items.upsert(
      "portal-login",
      id_or_name=vault.id,
      type="credential",
      spec={
          "description": "Account Portal",
          "fields": {
              "username": {"type": "email", "required": True, "sensitive": False},
              "password": {"type": "password", "required": True, "sensitive": True},
          },
      },
  )
  ```
</CodeGroup>

use only the recognizable site or service name for `description`. it's the collection form's title, not a destination restriction. choose a vault per user or access boundary; don't put unrelated users' credentials in the same vault.

| field setting | behavior                                                                              |
| ------------- | ------------------------------------------------------------------------------------- |
| `type`        | `text`, `email`, `password`, or `totp`                                                |
| `required`    | defaults to `true`; all required fields must have values for the item to become ready |
| `sensitive`   | defaults to `true`; explicitly set `false` for ordinary usernames and email addresses |
| `value`       | optional initial value from trusted code; omit it to leave the field unset            |

password and totp fields must be sensitive. an item accepts 1–32 named fields. initial values must be nonempty strings and fit within 16 kib of utf-8 data each; `null` and empty strings aren't accepted on creation.

field names, types, required flags, and sensitivity are immutable. repeating the same creation request retrieves the current item without overwriting later edits. use an update for value changes; use a new item key for a different field definition.

## Collect values from the user

if required values are missing, the item has `state.status: "pending_collection"` and an `action` named `collect`. present `action.url` in your authenticated application, bound to the intended user and item. open the url as returned; don't extract its token or pass it to the public item api.

<Warning>
  collection links are bearer credentials. share them only with the intended user, not in shared logs, analytics, screenshots, or replay. in an application, present the link directly in the user's authenticated interface. the [cli cookbook](/browsers/use-vault-credentials-in-browser-agent) lets an agent relay it in a private conversation. open collection outside the agent-controlled browser.
</Warning>

KERNEL-hosted links expire after 30 minutes. retrieve the item from your trusted backend to obtain a renewed link when needed; an expired link can't renew itself. listing items doesn't renew collection sessions.

poll the item with a bounded wait until its status is `ready`. readiness means required values exist, not that a website accepted them. optional fields can remain unset, and unset fields can't be filled.

invoke the advertised `collect` operation to reopen collection for a ready item. this doesn't clear its values. record its `version` before opening the form, then retrieve without `wait` to observe edits: `wait` waits for readiness, not changes to an already-ready item. a version change can also come from an api update, so it doesn't identify a particular form submission.

the form includes text, email, and password fields, not totp. non-sensitive values can be prefilled; stored secrets aren't revealed. required visible inputs must be populated on submission.

## Read and update values

`spec.fields` contains definitions, never initial values. `state.fields` reports `has_value` for each field. it also returns `value` when the field is populated and `sensitive: false`. sensitive values aren't returned.

updates require `type: "credential"` and the latest `version`. send only fields you want to change. bind forms to the immutable item id with `expected_item_id` so a deleted and recreated key can't receive an old form's submission.

<CodeGroup>
  ```typescript TypeScript theme={null}
  const current = await kernel.vaults.items.retrieve(item.key, { id_or_name: vault.id });
  if (current.type !== "credential" || current.id !== item.id) {
    throw new Error("credential item was replaced");
  }
  const updated = await kernel.vaults.items.update(item.key, {
    id_or_name: vault.id,
    type: "credential",
    version: current.version,
    expected_item_id: item.id,
    spec: { fields: { password: { value: null } } },
  });
  ```

  ```python Python theme={null}
  current = kernel.vaults.items.retrieve(item.key, id_or_name=vault.id)
  if current.type != "credential" or current.id != item.id:
      raise RuntimeError("credential item was replaced")
  updated = kernel.vaults.items.update(
      item.key,
      id_or_name=vault.id,
      type="credential",
      version=current.version,
      expected_item_id=item.id,
      spec={"fields": {"password": {"value": None}}},
  )
  ```
</CodeGroup>

this clears the password and returns the item to `pending_collection`. public updates can clear text, email, and password values with `null` or `""`, even when required. required totp seeds can't be cleared. this differs from the hosted form, which requires populated required inputs.

a successful update increments the version and invalidates outstanding hosted collection sessions. on a `409` conflict, reload and reconcile with the user rather than automatically resubmitting stale edits.

## Use totp

supply a base32 generator seed through trusted backend code, using `value` at creation or an authenticated update. a required totp field needs its seed at creation; the collection form can't supply it. an optional totp field can receive its seed later.

KERNEL generates a fresh six-digit code immediately before filling, using hmac-sha1 and a 30-second period. neither the seed nor a generated code is returned by item reads. the seed never enters the browser; the generated code does. custom algorithms, periods, and digit counts aren't supported.

## Build your own collection surface

your authenticated backend can retrieve safe item state and submit value updates using the ordinary item api. authenticate your own users, authorize their access to the vault and immutable item id, and apply the version precondition. keep broad KERNEL api credentials out of the frontend.

render every form-supported field, omit totp, prefill only non-sensitive values, and don't log submitted values. for an unchanged form, use your own completion callback rather than an empty update. KERNEL doesn't store or authenticate your custom collection url.

continue with [fill browser fields](/vaults/fill) or the [browser agent cookbook](/browsers/use-vault-credentials-in-browser-agent).
