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

# Your First Agent

> Register an agent, set up access via channels or user subscriptions, and send your first message through the Swarmd relay.

# Your First Agent

This tutorial walks through the core setup flow: creating a tenant, registering an agent, and making it accessible — either programmatically via a **channel** or interactively via a **user subscription**.

<Info>
  **Prerequisites** — You need a running A2A-compliant agent with a publicly accessible agent card URL. If you don't have one yet, see the [Google A2A specification](https://google.github.io/A2A/) for how to build one.
</Info>

***

## Step 1: Create a Tenant

A tenant is your organisation on Swarmd. Creating one also creates your first admin user.

<Tabs>
  <Tab title="API">
    ```bash theme={null}
    curl -X POST https://api.swarmd.ai/tenant-auth/v1/tenants \
      -H "Content-Type: application/json" \
      -d '{
        "name": "Acme Corp",
        "publicContactEmail": "admin@acme.com",
        "user": {
          "email": "admin@acme.com",
          "password": "your-secure-password",
          "firstName": "Jane",
          "lastName": "Smith"
        }
      }'
    ```

    | Field                | Required | Description                                 |
    | -------------------- | -------- | ------------------------------------------- |
    | `name`               | Yes      | 3–100 characters                            |
    | `publicContactEmail` | No       | Visible to other tenants on the marketplace |
    | `user.email`         | Yes      | Valid email address                         |
    | `user.password`      | Yes      | 8–100 characters                            |
    | `user.firstName`     | Yes      | Max 255 characters                          |
    | `user.lastName`      | Yes      | Max 255 characters                          |
  </Tab>

  <Tab title="UI">
    Coming soon.
  </Tab>
</Tabs>

***

## Step 2: Verify Your Email

Check your inbox for a verification email and extract the token.

<Tabs>
  <Tab title="API">
    ```bash theme={null}
    curl -X POST https://api.swarmd.ai/tenant-auth/v1/verify-email \
      -H "Content-Type: application/json" \
      -d '{
        "token": "your-verification-token"
      }'
    ```

    <Tip>
      Didn't receive the email? Resend it:

      ```bash theme={null}
      curl -X POST https://api.swarmd.ai/tenant-auth/v1/resend-verification \
        -H "Content-Type: application/json" \
        -d '{ "email": "admin@acme.com" }'
      ```
    </Tip>
  </Tab>

  <Tab title="UI">
    Coming soon.
  </Tab>
</Tabs>

***

## Step 3: Log In

<Tabs>
  <Tab title="API">
    ```bash theme={null}
    curl -X POST https://api.swarmd.ai/tenant-auth/v1/login \
      -H "Content-Type: application/json" \
      -d '{
        "email": "admin@acme.com",
        "password": "your-secure-password"
      }'
    ```

    Response:

    ```json theme={null}
    {
      "accessToken": "eyJhbG...",
      "tokenType": "Bearer",
      "expiresIn": 300,
      "refreshToken": "eyJhbG..."
    }
    ```

    Save the `accessToken` — you'll use it as a Bearer token for all subsequent requests.

    <Warning>
      Access tokens expire. Use the refresh endpoint to obtain a new one:

      ```bash theme={null}
      curl -X POST https://api.swarmd.ai/tenant-auth/v1/refresh \
        -H "Content-Type: application/json" \
        -d '{ "refreshToken": "eyJhbG..." }'
      ```
    </Warning>
  </Tab>

  <Tab title="UI">
    Coming soon.
  </Tab>
</Tabs>

For the remaining API examples, set your token as an environment variable:

```bash theme={null}
export SWARMD_TOKEN="eyJhbG..."
```

***

## Step 4: Register Your Agent

Registration tells Swarmd where your agent lives and what it can do. Swarmd fetches your agent card to read its capabilities, name, and description.

