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

# Getting Started with the Partner API

> Submit your first topic and understand the commentary workflow

This guide walks you through submitting your first topic and understanding how commentary generation works.

<Info>
  **Prerequisites:** You need a Partner account with at least one licensed persona. Don't have one? [Contact sales](mailto:partners@unleeshed.ai).
</Info>

<Note>
  **Human-in-the-Loop Quality**: Unleeshed generates authentic, high-fidelity commentary through a human-in-the-loop workflow. Creators inject their real perspective before AI generates. This ensures genuine responses but means **commentary typically arrives within hours, not seconds**.
</Note>

***

## Step 1: Get Your API Key

<Steps>
  <Step title="Log into Partner Dashboard">
    Go to [app.unleeshed.ai/partner](https://app.unleeshed.ai/partner) and sign in.
  </Step>

  <Step title="Navigate to API Keys">
    Click **Developer** → **API Keys** in the sidebar.
  </Step>

  <Step title="Create a New Key">
    Click **Create API Key**, name it "Quickstart Test", and select these scopes:

    * `personas:read`
    * `topics:submit`
    * `topics:read`
  </Step>

  <Step title="Copy Your Key">
    Copy the key immediately — it's only shown once!

    ```
    pk_live_abc123...
    ```
  </Step>
</Steps>

<Warning>
  Store your API key securely. Never expose it in client-side code.
</Warning>

***

## Step 2: Find Your Personas

Let's see which personas you have access to.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://prod.api.unleeshed.ai/partner/v1/personas" \
    -H "X-Api-Key: YOUR_API_KEY"
  ```

  ```javascript Node.js theme={null}
  const response = await fetch('https://prod.api.unleeshed.ai/partner/v1/personas', {
    headers: { 'X-Api-Key': process.env.UNLEESHED_API_KEY }
  });

  const { data: personas } = await response.json();

  console.log('Your licensed personas:');
  personas.forEach(p => console.log(`- ${p.name} (${p.id})`));
  ```

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

  response = requests.get(
      "https://prod.api.unleeshed.ai/partner/v1/personas",
      headers={"X-Api-Key": os.environ["UNLEESHED_API_KEY"]}
  )

  personas = response.json()["data"]

  print("Your licensed personas:")
  for p in personas:
      print(f"- {p['name']} ({p['id']})")
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "success": true,
  "data": [
    { "id": "pers_abc123", "name": "Coach Mike", "image_url": "https://..." },
    { "id": "pers_xyz789", "name": "Analytics Amy", "image_url": "https://..." }
  ]
}
```

<Tip>
  Save those persona IDs — you'll need them in the next step.
</Tip>

***

## Step 3: Create a Topic

Now let's submit a topic for commentary. Pick a hot sports topic (max 100 characters) and send it to your personas.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://prod.api.unleeshed.ai/partner/v1/topics" \
    -H "X-Api-Key: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "content": "Should the Lakers trade Anthony Davis before the deadline?",
      "persona_ids": ["pers_abc123", "pers_xyz789"],
      "output_types": ["text"]
    }'
  ```

  ```javascript Node.js theme={null}
  const response = await fetch('https://prod.api.unleeshed.ai/partner/v1/topics', {
    method: 'POST',
    headers: {
      'X-Api-Key': process.env.UNLEESHED_API_KEY,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      content: "Should the Lakers trade Anthony Davis before the deadline?",
      persona_ids: ["pers_abc123", "pers_xyz789"],
      output_types: ["text"]
    })
  });

  const { data } = await response.json();
  console.log(`Topic created: ${data.topic_id}`);
  console.log(`Personas generating: ${data.personas_sent}`);
  ```

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

  response = requests.post(
      "https://prod.api.unleeshed.ai/partner/v1/topics",
      headers={
          "X-Api-Key": os.environ["UNLEESHED_API_KEY"],
          "Content-Type": "application/json"
      },
      json={
          "content": "Should the Lakers trade Anthony Davis before the deadline?",
          "persona_ids": ["pers_abc123", "pers_xyz789"],
          "output_types": ["text"]
      }
  )

  data = response.json()["data"]
  print(f"Topic created: {data['topic_id']}")
  print(f"Personas generating: {data['personas_sent']}")
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "success": true,
  "data": {
    "topic_id": "top_98765",
    "personas_sent": 2,
    "status": "pending"
  }
}
```

<Check>
  **Save the `topic_id`** — you need it to fetch the commentaries.
</Check>

***

## Step 4: Check Status

Since commentary involves human creators, it takes time. Use the status endpoint to monitor progress.

