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

# List tool set events

> The sync history of a tool set. The only way to know a sync landed, and whether it landed whole.

A [synced tool set](/docs/api-reference/toolservice/create-a-new-tool-set) discovers its tools in the background. There is no sync endpoint to call and no status field to poll. This event log is how you know a sync ran and how it went.

<CodeGroup>
  ```typescript TypeScript theme={null}
  const events = await client.toolSets.listEvents(toolSetId, { workspaceId });

  for await (const event of events) {
    console.log(event.event?.type, event.event?.type === 'syncCompleted' ? event.event.syncCompleted.toolsSynced : undefined);
  }
  // syncCompleted  3
  // syncStarted    undefined
  ```

  ```go Go theme={null}
  page, err := client.ToolSets.ListEvents(ctx, toolSetID,
  	cadenya.ToolSetListEventsParams{WorkspaceID: cadenya.String(workspaceID)})
  if err != nil {
  	panic(err.Error())
  }

  for _, event := range page.Items {
  	fmt.Println(event.Event.Type, event.Event.SyncCompleted.ToolsSynced)
  }
  // syncCompleted  3
  // syncStarted    0
  ```

  ```ruby Ruby theme={null}
  page = cadenya.tool_sets.list_events(tool_set_id, workspace_id: workspace_id)

  page.auto_paging_each do |event|
    puts([event.event.type, event.event.sync_completed&.tools_synced].inspect)
  end
  # [:syncCompleted, 3]
  # [:syncStarted, nil]
  ```

  ```bash cURL theme={null}
  curl "https://api.cadenya.com/v1/workspaces/${WORKSPACE_ID}/tool_sets/${TOOL_SET_ID}/events" \
    -H "Authorization: Bearer ${CADENYA_API_KEY}"
  ```
</CodeGroup>

Events come back **newest first**. The most recent sync is the first row.

## Three event types

| Type            | Payload         | Means                                                        |
| --------------- | --------------- | ------------------------------------------------------------ |
| `syncStarted`   | `syncStarted`   | A sync began                                                 |
| `syncCompleted` | `syncCompleted` | It finished. `toolsSynced` counts the tools written.         |
| `syncFailed`    | `syncFailed`    | It failed. `message`, `errorType`, and `error` describe why. |

The event is a discriminated union: `type` names the variant, and the key matching `type` carries the payload. A sync is a `syncStarted` followed by exactly one `syncCompleted` or `syncFailed`. To block a setup script until the tools exist, poll this log after creating the set and stop on the first terminal event newer than your create.

## `syncCompleted` does not mean every tool synced

This is the part to handle. A `syncCompleted` carries a `message` when some tools failed even though the sync as a whole succeeded. `toolsSynced` counts what landed; the message lists what did not.

```json theme={null}
{ "type": "syncCompleted",
  "syncCompleted": {
    "toolsSynced": 3,
    "message": "Some tools could not be synced:\n- tool_...: constraint failed: ..." } }
```

So a green `syncCompleted` is not proof the whole provider synced. Read `toolsSynced` against the count you expect, and read `message` when they differ:

```typescript theme={null}
const events = await client.toolSets.listEvents(toolSetId, { workspaceId });
for await (const event of events) {
  if (event.event?.type === 'syncCompleted') {
    const done = event.event.syncCompleted;
    if (done.message) console.warn(`partial sync: ${done.toolsSynced} synced,`, done.message);
  }
  if (event.event?.type === 'syncCompleted' || event.event?.type === 'syncFailed') break; // first terminal event
}
```

## Reading a failure

`syncFailed` carries three fields. `message` is the human-readable summary, `errorType` is a machine tag for grouping, and `error` holds the underlying detail:

```typescript theme={null}
if (event.event?.type === 'syncFailed') {
  const failed = event.event.syncFailed;
  failed.message;    // "Some tools could not be synced: ..."
  failed.errorType;  // a category tag, may be empty
  failed.error;      // the raw provider or database error
}
```