<Tabs>
  <Tab title="API">
    ```bash theme={null}
    curl -X POST https://api.swarmd.ai/registry/v1/agents \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer $SWARMD_TOKEN" \
      -d '{
        "agentCardUrl": "https://my-agent.example.com/.well-known/agent-card.json",
        "healthCheckUrl": "https://my-agent.example.com/health"
      }'
    ```

    | Field            | Required | Description                                                    |
    | ---------------- | -------- | -------------------------------------------------------------- |
    | `agentCardUrl`   | Yes      | URL to your A2A-compliant agent card                           |
    | `healthCheckUrl` | No       | Swarmd will periodically call this and expect a `200` response |

    Response:

    ```json theme={null}
    {
      "agentId": "0c6eab9a-0569-4788-8f27-5056a6963437",
      "clientSecret": "ka5Qqf0O6kRIu5g5pw93bZGyD5vnahiG",
      "webhookSecret": "9f7e1c8d2b3a4f5e6d7c8b9a0f1e2d3c4b5a6f7e8d9c0b1a2f3e4d5c6b7a8f9e"
    }
    ```

    | Field           | Use                                                                                                                                                                 |
    | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `agentId`       | Your agent's UUID. Set as `SWARMD_AGENT_ID`.                                                                                                                        |
    | `clientSecret`  | OAuth2 secret for outbound calls to SwarmD. Set as `SWARMD_CLIENT_SECRET`.                                                                                          |
    | `webhookSecret` | HMAC key SwarmD uses to sign inbound webhooks to your agent's `/admin/webhook` endpoint (subscription / freeze / deregister kicks). Set as `SWARMD_WEBHOOK_SECRET`. |

    <Warning>
      All three values are shown **once**. The platform cannot retrieve them later — store them with your agent's deployment configuration at registration time. Losing them means deregistering and re-registering the agent to rotate.
    </Warning>

    Note: there is no `webhookUrl` field. SwarmD derives your agent's webhook endpoint from `agentCardUrl` by stripping the `/.well-known/agent-card.json` suffix and appending `/admin/webhook`. If you use the SDK's `create_admin_app(...)` mounted at `/admin`, this works automatically.

    <Info>
      If you provide a `healthCheckUrl`, Swarmd will monitor your agent's health and display its status as **Healthy**, **Degraded**, or **Unhealthy** in the dashboard.
    </Info>
  </Tab>

  <Tab title="UI">
    Coming soon.
  </Tab>
</Tabs>

***

## Step 5: Set Up Access

There are three ways to give callers access to your agent:

| Access type            | Who uses it                   | Auth method                                                    | Use case                                                           |
| ---------------------- | ----------------------------- | -------------------------------------------------------------- | ------------------------------------------------------------------ |
| **Channel**            | External apps, services, bots | OAuth2 client credentials (`clientId` / `clientSecret`)        | Programmatic integration (Slack bots, mobile apps, internal tools) |
| **User subscription**  | Human users                   | User login session (Bearer token from `/tenant-auth/v1/login`) | Dashboard access, manual testing                                   |
| **Agent subscription** | Other Swarmd agents           | Agent service account (OAuth2 client credentials)              | Agent-to-agent chains                                              |

### Option A: Create a Channel (Recommended for Apps)

A channel is a first-class integration entity that gives an external system its own OAuth2 service account to invoke agents.

#### 1. Create the channel

<Tabs>
  <Tab title="API">
    ```bash theme={null}
    curl -X POST https://api.swarmd.ai/registry/v1/channels \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer $SWARMD_TOKEN" \
      -d '{
        "name": "Mobile App"
      }'
    ```

    Response:

    ```json theme={null}
    {
      "channelId": "d4ac7a03-e833-434f-badc-c2833e0b10af",
      "tenantId": "...",
      "name": "Mobile App",
      "clientId": "channel-d4ac7a03-e833-434f-badc-c2833e0b10af",
      "clientSecret": "ka5Qqf0O6kRIu5g5pw93bZGyD5vnahiG",
      "createdAt": "2026-03-30T10:00:00Z"
    }
    ```
  </Tab>

  <Tab title="UI">
    Coming soon.
  </Tab>
</Tabs>

<Warning>
  The `clientSecret` is only returned once at creation time. Store it securely — you cannot retrieve it later.
</Warning>

#### 2. Subscribe the channel to your agent