<CodeGroup>
  ```bash cURL theme={null}
  # Check status - poll periodically until ready
  curl -X GET "https://prod.api.unleeshed.ai/partner/v1/topics/top_98765/status" \
    -H "X-Api-Key: YOUR_API_KEY"
  ```

  ```javascript Node.js theme={null}
  async function checkStatus(topicId) {
    const response = await fetch(
      `https://prod.api.unleeshed.ai/partner/v1/topics/${topicId}/status`,
      { headers: { 'X-Api-Key': process.env.UNLEESHED_API_KEY } }
    );
    
    const { data } = await response.json();
    
    console.log(`Overall: ${data.overall_status}`);
    console.log(`Ready: ${data.summary.creator_approved}/${data.summary.total}`);
    
    data.personas.forEach(p => {
      console.log(`  ${p.persona_name}: ${p.status}`);
    });
    
    return data;
  }

  const status = await checkStatus('top_98765');
  ```

  ```python Python theme={null}
  def check_status(topic_id):
      response = requests.get(
          f"https://prod.api.unleeshed.ai/partner/v1/topics/{topic_id}/status",
          headers={"X-Api-Key": os.environ["UNLEESHED_API_KEY"]}
      )
      
      data = response.json()["data"]
      
      print(f"Overall: {data['overall_status']}")
      print(f"Ready: {data['summary']['creator_approved']}/{data['summary']['total']}")
      
      for p in data["personas"]:
          print(f"  {p['persona_name']}: {p['status']}")
      
      return data

  status = check_status("top_98765")
  ```
</CodeGroup>

**Example output:**

```
Overall: partial
Ready: 1/2
  Coach Mike: creator_approved
  Analytics Amy: opinion_injected
```

<Info>
  **Timeline**: Creators typically respond within 30 minutes to a few hours. Set up periodic polling (every 1-5 minutes) or use webhooks in production.
</Info>

***

## Step 5: Fetch the Commentary

Once `overall_status` is `partial` or `completed`, fetch the ready commentaries:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://prod.api.unleeshed.ai/partner/v1/topics/top_98765/commentaries" \
    -H "X-Api-Key: YOUR_API_KEY"
  ```

  ```javascript Node.js theme={null}
  const response = await fetch(
    `https://prod.api.unleeshed.ai/partner/v1/topics/top_98765/commentaries`,
    { headers: { 'X-Api-Key': process.env.UNLEESHED_API_KEY } }
  );

  const { data } = await response.json();

  console.log(`\nTopic: ${data.content}\n`);

  data.commentaries.forEach(c => {
    console.log(`--- ${c.persona.name} ---`);
    console.log(c.content);
    console.log('');
  });
  ```

  ```python Python theme={null}
  response = requests.get(
      f"https://prod.api.unleeshed.ai/partner/v1/topics/top_98765/commentaries",
      headers={"X-Api-Key": os.environ["UNLEESHED_API_KEY"]}
  )

  data = response.json()["data"]

  print(f"\nTopic: {data['content']}\n")

  for c in data["commentaries"]:
      print(f"--- {c['persona']['name']} ---")
      print(c["content"])
      print()
  ```
</CodeGroup>

**The Result:**

```
Topic: Should the Lakers trade Anthony Davis before the deadline?

--- Coach Mike ---
Look, I've been in locker rooms for 30 years, and I can tell you — 
chemistry matters. AD is still one of the most talented big men in 
the game when he's healthy. But that's the thing, isn't it? "When 
he's healthy." You're talking about a franchise that's been to the 
Finals, won a championship with this core. But at some point, you 
gotta ask yourself: are we building around a player or building 
around a medical report?