The common causes are a provider your workspace cannot reach, an [MCP](/docs/guides/tool-sets/mcp) server that is down, an [OpenAPI](/docs/guides/tool-sets/openapi) URL that returns something other than a spec, or a bad credential in an adapter header. A failed sync leaves the previously synced tools in place; the set does not empty itself because a refresh failed.

## Cadence

You do not trigger a sync. Cadenya syncs when you create or update the adapter, and on its own cycle after that. An OpenAPI adapter fetched by URL re-syncs hourly, which is visible here as a `syncStarted` roughly every hour. `info.lastSync` on the [tool set](/docs/api-reference/toolservice/list-tool-sets) gives you the timestamp of the most recent *successful* sync without walking the log. It is omitted until a sync completes, so a set whose only syncs have failed has no `lastSync`.

`sortOrder`, `limit`, and `cursor` page the history the usual way; the SDK iterator follows the cursor for you.

## Related

<CardGroup cols={2}>
  <Card title="Create a tool set" icon="wrench" href="/docs/api-reference/toolservice/create-a-new-tool-set">
    What a sync discovers, and the filters it applies each time.
  </Card>

  <Card title="List tools" icon="list" href="/docs/api-reference/toolservice/list-tools">
    The tools a completed sync wrote.
  </Card>

  <Card title="List tool sets" icon="layer-group" href="/docs/api-reference/toolservice/list-tool-sets">
    `info.lastSync` and the live tool count.
  </Card>

  <Card title="Connect an MCP server" icon="plug" href="/docs/guides/tool-sets/mcp">
    The hands-on path, from URL to a synced tool.
  </Card>
</CardGroup>


## OpenAPI

````yaml get /v1/workspaces/{workspaceId}/tool_sets/{toolSetId}/events
openapi: 3.1.0
info:
  title: Cadenya API
  description: API for the Cadenya Agent Runtime platform.
  version: '1.0'
servers:
  - url: https://api.cadenya.com
    description: Production server
security:
  - bearerAuth: []
tags:
  - name: AIProviderKeyService
  - name: APIKeyService
    description: |-
      Issue, rotate, disable, and revoke a workspace's API keys. Every key
       belongs to exactly one workspace; the system-managed global account key is
       managed via GlobalAPIKeyService instead.
  - name: AccountService
    description: >-
      Manage the authenticated account. Accounts are the top-level
      organizational
       unit and contain one or more workspaces.
  - name: AgentScheduleService
    description: >-
      Manage recurring schedules attached to agents. Schedules trigger
      objectives
       on a cadence defined by AgentScheduleSpec.Schedule.
  - name: AgentService
    description: >-
      Manage AI agents within a workspace. Agents define AI behavior and tool
      access.
  - name: AgentVariationService
    description: >-
      Manage variations of an agent and their tool, sub-agent, and memory layer
      assignments.
  - name: GlobalAPIKeyService
    description: |-
      Manage the account's system-provisioned global API key. The global key is
       the only key that spans every workspace; it is created by the system and
       cannot be deleted, so the surface is retrieve, rotate, and the
       disable/enable kill switch.
  - name: MemoryService
    description: >-
      Manage memory layers and their entries. Layers are named containers that
      can
       be composed into an objective's memory cascade; entries are the keyed values
       within a layer. System-managed layers (e.g., episodic layers created by the
       runtime) cannot be mutated through this API.
  - name: ModelService
    description: |-
      Manage LLM models available to a workspace. Models represent provider and
       family pairs (e.g., "anthropic/claude-sonnet-4.6"). Workspaces are seeded
       with the supported models and you can enable or disable each one.
  - name: ObjectiveEventStreamsService
  - name: ObjectiveService
  - name: ProfilesService
    description: |-
      Operations on profiles, the account-level principals (users, API keys,
       system) that authenticate against the API.
  - name: SearchService
  - name: TenantService
    description: >-
      Read and erase tenants and the subjects under them. Tenants and subjects
      are
       created by assertion — on objective creation or widget session mint — never
       directly, so this service has no create or update: it exists to enumerate what
       assertions have produced, and to destroy it on request.
  - name: ToolService
    description: >-
      Manage tool sets and the tools they contain. Tool sets group related
      tools,
       and tools define specific capabilities available to agents.

       When a tool set is managed, only API key actors can modify its tools; human
       (profile) actors cannot.
  - name: UploadService
    description: |-
      Issue short-lived presigned URLs for direct client-to-object-storage
       uploads. Created uploads can be referenced by id when creating or updating
       resources that accept binary content (e.g., MemoryEntry).
  - name: WidgetService
    description: |-
      Manage embeddable chat widgets. A widget binds an agent to a globally
       unique hostname with a per-widget origin allowlist; browsers reach it with
       session tokens minted via WidgetSessionService.
  - name: WidgetSessionService
    description: >-
      Mint and manage widget sessions. Session creation is server-to-server
      only:
       the customer's backend authenticates its visitor, asserts tenant/subject
       context, attaches any per-visitor secrets, and receives a short-lived
       bearer token the browser uses against the widget host.
  - name: WorkspaceAdminService
    description: >-
      Administer workspaces across the account: create and archive workspaces
      and
       manage their membership. These operations are account-scoped and require the
       admin role (a token whose profile holds the WorkOS admin role); they live
       under /v1/account/workspaces rather than the workspace-scoped /v1/workspaces
       tree so an admin can manage any workspace in the account, including ones they
       are not themselves a member of.
  - name: WorkspaceSecretService
  - name: WorkspaceService
    description: |-
      Manage workspaces within an account. Workspaces provide organizational
       grouping and isolation for resources such as agents, tools, and API keys.

       This is the workspace-scoped, end-user surface. Administrative operations
       (create / archive workspaces, manage members) live in WorkspaceAdminService
       under /v1/account/workspaces and require the admin role.
