> ## 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.

# Quickstart

> Start with an empty workspace, build a Faker-powered agent in the dashboard, and watch its first objective from code.

Start with an empty workspace and build a published [agent](/docs/guides/agents) that creates synthetic conference attendee records. You create every resource this guide uses: an API key, a Faker [tool set](/docs/guides/tool-sets), an agent, and its variation. You then dispatch an [objective](/docs/guides/objectives) and stream its events from code.

## What you need

* A Cadenya account with access to a workspace.
* A model available in that workspace.
* A terminal with one of the supported SDKs or `curl`.

## Build the agent

<Steps>
  <Step title="Create an API key">
    Select **API Keys**, click **Create API Key**, and name the key `Quickstart`.

    Under **Objectives**, select **Manage**. This scope lets the key create objectives and read their event streams. Click **Create API key**, then copy the token.

    Find your workspace ID in the dashboard URL. It is the value after `/w/`, such as `workspace_01KZ950VW79SJGDGEMQPAYYCXR`.

    Export both values in your terminal:

    ```bash theme={null}
    export CADENYA_API_KEY='your-api-key'
    export CADENYA_WORKSPACE_ID='workspace_your-workspace-id'
    ```

    Cadenya shows the raw API key when you create or rotate it. If you lose the value, rotate the key and copy the replacement.
  </Step>

  <Step title="Create the Faker MCP tool set">
    Select **Tool Sets**, click **Create Tool Set**, and select **MCP**. Enter `https://free.cadenya.com/faker-mcp` as the **Server URL**.

    <Frame caption="The Faker MCP connection settings">
      <img src="https://mintcdn.com/cadenya/jVN0RLx9DL3HyxfK/images/docs/quickstart-ui/faker-mcp-connection.webp?fit=max&auto=format&n=jVN0RLx9DL3HyxfK&q=85&s=c27b491514f51d237ef4d40517aa7449" alt="MCP connection settings with MCP selected and the Faker server URL entered" width="1800" height="940" data-path="images/docs/quickstart-ui/faker-mcp-connection.webp" />
    </Frame>

    Click **Generate Preview**. The server exposes `GenerateFake`, `GetFakerOptions`, and `GenerateCurseWord`.

    <Frame caption="The tools exposed by Faker MCP">
      <img src="https://mintcdn.com/cadenya/jVN0RLx9DL3HyxfK/images/docs/quickstart-ui/faker-tools-preview.webp?fit=max&auto=format&n=jVN0RLx9DL3HyxfK&q=85&s=0bda53775c6b3daf5d6bddd0b99d90d9" alt="MCP Tools Preview card listing GenerateCurseWord, GenerateFake, and GetFakerOptions as available" width="1688" height="832" data-path="images/docs/quickstart-ui/faker-tools-preview.webp" />
    </Frame>

    Continue with the default tool behavior. Name the tool set `Faker MCP`, review the configuration, and click **Create Tool Set**.
  </Step>

  <Step title="Create the agent">
    Select **Agents**, click **Create Agent**, and enter:

    * **Name:** `Conference Attendee Generator`
    * **External ID:** `conference-attendee-generator`
    * **Description:** `Creates realistic synthetic conference attendee records for demos and tests with the Faker MCP tool set.`

    Leave webhooks, structured output, and episodic memory unset. Click **Create agent**.

    <Frame caption="The completed Create Agent form">
      <img src="https://mintcdn.com/cadenya/jVN0RLx9DL3HyxfK/images/docs/quickstart-ui/create-agent-form.webp?fit=max&auto=format&n=jVN0RLx9DL3HyxfK&q=85&s=f77fb948b42fa6953df798f8525c262e" alt="Create Agent form for Conference Attendee Generator with its external ID and Faker-focused description" width="1464" height="1072" data-path="images/docs/quickstart-ui/create-agent-form.webp" />
    </Frame>
  </Step>

  <Step title="Configure the variation">
    The agent opens with a **New Variation** form. Name the variation `Default` and paste this into **System prompt**:

    ```text theme={null}
    You create realistic synthetic conference attendee records for product demos and automated tests. For common attendee fields, use these Faker generators: name uses person.name, email uses internet.safe_email, phone uses phone.number, company uses company.name, job title uses company.job_title, city uses address.city, and country uses address.country. Call GenerateFake for every requested value. Use GetFakerOptions only when a requested field has no generator listed here. Complete the entire request before sending an assistant message. Never invent a value when Faker can generate it. Do not narrate or announce tool calls. Do not generate Social Security numbers, payment data, or passwords. Your only assistant message must be one concise JSON array with the requested fields and no surrounding prose.
    ```

    Under **Model configuration**, select a model available in your workspace and set **Temperature** to `0.2`. Set **Max tool calls** to `20`, then click **Create variation**.

    <Frame caption="The configured Default variation">
      <img src="https://mintcdn.com/cadenya/jVN0RLx9DL3HyxfK/images/docs/quickstart-ui/variation-form.webp?fit=max&auto=format&n=jVN0RLx9DL3HyxfK&q=85&s=41ecf8528acf12b74f9698b7f143b160" alt="Default variation form with the Faker system prompt, a selected model, 0.2 temperature, and a 20 tool-call limit" width="2006" height="2280" data-path="images/docs/quickstart-ui/variation-form.webp" />
    </Frame>
  </Step>

  <Step title="Assign Faker and publish">
    In the variation's **Assignments** card, click **Add**, keep the assignment type on **Tool Set**, search for `Faker MCP`, and select it.

    <Frame caption="Faker MCP assigned to the variation">
      <img src="https://mintcdn.com/cadenya/jVN0RLx9DL3HyxfK/images/docs/quickstart-ui/faker-assignment.webp?fit=max&auto=format&n=jVN0RLx9DL3HyxfK&q=85&s=d959e2f64ba51d8cfdb8e54218481ebb" alt="Assignments card showing one tool set named Faker MCP" width="1910" height="238" data-path="images/docs/quickstart-ui/faker-assignment.webp" />
    </Frame>

    In the agent's **Details** card, open the **Draft** status menu and select **Publish**. Published agents accept objectives.

    <Frame caption="The published agent">
      <img src="https://mintcdn.com/cadenya/jVN0RLx9DL3HyxfK/images/docs/quickstart-ui/published-agent-details.webp?fit=max&auto=format&n=jVN0RLx9DL3HyxfK&q=85&s=69fe9315a4431e6510a7ba2e50feabef" alt="Agent Details card showing conference-attendee-generator as the external ID and Published as the status" width="840" height="840" data-path="images/docs/quickstart-ui/published-agent-details.webp" />
    </Frame>
  </Step>
