Skip to main content

What is a Group?

A group is the core organizing unit in Lit Chipotle. It binds together three things:
  1. Wallets (PKPs) — which wallets can be used
  2. IPFS Actions — which lit-actions can be executed
  3. Usage API Keys — which keys have access (via their permission arrays)
Think of a group as an access-control boundary: scoped usage keys can run actions in their permitted groups, and PKP wallet access requires a group permitting both the action and wallet. Wildcard execution keys can run arbitrary code without a group, but still need that group match to use a PKP wallet.
In this example, Key A can only use Group 1’s wallets and actions. Key B can use both groups. The account key administers all groups; use a usage key to execute actions.

Why Groups Exist

Without groups, every usage key would have access to every wallet and every action in your account. Groups let you:
  • Scope a key to a single dApp — give your price-oracle service a key that can only execute the price-oracle action using a specific wallet.
  • Isolate environments — separate staging actions from production actions.
  • Rotate access safely — revoke a usage key without affecting other keys or groups.

How Groups Connect to Everything

Common Patterns

One group per dApp

Give each dApp its own usage key scoped to its group. If the price-oracle key leaks, the minter is unaffected.

All-access key for development

Create a usage key with execute_in_groups: [0] (wildcard). This key can run arbitrary action code, including code pasted into the Dashboard Action Runner, without registering a CID or creating a group. Execution permission and PKP wallet permission are separate. If the action requests a PKP private key or uses PKP encryption/decryption, a group in the key’s own account must permit both the action CID and the requested wallet. They must match the same group. Wildcard execution skips the individual group grants on the key; it does not skip this resource check or grant access to another account’s wallets. Group membership is not proof of wallet ownership: listing a foreign wallet address can satisfy the group check, but the node separately resolves the wallet in the caller’s account and verifies the derived key’s address before releasing or using it. For example, console.log("hello") needs no group with a wildcard key. An action using wallet A requires a group containing wallet A and that action’s CID (or the group’s all-actions wildcard). Changing the code changes its CID, so update the permitted CID or deliberately allow all actions for that group. Use a scoped key when you want to restrict which code can execute. Expired and revoked keys do not gain access through wildcard permissions.

Shared wallets across groups

A single wallet can belong to multiple groups. This is useful when multiple dApps need to sign with the same address but run different actions.

Group Lifecycle

  1. Create — POST /core/v1/add_group with a name and optional pre-permitted PKPs and CID hashes.
  2. Configure — Add wallets (add_pkp_to_group) and actions (add_action_to_group).
  3. Grant access — Create or update usage keys with the group ID in their permission arrays.
  4. Update — POST /core/v1/update_group to change name, description, or permission lists.
  5. Delete — POST /core/v1/remove_group to remove the group. Usage keys that referenced it lose that access.

Revocation during a running action

Each PKP private-key request and PKP AES encrypt/decrypt operation checks wallet permission through the shared blockchain cache, including repeated operations in the same action execution. An execution does not retain its first permission decision for its entire lifetime. Revocation is not instantaneous. API mutation hooks and the on-chain account-event listener selectively invalidate affected cache entries; the listener polls every 10 seconds. Cached grants expire after 300 seconds without a hit; each hit renews that window. Cached denials expire 30 seconds after insertion or update, without extension on reads. Both grants and denials are invalidated by relevant events: once a grant event is processed successfully, the next lookup can observe the new permission without waiting for the denial TTL. This is not instantaneous; mining, polling, RPC visibility, and usage-key invalidation affect propagation. There is no hard maximum age for a continuously used grant. If the listener misses an event or invalidation is incomplete, a hot stale grant can remain usable indefinitely. Denials retain their short TTL as a fallback. Once a fresh lookup is required, lookup errors stop the operation rather than falling back to an old grant. Wallet-derivation caching retains its separate fixed five-minute TTL. An operation whose permission check started before invalidation may still finish. Revocation does not erase a private key already returned to action code, terminate the running action, or revoke access granted through another matching group.

Permission Flags on Groups

When creating a group, two convenience flags control default access:
  • All wallets permitted — any wallet in the account can be used via this group (no need to add individually).
  • All actions permitted — any action CID matches this group, including code that has not been registered.
These are set in the Dashboard’s group creation form or via the pkp_ids_permitted and cid_hashes_permitted arrays in the API. On-chain, these flags are not separate booleans: they are encoded using wildcard values in the arrays:
  • To permit all wallets, include the zero PKP ID in pkp_ids_permitted:
    • pkp_ids_permitted: ["0x0000000000000000000000000000000000000000000000000000000000000000"]
  • To permit all actions, include 0 in cid_hashes_permitted:
    • cid_hashes_permitted: [0]
Leaving these arrays empty or omitting them does not mean “all” — it means no wallets/actions are automatically permitted by default.

Further Reading