paths:
  /v1/workspaces/{workspaceId}/tool_sets/{toolSetId}/events:
    get:
      tags:
        - ToolService
        - Tool Sets
      summary: List tool set events
      description: Lists all events (including sync status) for a tool set
      operationId: ToolService_ListToolSetEvents
      parameters:
        - name: workspaceId
          in: path
          description: Workspace ID.
          required: true
          schema:
            type: string
            example: workspace_01HXKD2E5NQM3T9AYWCF133E3Q
        - name: toolSetId
          in: path
          description: |-
            Tool set ID. Accepts the canonical ts_… form or the
             external_id:<value> form.
          required: true
          schema:
            example: toolset_01HXKD2E5NQM3T9AYWCFNRMN74
            type: string
        - name: limit
          in: query
          description: Maximum number of results to return
          schema:
            type: integer
            format: int32
        - name: cursor
          in: query
          description: Pagination cursor from previous response
          schema:
            type: string
        - name: sortOrder
          in: query
          description: Sort order for results (asc or desc by creation time)
          schema:
            type: string
        - name: includeInfo
          in: query
          description: When set to true you may use more of your alloted API rate-limit
          schema:
            type: boolean
        - name: labels
          in: query
          description: |-
            Filters by metadata labels. Comma-separated key=value pairs,
             e.g. "env=prod,team=ai". A resource matches only if every pair
             matches exactly (AND semantics).
          schema:
            type: string
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListToolSetEventsResponse'
        default:
          description: Default error response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Status'
      x-codeSamples:
        - lang: JavaScript
          source: >-
            import Cadenya from '@cadenya/cadenya';


            const client = new Cadenya({
              apiKey: process.env['CADENYA_API_KEY'], // This is the default and can be omitted
            });


            // Automatically fetches more pages as needed.

            for await (const toolSetEvent of
            client.toolSets.listEvents('toolset_01HXKD2E5NQM3T9AYWCFNRMN74', {
              workspaceId: 'workspace_01HXKD2E5NQM3T9AYWCF133E3Q',
            })) {
              console.log(toolSetEvent.metadata);
            }
        - lang: Python
          source: |-
            import os
            from cadenya import Cadenya

            client = Cadenya(
                api_key=os.environ.get("CADENYA_API_KEY"),  # This is the default and can be omitted
            )
            page = client.tool_sets.list_events(
                tool_set_id="toolset_01HXKD2E5NQM3T9AYWCFNRMN74",
                workspace_id="workspace_01HXKD2E5NQM3T9AYWCF133E3Q",
            )
            page = page.items[0]
            print(page.metadata)
        - lang: Go
          source: "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"go.cadenya.com/cadenya-go\"\n\t\"go.cadenya.com/cadenya-go/option\"\n)\n\nfunc main() {\n\tclient := cadenya.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tpage, err := client.ToolSets.ListEvents(\n\t\tcontext.TODO(),\n\t\t\"toolset_01HXKD2E5NQM3T9AYWCFNRMN74\",\n\t\tcadenya.ToolSetListEventsParams{\n\t\t\tWorkspaceID: cadenya.String(\"workspace_01HXKD2E5NQM3T9AYWCF133E3Q\"),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", page)\n}\n"
        - lang: Ruby
          source: |-
            require "cadenya"

            cadenya = Cadenya::Client.new(api_key: "My API Key")

            page = cadenya.tool_sets.list_events(
              "toolset_01HXKD2E5NQM3T9AYWCFNRMN74",
              workspace_id: "workspace_01HXKD2E5NQM3T9AYWCF133E3Q"
            )

            puts(page)
        - lang: CLI
          source: |-
            cadenya tool-sets list-events \
              --api-key 'My API Key' \
              --workspace-id workspace_01HXKD2E5NQM3T9AYWCF133E3Q \
              --tool-set-id toolset_01HXKD2E5NQM3T9AYWCFNRMN74