</Steps>

## Dispatch an objective

Choose your language and run one example. Each request uses the agent's external ID, so you do not need to copy its Cadenya ID.

<CodeGroup>
  ```typescript TypeScript theme={null}
  import Cadenya from '@cadenya/cadenya';

  const client = new Cadenya({ apiKey: process.env['CADENYA_API_KEY'] });
  const workspaceId = process.env['CADENYA_WORKSPACE_ID']!;

  const objective = await client.objectives.create({
    workspaceId,
    agentId: 'external_id:conference-attendee-generator',
    systemPromptData: {},
    firstUserMessage:
      'Create two conference attendee records with a name, email, phone, company, job title, city, and country. Return JSON.',
  });

  console.log(objective.metadata.id);
  ```

  ```go Go theme={null}
  package main

  import (
  	"context"
  	"log"
  	"os"

  	"go.cadenya.com/cadenya-go"
  	"go.cadenya.com/cadenya-go/option"
  )

  func main() {
  	client := cadenya.NewClient(
  		option.WithWorkspaceID(os.Getenv("CADENYA_WORKSPACE_ID")),
  	)

  	objective, err := client.Objectives.New(context.Background(), cadenya.ObjectiveNewParams{
  		AgentID:          "external_id:conference-attendee-generator",
  		SystemPromptData: map[string]any{},
  		FirstUserMessage: cadenya.String("Create two conference attendee records with a name, email, phone, company, job title, city, and country. Return JSON."),
  	})
  	if err != nil {
  		log.Fatal(err)
  	}

  	log.Println(objective.Metadata.ID)
  }
  ```

  ```ruby Ruby theme={null}
  require "cadenya"

  client = Cadenya::Client.new(api_key: ENV["CADENYA_API_KEY"])

  objective = client.objectives.create(
    workspace_id: ENV["CADENYA_WORKSPACE_ID"],
    agent_id: "external_id:conference-attendee-generator",
    system_prompt_data: {},
    first_user_message: "Create two conference attendee records with a name, email, phone, company, job title, city, and country. Return JSON."
  )

  puts objective.metadata.id
  ```

  ```bash cURL theme={null}
  curl "https://api.cadenya.com/v1/workspaces/${CADENYA_WORKSPACE_ID}/objectives" \
    -H "Authorization: Bearer ${CADENYA_API_KEY}" \
    -H "Content-Type: application/json" \
    -d '{
          "agentId": "external_id:conference-attendee-generator",
          "systemPromptData": {},
          "firstUserMessage": "Create two conference attendee records with a name, email, phone, company, job title, city, and country. Return JSON."
        }'
  ```