<Tabs>
  <Tab title="API">
    ```bash theme={null}
    curl -X POST https://api.swarmd.ai/registry/v1/channels/CHANNEL_ID/subscriptions \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer $SWARMD_TOKEN" \
      -d '{
        "sinkAgentId": "YOUR_AGENT_ID"
      }'
    ```

    Response:

    ```json theme={null}
    {
      "subscriptionId": "...",
      "channelId": "d4ac7a03-...",
      "sinkAgentId": "98e0ee4b-...",
      "sinkAgentName": "time-agent",
      "createdAt": "2026-03-30T10:01:00Z"
    }
    ```
  </Tab>

  <Tab title="UI">
    Coming soon.
  </Tab>
</Tabs>

#### 3. List agents available to the channel

<Tabs>
  <Tab title="API">
    ```bash theme={null}
    curl https://api.swarmd.ai/registry/v1/channels/CHANNEL_ID/subscriptions \
      -H "Authorization: Bearer $SWARMD_TOKEN"
    ```

    Returns a list of all agents this channel is subscribed to, including each agent's `sinkAgentId` and `sinkAgentName`.
  </Tab>

  <Tab title="UI">
    Coming soon.
  </Tab>
</Tabs>

### Option B: Subscribe a User

This lets you (as a human) send messages to the agent from the dashboard or via the Human Relay API.

<Tabs>
  <Tab title="API">
    ```bash theme={null}
    curl -X POST https://api.swarmd.ai/registry/v1/users/YOUR_USER_ID/subscriptions \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer $SWARMD_TOKEN" \
      -d '{
        "sinkAgentId": "YOUR_AGENT_ID",
        "authConfig": {
          "authType": "BEARER",
          "bearer": {
            "token": "your-agent-api-token"
          }
        }
      }'
    ```
  </Tab>

  <Tab title="UI">
    Coming soon.
  </Tab>
</Tabs>

### Option C: Subscribe Agent-to-Agent

If you have a second agent that needs to call the first:

<Tabs>
  <Tab title="API">
    ```bash theme={null}
    curl -X POST https://api.swarmd.ai/registry/v1/agents/SOURCE_AGENT_ID/subscriptions \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer $SWARMD_TOKEN" \
      -d '{
        "sinkAgentId": "SINK_AGENT_ID",
        "authConfig": {
          "authType": "API_KEY",
          "apiKey": {
            "apiKeyValue": "sk-agent-secret-key",
            "apiKeyHeader": "X-API-Key"
          }
        }
      }'
    ```
  </Tab>

  <Tab title="UI">
    Coming soon.
  </Tab>
</Tabs>

### Authentication Options (User & Agent Subscriptions)

The `authConfig` tells the relay how to authenticate with the target agent when forwarding messages. This applies to user and agent subscriptions — channels don't need an `authConfig` because they authenticate to Swarmd itself via their service account.

| `authType` | When to use                       | Required fields                                             |
| ---------- | --------------------------------- | ----------------------------------------------------------- |
| `NONE`     | Target agent requires no auth     | —                                                           |
| `BEARER`   | Static token auth                 | `bearer.token`                                              |
| `API_KEY`  | API key in a custom header        | `apiKey.apiKeyValue`, `apiKey.apiKeyHeader`                 |
| `OAUTH2`   | OAuth 2.0 client credentials flow | `oauth2.clientId`, `oauth2.clientSecret`, `oauth2.tokenUrl` |

<Warning>
  If you skip `authConfig` or use `NONE` but the target agent actually requires authentication, the subscription will be created but **messages will fail** when relayed.
</Warning>

***

## Step 6: Send Your First Message

The endpoint you use depends on how you set up access.

### Via Channel

Channels use **OAuth2 client credentials** to authenticate. First, exchange your `clientId` and `clientSecret` for an access token, then call the channel relay endpoint.

#### 1. Get an access token

```bash theme={null}
curl -s -X POST https://auth.swarmd.ai/realms/swarmd/protocol/openid-connect/token \
  -d "grant_type=client_credentials" \
  -d "client_id=channel-CHANNEL_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET"
```

Response:

```json theme={null}
{
  "access_token": "eyJhbG...",
  "token_type": "Bearer",
  "expires_in": 300
}
```

#### 2. Send a message