components:
  schemas:
    ListToolSetEventsResponse:
      type: object
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/ToolSetEvent'
        pagination:
          $ref: '#/components/schemas/Page'
    Status:
      type: object
      properties:
        code:
          type: integer
          description: >-
            The status code, which should be an enum value of
            [google.rpc.Code][google.rpc.Code].
          format: int32
        message:
          type: string
          description: >-
            A developer-facing error message, which should be in English. Any
            user-facing error message should be localized and sent in the
            [google.rpc.Status.details][google.rpc.Status.details] field, or
            localized by the client.
        details:
          type: array
          items:
            $ref: '#/components/schemas/GoogleProtobufAny'
          description: >-
            A list of messages that carry the error details.  There is a common
            set of message types for APIs to use.
      description: >-
        The `Status` type defines a logical error model that is suitable for
        different programming environments, including REST APIs and RPC APIs. It
        is used by [gRPC](https://github.com/grpc). Each `Status` message
        contains three pieces of data: error code, error message, and error
        details. You can find out more about this error model and how to work
        with it in the [API Design
        Guide](https://cloud.google.com/apis/design/errors).
    ToolSetEvent:
      required:
        - metadata
      type: object
      properties:
        metadata:
          allOf:
            - $ref: '#/components/schemas/OperationMetadata'
          description: Metadata for this operation event.
        toolSetId:
          readOnly: true
          example: toolset_01HXKD2E5NQM3T9AYWCFNRMN74
          type: string
          description: The tool set this event is associated with.
        event:
          allOf:
            - $ref: '#/components/schemas/ToolSetEventData'
          description: The event payload.
        info:
          $ref: '#/components/schemas/ToolSetEventInfo'
      description: A single event in the tool set's operation timeline.
    Page:
      type: object
      properties:
        nextCursor:
          type: string
      description: >-
        Page carries cursor-based pagination state. There is no total: the
        cursor
         walks the result set without ever counting it, and a count would cost a second
         query on every list.
    GoogleProtobufAny:
      type: object
      properties:
        '@type':
          type: string
          description: The type of the serialized message.
      additionalProperties: true
      description: >-
        Contains an arbitrary serialized message along with a @type that
        describes the type of the serialized message.
    OperationMetadata:
      required:
        - id
        - accountId
        - workspaceId
        - profileId
        - createdAt
      type: object
      properties:
        id:
          readOnly: true
          type: string
          description: >-
            Unique identifier for the operation (prefixed ULID, e.g.,
            "obj_01HXK...")
        accountId:
          readOnly: true
          example: account_01HXKD2E5NQM3T9AYWCFTJHJVF
          type: string
          description: >-
            Account this operation belongs to for multi-tenant isolation
            (prefixed ULID)
        workspaceId:
          readOnly: true
          example: workspace_01HXKD2E5NQM3T9AYWCF133E3Q
          type: string
          description: >-
            Workspace this operation belongs to for organizational grouping
            (prefixed ULID)
        labels:
          type: object
          additionalProperties:
            type: string
          description: |-
            Key-value pairs for categorization and filtering. Values are 0-63
             alphanumeric characters with "-", "_", or "." allowed between; keys
             follow the same shape and additionally accept an optional DNS-subdomain
             prefix (e.g. "cadenya.com/") of at most 253 characters.
             Examples: {"priority": "high", "source": "api", "workflow": "onboarding"}
        createdAt:
          readOnly: true
          type: string
          description: |-
            Timestamp when this operation was created
             ULID includes timestamp information, but this explicit field enables easier querying
          format: date-time
        externalId:
          type: string
          description: >-
            External ID for the operation (e.g., a workflow ID from an external
            system)
        profileId:
          readOnly: true
          example: profile_01HXKD2E5NQM3T9AYWCFS0AP08
          type: string
          description: >-
            ID of the actor (user or service account) that created this
            operation
      description: >-
        Metadata for ephemeral operations and activities (e.g., objectives,
        executions, runs)
    ToolSetEventData:
      oneOf:
        - $ref: '#/components/schemas/ToolSetEventData_SyncStarted'
        - $ref: '#/components/schemas/ToolSetEventData_SyncCompleted'
        - $ref: '#/components/schemas/ToolSetEventData_SyncFailed'
      discriminator:
        propertyName: type
        mapping:
          syncStarted:
            $ref: '#/components/schemas/ToolSetEventData_SyncStarted'
          syncCompleted:
            $ref: '#/components/schemas/ToolSetEventData_SyncCompleted'
          syncFailed:
            $ref: '#/components/schemas/ToolSetEventData_SyncFailed'
      description: Event payload for a tool set operation.
    ToolSetEventInfo:
      type: object
      properties:
        toolSet:
          $ref: '#/components/schemas/ResourceMetadata'
        createdBy:
          $ref: '#/components/schemas/Profile'
    ToolSetEventData_SyncStarted:
      type: object
      required:
        - type
        - syncStarted
      properties:
        type:
          type: string
          enum:
            - syncStarted
        syncStarted:
          $ref: '#/components/schemas/SyncStarted'
    ToolSetEventData_SyncCompleted:
      type: object
      required:
        - type
        - syncCompleted
      properties:
        type:
          type: string
          enum:
            - syncCompleted
        syncCompleted:
          $ref: '#/components/schemas/SyncCompleted'
    ToolSetEventData_SyncFailed:
      type: object
      required:
        - type
        - syncFailed
      properties:
        type:
          type: string
          enum:
            - syncFailed
        syncFailed:
          $ref: '#/components/schemas/SyncFailed'
    ResourceMetadata:
      required:
        - id
        - accountId
        - workspaceId
        - name
        - profileId
        - createdAt
      type: object
      properties:
        id:
          readOnly: true
          type: string
          description: >-
            Unique identifier for the resource (prefixed ULID, e.g.,
            "agent_01HXK...")
        accountId:
          readOnly: true
          example: account_01HXKD2E5NQM3T9AYWCFTJHJVF
          type: string
          description: >-
            Account this resource belongs to for multi-tenant isolation
            (prefixed ULID)
        workspaceId:
          readOnly: true
          example: workspace_01HXKD2E5NQM3T9AYWCF133E3Q
          type: string
          description: >-
            Workspace this resource belongs to for organizational grouping
            (prefixed ULID)
        name:
          type: string
          description: >-
            Human-readable name for the resource (e.g., "Customer Support
            Agent", "Email Tool")
             Required for resources that users interact with directly
        externalId:
          type: string
          description: >-
            External ID for the resource (e.g., a workflow ID from an external
            system)
        labels:
          type: object
          additionalProperties:
            type: string
          description: |-
            Key-value pairs for categorization and filtering. Values are 0-63
             alphanumeric characters with "-", "_", or "." allowed between; keys
             follow the same shape and additionally accept an optional DNS-subdomain
             prefix (e.g. "cadenya.com/") of at most 253 characters.
             Examples: {"environment": "production", "team": "platform", "version": "v2"}
        profileId:
          readOnly: true
          example: profile_01HXKD2E5NQM3T9AYWCFS0AP08
          type: string
          description: ID of the actor (user or service account) that created this resource
        createdAt:
          readOnly: true
          type: string
          description: Timestamp when this resource was created
          format: date-time
        updatedAt:
          readOnly: true
          type: string
          description: Timestamp when this resource was last updated
          format: date-time
      description: >-
        Standard metadata for persistent, named resources (e.g., agents, tools,
        prompts)
    Profile:
      required:
        - metadata
        - spec
      type: object
      properties:
        metadata:
          $ref: '#/components/schemas/AccountResourceMetadata'
        spec:
          $ref: '#/components/schemas/ProfileSpec'
      description: |-
        A profile identifies a user or non-human principal (such as an API key)
         at the account level. Profiles are account-scoped and can be granted access
         to multiple workspaces.
    SyncStarted:
      type: object
      properties:
        message:
          type: string
          description: Human-readable message describing the start of the sync.
      description: Emitted when a tool set sync operation begins.
    SyncCompleted:
      type: object
      properties:
        toolsSynced:
          type: integer
          description: Number of tools synced.
          format: int32
        message:
          type: string
          description: Optional message with additional details.
      description: Emitted when a tool set sync operation completes successfully.
    SyncFailed:
      type: object
      properties:
        error:
          type: boolean
          description: Indicates this is an error event.
        message:
          type: string
          description: Error message describing what went wrong.
        errorType:
          type: string
          description: Optional error type/code for programmatic handling.
      description: Emitted when a tool set sync operation fails.
    AccountResourceMetadata:
      required:
        - id
        - accountId
        - name
        - profileId
      type: object
      properties:
        id:
          readOnly: true
          type: string
          description: >-
            Unique identifier for the resource (prefixed ULID, e.g.,
            "apikey_01HXK...")
        accountId:
          readOnly: true
          example: account_01HXKD2E5NQM3T9AYWCFTJHJVF
          type: string
          description: >-
            Account this resource belongs to for multi-tenant isolation
            (prefixed ULID)
        name:
          type: string
          description: >-
            Human-readable name for the resource (e.g., "Customer Support
            Agent", "Email Tool")
             Required for resources that users interact with directly
        externalId:
          type: string
          description: >-
            External ID for the resource (e.g., a workflow ID from an external
            system)
        labels:
          type: object
          additionalProperties:
            type: string
          description: |-
            Key-value pairs for categorization and filtering. Values are 0-63
             alphanumeric characters with "-", "_", or "." allowed between; keys
             follow the same shape and additionally accept an optional DNS-subdomain
             prefix (e.g. "cadenya.com/") of at most 253 characters.
             Examples: {"environment": "production", "team": "platform", "version": "v2"}
        profileId:
          readOnly: true
          example: profile_01HXKD2E5NQM3T9AYWCFS0AP08
          type: string
        createdAt:
          readOnly: true
          type: string
          format: date-time
      description: >-
        AccountResourceMetadata is used to represent a resource that is
        associated to an account but not to a workspace.
    ProfileSpec:
      required:
        - type
      type: object
      properties:
        email:
          type: string
          description: >-
            Email address of the profile. Required and unique within an account
            for
             user profiles.
        name:
          type: string
          description: Display name (e.g., "Bobby Tables").
        type:
          enum:
            - PROFILE_TYPE_UNSPECIFIED
            - PROFILE_TYPE_USER
            - PROFILE_TYPE_API_KEY
            - PROFILE_TYPE_SYSTEM
          type: string
          description: >-
            Whether this profile represents a human user, an API key, or a
            system
             principal.
          format: enum
      description: Configuration for a profile.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

````