</CodeGroup>

The create call returns while the objective is **Pending**. Open **Objectives** in the dashboard and select the returned objective ID. Its timeline shows the Faker tool calls, their results, and the agent's JSON response.

## Stream objective events

An event stream starts with events emitted after the connection opens. Create another objective and connect immediately so a short run cannot finish before the watcher is ready. Choose an example to watch the agent's messages and tool activity through [server-sent events](/docs/api-reference/objectiveeventstreamsservice/stream-objective-events).

<CodeGroup>
  ```typescript TypeScript theme={null}
  import Cadenya from '@cadenya/cadenya';

  const client = new Cadenya({ apiKey: process.env['CADENYA_API_KEY'] });
  const workspaceId = process.env['CADENYA_WORKSPACE_ID']!;

  const objective = await client.objectives.create({
    workspaceId,
    agentId: 'external_id:conference-attendee-generator',
    systemPromptData: {},
    firstUserMessage:
      'Create one conference attendee record with a name and email. Return JSON.',
  });

  const stream = await client.objectives.streamEvents(
    objective.metadata.id,
    { workspaceId },
  );

  events:
  for await (const event of stream) {
    const data = event.data;

    switch (data.type) {
      case 'toolCalled': {
        const called = data.toolCalled.tool;
        const name =
          called?.type === 'tool' ? called.tool.name :
          called?.type === 'agent' ? called.agent.name :
          '(built-in)';

        console.log(`Tool called: ${name}`);
        break;
      }
      case 'toolResult':
        console.log(`Tool completed: ${data.toolResult.toolCallId}`);
        break;
      case 'assistantMessage': {
        const content = data.assistantMessage.content;
        if (content) console.log(content);
        break;
      }
      case 'finalized':
      case 'cancelled':
      case 'timedOut':
      case 'error':
        break events;
    }
  }
  ```

  ```bash cURL theme={null}
  CADENYA_OBJECTIVE_ID="$(
    curl --silent \
      "https://api.cadenya.com/v1/workspaces/${CADENYA_WORKSPACE_ID}/objectives" \
      -H "Authorization: Bearer ${CADENYA_API_KEY}" \
      -H "Content-Type: application/json" \
      -d '{
            "agentId": "external_id:conference-attendee-generator",
            "systemPromptData": {},
            "firstUserMessage": "Create one conference attendee record with a name and email. Return JSON."
          }' |
      jq --raw-output '.metadata.id'
  )"

  curl -N \
    "https://api.cadenya.com/v1/workspaces/${CADENYA_WORKSPACE_ID}/objectives/${CADENYA_OBJECTIVE_ID}/events:stream" \
    -H "Authorization: Bearer ${CADENYA_API_KEY}" \
    -H "Accept: text/event-stream"
  ```
</CodeGroup>

`event.data` is a discriminated union in the TypeScript SDK. Switching on `data.type` narrows `data` to the matching event interface, so fields such as `toolCalled` and `assistantMessage` are type-safe inside their cases.

Both streams stay open because this agent has no structured output definition and can accept another message. Press `Ctrl+C` after the agent prints its final JSON response.

<Check>
  You now have a published agent that creates synthetic attendee data through a live MCP server, plus an event stream that exposes its work as it happens.
</Check>

## Next steps

<CardGroup cols={2}>
  <Card title="Build resilient event streams" icon="timeline" href="/docs/api-reference/objectiveeventstreamsservice/stream-objective-events">
    Resume after disconnects and handle every terminal event.
  </Card>

  <Card title="Build an agent that improves" icon="chart-line" href="/docs/guides/agents">
    Add another variation and use feedback to steer traffic.
  </Card>

  <Card title="Connect another MCP server" icon="plug" href="/docs/guides/tool-sets/mcp">
    Connect a server, inspect its tools, and control approvals.
  </Card>

  <Card title="Use structured output" icon="brackets-curly" href="/docs/guides/get-structured-output">
    Validate the final records against a JSON Schema.
  </Card>
</CardGroup>