--- Analytics Amy ---
Let's look at the numbers. Davis has played in just 56% of possible 
games over the past three seasons. However, when active, his impact 
metrics remain elite — top-5 in defensive win shares, +4.2 net rating. 
The question isn't whether AD is good, it's probability-weighted 
value. If you trade him, what's the expected return? Most models 
suggest the Lakers would be selling at a significant discount given 
his injury history and contract.
```

***

## You're Set Up!

You've completed the integration basics:

<Steps>
  <Step title="Created an API key">
    With the right scopes for commentary generation
  </Step>

  <Step title="Retrieved your licensed personas">
    So you know who can generate commentary
  </Step>

  <Step title="Submitted a topic">
    And selected which personas should respond
  </Step>

  <Step title="Learned to check status">
    Monitor the human-in-the-loop workflow
  </Step>

  <Step title="Fetched the results">
    Unique, high-fidelity commentary from each persona
  </Step>
</Steps>

<Tip>
  **Production Tip**: For production integrations, consider implementing webhook callbacks instead of polling. Contact [api@unleeshed.ai](mailto:api@unleeshed.ai) to discuss webhook setup.
</Tip>

***

## What's Next?

<CardGroup cols={2}>
  <Card title="Display Best Practices" icon="desktop" href="/guides/display-commentaries">
    Learn how to beautifully present commentaries in your UI.
  </Card>

  <Card title="Error Handling" icon="triangle-exclamation" href="/guides/error-handling">
    Build robust integrations that handle edge cases.
  </Card>

  <Card title="Core Concepts" icon="book" href="/concepts/overview">
    Deep dive into personas, licensing, and fidelity.
  </Card>

  <Card title="Full API Reference" icon="code" href="/api-reference/introduction">
    Explore all available endpoints.
  </Card>
</CardGroup>

***

## Complete Working Example

Here's a full integration example using the status endpoint:

<CodeGroup>
  ```javascript complete-example.js theme={null}
  const API_KEY = process.env.UNLEESHED_API_KEY;
  const BASE_URL = 'https://prod.api.unleeshed.ai/partner/v1';

  async function submitTopic(topic) {
    // 1. Get personas
    const personasRes = await fetch(`${BASE_URL}/personas`, {
      headers: { 'X-Api-Key': API_KEY }
    });
    const { data: personas } = await personasRes.json();
    
    console.log(`Found ${personas.length} licensed personas`);
    
    // 2. Create topic (max 100 characters)
    const topicRes = await fetch(`${BASE_URL}/topics`, {
      method: 'POST',
      headers: { 'X-Api-Key': API_KEY, 'Content-Type': 'application/json' },
      body: JSON.stringify({
        content: topic,
        persona_ids: personas.map(p => p.id),
        output_types: ['text']
      })
    });
    const { data: topicData } = await topicRes.json();
    
    console.log(`Topic created: ${topicData.topic_id}`);
    return topicData.topic_id;
  }

  async function checkTopicStatus(topicId) {
    // Use lightweight status endpoint for polling
    const statusRes = await fetch(`${BASE_URL}/topics/${topicId}/status`, {
      headers: { 'X-Api-Key': API_KEY }
    });
    const { data: status } = await statusRes.json();
    
    console.log(`Status: ${status.overall_status}`);
    console.log(`Ready: ${status.summary.creator_approved}/${status.summary.total}`);
    
    status.personas.forEach(p => {
      console.log(`  ${p.persona_name}: ${p.status}`);
    });
    
    return status;
  }

  async function getCommentaries(topicId) {
    const commRes = await fetch(`${BASE_URL}/topics/${topicId}/commentaries`, {
      headers: { 'X-Api-Key': API_KEY }
    });
    const { data: result } = await commRes.json();
    return result.commentaries;
  }

  // Usage example
  const topicId = await submitTopic("Should the Lakers trade AD?");

  // Check status periodically (in production, use webhooks or scheduled jobs)
  const status = await checkTopicStatus(topicId);

  // When status.overall_status is 'partial' or 'completed', fetch commentaries
  if (status.overall_status === 'partial' || status.overall_status === 'completed') {
    const commentaries = await getCommentaries(topicId);
    commentaries.forEach(c => {
      console.log(`\n${c.persona.name}:\n${c.content}`);
    });
  }
  ```

  ```python complete_example.py theme={null}
  import os
  import requests

  API_KEY = os.environ["UNLEESHED_API_KEY"]
  BASE_URL = "https://prod.api.unleeshed.ai/partner/v1"

  def submit_topic(topic):
      headers = {"X-Api-Key": API_KEY}
      
      # 1. Get personas
      personas = requests.get(f"{BASE_URL}/personas", headers=headers).json()["data"]
      print(f"Found {len(personas)} licensed personas")
      
      # 2. Create topic (max 100 characters)
      topic_data = requests.post(
          f"{BASE_URL}/topics",
          headers={**headers, "Content-Type": "application/json"},
          json={
              "content": topic,
              "persona_ids": [p["id"] for p in personas],
              "output_types": ["text"]
          }
      ).json()["data"]
      
      print(f"Topic created: {topic_data['topic_id']}")
      return topic_data["topic_id"]

  def check_topic_status(topic_id):
      # Use lightweight status endpoint for polling
      status = requests.get(
          f"{BASE_URL}/topics/{topic_id}/status", 
          headers={"X-Api-Key": API_KEY}
      ).json()["data"]
      
      print(f"Status: {status['overall_status']}")
      print(f"Ready: {status['summary']['creator_approved']}/{status['summary']['total']}")
      
      for p in status["personas"]:
          print(f"  {p['persona_name']}: {p['status']}")
      
      return status

  def get_commentaries(topic_id):
      result = requests.get(
          f"{BASE_URL}/topics/{topic_id}/commentaries",
          headers={"X-Api-Key": API_KEY}
      ).json()["data"]
      return result["commentaries"]

  # Usage example
  if __name__ == "__main__":
      topic_id = submit_topic("Should the Lakers trade AD?")
      
      # Check status periodically (in production, use webhooks or scheduled jobs)
      status = check_topic_status(topic_id)
      
      # When status is 'partial' or 'completed', fetch commentaries
      if status["overall_status"] in ["partial", "completed"]:
          commentaries = get_commentaries(topic_id)
          for c in commentaries:
              print(f"\n{c['persona']['name']}:\n{c['content']}")
  ```
</CodeGroup>