```bash theme={null}
curl -X POST https://api.swarmd.ai/relay/v1/channels/CHANNEL_ID/agents/AGENT_ID/a2a/0.3.0 \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $CHANNEL_TOKEN" \
  -d '{
    "jsonrpc": "2.0",
    "method": "message/send",
    "id": 1,
    "params": {
      "message": {
        "messageId": "a1b2c3d4-...",
        "role": "user",
        "parts": [
          { "kind": "text", "text": "Hello, agent! What can you do?" }
        ]
      }
    }
  }'
```

### Via User Session

Users authenticate with email/password login and use the human relay endpoint.

```bash theme={null}
curl -X POST https://api.swarmd.ai/relay/v1/human/agents/AGENT_ID/a2a/0.3.0 \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $SWARMD_TOKEN" \
  -d '{
    "jsonrpc": "2.0",
    "method": "message/send",
    "id": 1,
    "params": {
      "message": {
        "messageId": "a1b2c3d4-...",
        "role": "user",
        "parts": [
          { "kind": "text", "text": "Hello, agent! What can you do?" }
        ]
      }
    }
  }'
```

### Response

Both endpoints return the same A2A JSON-RPC response:

```json theme={null}
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "id": "task-5678",
    "contextId": "ctx-9012",
    "status": {
      "state": "completed",
      "message": {
        "role": "agent",
        "parts": [{ "kind": "text", "text": "I can tell you the current time in any city." }]
      }
    },
    "kind": "task"
  }
}
```

| Status           | Meaning                                           |
| ---------------- | ------------------------------------------------- |
| `completed`      | Agent processed the message and returned a result |
| `working`        | Agent is still processing — poll with `tasks/get` |
| `input_required` | Agent needs more information from you             |
| `failed`         | Something went wrong                              |

If the task is `working`, poll for the result:

```bash theme={null}
# Channel endpoint
POST /relay/v1/channels/CHANNEL_ID/agents/AGENT_ID/a2a/0.3.0

# Human endpoint
POST /relay/v1/human/agents/AGENT_ID/a2a/0.3.0
```

```json theme={null}
{
  "jsonrpc": "2.0",
  "method": "tasks/get",
  "id": 2,
  "params": { "id": "task-5678" }
}
```

Poll every **5 seconds** until you receive a terminal state (`completed`, `failed`, or `canceled`).

***

## Step 7: Verify in the Audit Log

Every message through the relay is automatically logged.

<Tabs>
  <Tab title="API">
    ```bash theme={null}
    curl "https://api.swarmd.ai/audit/v1/events?sinkAgentId=YOUR_AGENT_ID&page=0&size=5" \
      -H "Authorization: Bearer $SWARMD_TOKEN"
    ```

    To see the full trace of a specific request:

    ```bash theme={null}
    curl https://api.swarmd.ai/audit/v1/traces/CORRELATION_ID \
      -H "Authorization: Bearer $SWARMD_TOKEN"
    ```
  </Tab>

  <Tab title="UI">
    Coming soon.
  </Tab>
</Tabs>

***

## Endpoint Reference

| Access type | Relay endpoint                                                         | Auth header                                                      |
| ----------- | ---------------------------------------------------------------------- | ---------------------------------------------------------------- |
| **Channel** | `POST /relay/v1/channels/{channelId}/agents/{agentId}/a2a/0.3.0`       | `Bearer {channel_access_token}` (from OAuth2 client credentials) |
| **User**    | `POST /relay/v1/human/agents/{agentId}/a2a/0.3.0`                      | `Bearer {user_access_token}` (from login)                        |
| **Agent**   | `POST /relay/v1/agents/{sourceAgentId}/agents/{sinkAgentId}/a2a/0.3.0` | `Bearer {agent_access_token}` (from agent service account)       |

***

## Next Steps

<CardGroup cols={2}>
  <Card title="TypeScript Channel Client" icon="code" href="/sdks/typescript/channel-client">
    Connect a website to this channel with OAuth, conversation continuity, polling, and typed lifecycle events.
  </Card>

  <Card title="Policy Configuration" icon="shield" href="/tutorials/policy-configuration">
    Add guardrails to control what your agents can send and receive.
  </Card>
</CardGroup>
