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

# Generate Conversation from PDF

> Learn how to transform PDF documents into engaging multi-speaker conversations

This guide will walk you through generating a conversational-style podcast from a PDF using the PlayNote API. We'll use the `PlayNote API` to take a PDF source file, synthesize it into an audio conversation between two voices, and retrieve the generated podcast URL.

## Prerequisites

Before you start, ensure you have the following:

* Access your [credentials](https://play.ai/api/keys) (API key and user ID)
* Development environment for your chosen programming language
* Python's `requests` library installed (`pip install requests`)

## Steps

<Steps>
  <Step title="Set Up Environment Variables">
    Add your API key and user ID to your environment variables.

    <CodeGroup>
      ```bash macOS (zsh) theme={null}
      echo 'export PLAYAI_API_KEY="your_api_key_here"' >> ~/.zshrc
      echo 'export PLAYAI_USER_ID="your_user_id_here"' >> ~/.zshrc
      source ~/.zshrc
      ```

      ```bash bash theme={null}
      echo 'export PLAYAI_API_KEY="your_api_key_here"' >> ~/.bashrc
      echo 'export PLAYAI_USER_ID="your_user_id_here"' >> ~/.bashrc
      source ~/.bashrc
      ```

      ```cmd Windows theme={null}
      setx PLAYAI_API_KEY "your_api_key_here"
      setx PLAYAI_USER_ID "your_user_id_here"
      ```
    </CodeGroup>
  </Step>

  <Step title="Configure API Access">
    Create a script with the following authentication setup:

    <CodeGroup>
      ```python Python theme={null}
      import requests
      import os

      # Define the URL of your PDF file
      SOURCE_FILE_URL = "https://godinton.kent.sch.uk/media/2601/goldilocks-story.pdf"

      # PlayNote API URL
      url = "https://api.play.ai/api/v1/playnotes"

      # Retrieve API key and User ID from environment variables
      api_key = os.getenv("PLAYAI_API_KEY")
      user_id = os.getenv("PLAYAI_USER_ID")

      # Set up headers with authorization details
      headers = {
          'AUTHORIZATION': api_key,
          'X-USER-ID': user_id,
          'accept': 'application/json'
      }
      ```

      ```javascript JavaScript theme={null}
      const SOURCE_FILE_URL = "https://godinton.kent.sch.uk/media/2601/goldilocks-story.pdf";
      const url = "https://api.play.ai/api/v1/playnotes";

      const apiKey = process.env.PLAYAI_API_KEY;
      const userId = process.env.PLAYAI_USER_ID;

      const headers = {
        'AUTHORIZATION': apiKey,
        'X-USER-ID': userId,
        'accept': 'application/json'
      };
      ```

      ```go Go theme={null}
      const SOURCE_FILE_URL = "https://godinton.kent.sch.uk/media/2601/goldilocks-story.pdf"
      const url = "https://api.play.ai/api/v1/playnotes"

      apiKey := os.Getenv("PLAYAI_API_KEY")
      userId := os.Getenv("PLAYAI_USER_ID")

      headers := map[string]string{
        "AUTHORIZATION": apiKey,
        "X-USER-ID": userId,
        "accept": "application/json",
      }
      ```

      ```dart Dart theme={null}
      import 'dart:io';
      import 'package:http/http.dart' as http;

      const SOURCE_FILE_URL = "https://godinton.kent.sch.uk/media/2601/goldilocks-story.pdf";
      final url = Uri.parse("https://api.play.ai/api/v1/playnotes");

      final apiKey = Platform.environment['PLAYAI_API_KEY'];
      final userId = Platform.environment['PLAYAI_USER_ID'];

      final headers = {
        'AUTHORIZATION': apiKey!,
        'X-USER-ID': userId!,
        'accept': 'application/json'
      };
      ```

      ```swift Swift theme={null}
      import Foundation

      let SOURCE_FILE_URL = "https://godinton.kent.sch.uk/media/2601/goldilocks-story.pdf"
      let url = URL(string: "https://api.play.ai/api/v1/playnotes")!

      guard let apiKey = ProcessInfo.processInfo.environment["PLAYAI_API_KEY"],
            let userId = ProcessInfo.processInfo.environment["PLAYAI_USER_ID"] else {
        fatalError("Please set PLAYAI_API_KEY and PLAYAI_USER_ID environment variables")
      }

      let headers = [
        "AUTHORIZATION": apiKey,
        "X-USER-ID": userId,
        "accept": "application/json"
      ]
      ```
    </CodeGroup>
  </Step>

  <Step title="Send Request to Generate PlayNote">
    Configure and send the request to create your podcast:

    <CodeGroup>
      ```python Python theme={null}
      # Configure the request parameters
      files = {
          'sourceFileUrl': (None, SOURCE_FILE_URL),
          'synthesisStyle': (None, 'podcast'),
          'voice1': (None, 's3://voice-cloning-zero-shot/baf1ef41-36b6-428c-9bdf-50ba54682bd8/original/manifest.json'),
          'voice1Name': (None, 'Angelo'),
          'voice2': (None, 's3://voice-cloning-zero-shot/e040bd1b-f190-4bdb-83f0-75ef85b18f84/original/manifest.json'),
          'voice2Name': (None, 'Deedee'),
      }

      # Send the POST request
      response = requests.post(url, headers=headers, files=files)

      if response.status_code == 201:
          print("Request sent successfully!")
          playNoteId = response.json().get('id')
          print(f"Generated PlayNote ID: {playNoteId}")
      else:
          print(f"Failed to generate PlayNote: {response.text}")
      ```

      ```javascript JavaScript theme={null}
      const files = {
        sourceFileUrl: SOURCE_FILE_URL,
        synthesisStyle: 'podcast',
        voice1: 's3://voice-cloning-zero-shot/baf1ef41-36b6-428c-9bdf-50ba54682bd8/original/manifest.json',
        voice1Name: 'Angelo',
        voice2: 's3://voice-cloning-zero-shot/e040bd1b-f190-4bdb-83f0-75ef85b18f84/original/manifest.json',
        voice2Name: 'Deedee'
      };

      fetch(url, {
        method: 'POST',
        headers: headers,
        body: JSON.stringify(files)
      })
      .then(response => response.json())
      .then(data => {
        if (response.status === 201) {
          console.log("Request sent successfully!");
          console.log(`Generated PlayNote ID: ${data.id}`);
        } else {
          console.log(`Failed to generate PlayNote: ${response.text}`);
        }
      });
      ```

      ```go Go theme={null}
      files := map[string]string{
        "sourceFileUrl": SOURCE_FILE_URL,
        "synthesisStyle": "podcast",
        "voice1": "s3://voice-cloning-zero-shot/baf1ef41-36b6-428c-9bdf-50ba54682bd8/original/manifest.json",
        "voice1Name": "Angelo",
        "voice2": "s3://voice-cloning-zero-shot/e040bd1b-f190-4bdb-83f0-75ef85b18f84/original/manifest.json",
        "voice2Name": "Deedee",
      }

      jsonData, _ := json.Marshal(files)
      req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))

      for key, value := range headers {
        req.Header.Add(key, value)
      }

      client := &http.Client{}
      resp, err := client.Do(req)
      if err != nil {
        log.Fatal(err)
      }
      defer resp.Body.Close()

      if resp.StatusCode == 201 {
        var result map[string]interface{}
        json.NewDecoder(resp.Body).Decode(&result)
        fmt.Println("Request sent successfully!")
        fmt.Printf("Generated PlayNote ID: %v\n", result["id"])
      } else {
        body, _ := io.ReadAll(resp.Body)
        fmt.Printf("Failed to generate PlayNote: %s\n", string(body))
      }
      ```

      ```dart Dart theme={null}
      final files = {
        'sourceFileUrl': SOURCE_FILE_URL,
        'synthesisStyle': 'podcast',
        'voice1': 's3://voice-cloning-zero-shot/baf1ef41-36b6-428c-9bdf-50ba54682bd8/original/manifest.json',
        'voice1Name': 'Angelo',
        'voice2': 's3://voice-cloning-zero-shot/e040bd1b-f190-4bdb-83f0-75ef85b18f84/original/manifest.json',
        'voice2Name': 'Deedee'
      };

      try {
        final response = await http.post(
          url,
          headers: headers,
          body: jsonEncode(files),
        );

        if (response.statusCode == 201) {
          final data = jsonDecode(response.body);
          print("Request sent successfully!");
          print("Generated PlayNote ID: ${data['id']}");
        } else {
          print("Failed to generate PlayNote: ${response.body}");
        }
      } catch (e) {
        print("Error: $e");
      }
      ```

      ```swift Swift theme={null}
      let files: [String: Any] = [
        "sourceFileUrl": SOURCE_FILE_URL,
        "synthesisStyle": "podcast",
        "voice1": "s3://voice-cloning-zero-shot/baf1ef41-36b6-428c-9bdf-50ba54682bd8/original/manifest.json",
        "voice1Name": "Angelo",
        "voice2": "s3://voice-cloning-zero-shot/e040bd1b-f190-4bdb-83f0-75ef85b18f84/original/manifest.json",
        "voice2Name": "Deedee"
      ]

      func createPlayNote() async throws {
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.allHTTPHeaderFields = headers
        request.httpBody = try JSONSerialization.data(withJSONObject: files)

        let (data, response) = try await URLSession.shared.data(for: request)
        
        guard let httpResponse = response as? HTTPURLResponse else {
          throw NSError(domain: "", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid response"])
        }

        if httpResponse.statusCode == 201 {
          let result = try JSONDecoder().decode([String: Any].self, from: data)
          print("Request sent successfully!")
          if let playNoteId = result["id"] as? String {
            print("Generated PlayNote ID: \(playNoteId)")
          }
        } else {
          print("Failed to generate PlayNote: \(String(data: data, encoding: .utf8) ?? "")")
        }
      }
      ```
    </CodeGroup>
  </Step>

  <Step title="Poll for Completion">
    Check the status of your PlayNote generation:

    <CodeGroup>
      ```python Python theme={null}
      import urllib.parse
      import time

      # Double-encode the PlayNote ID for the URL
      double_encoded_id = urllib.parse.quote(playNoteId, safe='')

      # Construct the final URL to check the status
      status_url = f"https://api.play.ai/api/v1/playnotes/{double_encoded_id}"

      # Poll for completion
      while True:
          response = requests.get(status_url, headers=headers)
          if response.status_code == 200:
              playnote_data = response.json()
              status = playnote_data['status']
              if status == 'completed':
                  print("PlayNote generation complete!")
                  print("Audio URL:", playnote_data['audioUrl'])
                  break
              elif status == 'generating':
                  print("Please wait, your PlayNote is still generating...")
                  time.sleep(120)  # Wait for 2 minutes before polling again
              else:
                  print("PlayNote creation failed, please try again.")
                  break
          else:
              print(f"Error polling for PlayNote status: {response.text}")
              break
      ```

      ```javascript JavaScript theme={null}
      const doubleEncodedId = encodeURIComponent(playNoteId);
      const statusUrl = `https://api.play.ai/api/v1/playnotes/${doubleEncodedId}`;

      const pollStatus = async () => {
        const response = await fetch(statusUrl, { headers });
        if (response.ok) {
          const data = await response.json();
          if (data.status === 'completed') {
            console.log("PlayNote generation complete!");
            console.log("Audio URL:", data.audioUrl);
            return;
          } else if (data.status === 'generating') {
            console.log("Please wait, your PlayNote is still generating...");
            setTimeout(pollStatus, 120000); // Poll every 2 minutes
          } else {
            console.log("PlayNote creation failed, please try again.");
          }
        } else {
          console.log(`Error polling for PlayNote status: ${response.text}`);
        }
      };

      pollStatus();
      ```

      ```go Go theme={null}
      doubleEncodedId := url.QueryEscape(playNoteId)
      statusUrl := fmt.Sprintf("https://api.play.ai/api/v1/playnotes/%s", doubleEncodedId)

      for {
        req, _ := http.NewRequest("GET", statusUrl, nil)
        for key, value := range headers {
          req.Header.Add(key, value)
        }

        resp, err := client.Do(req)
        if err != nil {
          log.Fatal(err)
        }

        var data map[string]interface{}
        json.NewDecoder(resp.Body).Decode(&data)
        resp.Body.Close()

        if resp.StatusCode == 200 {
          status := data["status"].(string)
          if status == "completed" {
            fmt.Println("PlayNote generation complete!")
            fmt.Printf("Audio URL: %v\n", data["audioUrl"])
            break
          } else if status == "generating" {
            fmt.Println("Please wait, your PlayNote is still generating...")
            time.Sleep(120 * time.Second)
          } else {
            fmt.Println("PlayNote creation failed, please try again.")
            break
          }
        } else {
          fmt.Printf("Error polling for PlayNote status: %s\n", resp.Status)
          break
        }
      }
      ```

      ```dart Dart theme={null}
      Future<void> pollStatus(String playNoteId) async {
        final doubleEncodedId = Uri.encodeComponent(playNoteId);
        final statusUrl = Uri.parse("https://api.play.ai/api/v1/playnotes/$doubleEncodedId");

        while (true) {
          try {
            final response = await http.get(statusUrl, headers: headers);
            if (response.statusCode == 200) {
              final data = jsonDecode(response.body);
              final status = data['status'];
              
              if (status == 'completed') {
                print("PlayNote generation complete!");
                print("Audio URL: ${data['audioUrl']}");
                break;
              } else if (status == 'generating') {
                print("Please wait, your PlayNote is still generating...");
                await Future.delayed(Duration(seconds: 120));
              } else {
                print("PlayNote creation failed, please try again.");
                break;
              }
            } else {
              print("Error polling for PlayNote status: ${response.body}");
              break;
            }
          } catch (e) {
            print("Error polling status: $e");
            break;
          }
        }
      }
      ```

      ```swift Swift theme={null}
      func pollStatus(playNoteId: String) async throws {
        let doubleEncodedId = playNoteId.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? playNoteId
        let statusUrl = URL(string: "https://api.play.ai/api/v1/playnotes/\(doubleEncodedId)")!

        while true {
          var request = URLRequest(url: statusUrl)
          request.allHTTPHeaderFields = headers

          let (data, response) = try await URLSession.shared.data(for: request)
          
          guard let httpResponse = response as? HTTPURLResponse else {
            throw NSError(domain: "", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid response"])
          }

          if httpResponse.statusCode == 200 {
            let result = try JSONDecoder().decode([String: Any].self, from: data)
            if let status = result["status"] as? String {
              switch status {
              case "completed":
                print("PlayNote generation complete!")
                if let audioUrl = result["audioUrl"] as? String {
                  print("Audio URL: \(audioUrl)")
                }
                return
              case "generating":
                print("Please wait, your PlayNote is still generating...")
                try await Task.sleep(nanoseconds: 120_000_000_000) // 120 seconds
              default:
                print("PlayNote creation failed, please try again.")
                return
              }
            }
          } else {
            print("Error polling for PlayNote status: \(String(data: data, encoding: .utf8) ?? "")")
            return
          }
        }
      }
      ```
    </CodeGroup>
  </Step>

  <Step title="Run and Test">
    Follow these steps to run your code:

    <Tabs>
      <Tab title="Python">
        1. Save your code as `playnote_generator.py`
        2. Open terminal in your code directory
        3. Run: `python3 playnote_generator.py`
        4. Wait for the generation process to complete
        5. Access your generated audio using the provided URL
      </Tab>

      <Tab title="JavaScript">
        1. Save your code as `playnote_generator.js`
        2. Install dependencies: `npm install node-fetch`
        3. Run: `node playnote_generator.js`
        4. Wait for the generation process to complete
        5. Access your generated audio using the provided URL
      </Tab>

      <Tab title="Go">
        1. Save your code as `playnote_generator.go`
        2. Run: `go run playnote_generator.go`
        3. Wait for the generation process to complete
        4. Access your generated audio using the provided URL
      </Tab>

      <Tab title="Dart">
        1. Save your code as `playnote_generator.dart`
        2. Install dependencies: `dart pub add http`
        3. Run: `dart run playnote_generator.dart`
        4. Wait for the generation process to complete
        5. Access your generated audio using the provided URL
      </Tab>

      <Tab title="Swift">
        1. Save your code as `playnote_generator.swift`
        2. Run: `swift playnote_generator.swift`
        3. Wait for the generation process to complete
        4. Access your generated audio using the provided URL
      </Tab>
    </Tabs>
  </Step>
</Steps>

## Complete Code

<CodeGroup>
  ```python Python [expandable] theme={null}
  import requests
  import os
  import urllib.parse
  import time

  # Define the URL of your PDF file
  SOURCE_FILE_URL = "https://godinton.kent.sch.uk/media/2601/goldilocks-story.pdf"

  # PlayNote API URL
  url = "https://api.play.ai/api/v1/playnotes"

  # Retrieve API key and User ID from environment variables
  api_key = os.getenv("PLAYAI_API_KEY")
  user_id = os.getenv("PLAYAI_USER_ID")

  # Set up headers with authorization details
  headers = {
      'AUTHORIZATION': api_key,
      'X-USER-ID': user_id,
      'accept': 'application/json'
  }

  # Configure the request parameters
  files = {
      'sourceFileUrl': (None, SOURCE_FILE_URL),
      'synthesisStyle': (None, 'podcast'),
      'voice1': (None, 's3://voice-cloning-zero-shot/baf1ef41-36b6-428c-9bdf-50ba54682bd8/original/manifest.json'),
      'voice1Name': (None, 'Angelo'),
      'voice2': (None, 's3://voice-cloning-zero-shot/e040bd1b-f190-4bdb-83f0-75ef85b18f84/original/manifest.json'),
      'voice2Name': (None, 'Deedee'),
  }

  # Send the POST request
  response = requests.post(url, headers=headers, files=files)

  if response.status_code == 201:
      print("Request sent successfully!")
      playNoteId = response.json().get('id')
      print(f"Generated PlayNote ID: {playNoteId}")

      # Double-encode the PlayNote ID for the URL
      double_encoded_id = urllib.parse.quote(playNoteId, safe='')

      # Construct the final URL to check the status
      status_url = f"https://api.play.ai/api/v1/playnotes/{double_encoded_id}"

      # Poll for completion
      while True:
          response = requests.get(status_url, headers=headers)
          if response.status_code == 200:
              playnote_data = response.json()
              status = playnote_data['status']
              if status == 'completed':
                  print("PlayNote generation complete!")
                  print("Audio URL:", playnote_data['audioUrl'])
                  break
              elif status == 'generating':
                  print("Please wait, your PlayNote is still generating...")
                  time.sleep(120)  # Wait for 2 minutes before polling again
              else:
                  print("PlayNote creation failed, please try again.")
                  break
          else:
              print(f"Error polling for PlayNote status: {response.text}")
              break
  else:
      print(f"Failed to generate PlayNote: {response.text}")
  ```

  ```javascript JavaScript [expandable] theme={null}
  const fetch = require('node-fetch');

  const SOURCE_FILE_URL = "https://godinton.kent.sch.uk/media/2601/goldilocks-story.pdf";
  const url = "https://api.play.ai/api/v1/playnotes";

  const apiKey = process.env.PLAYAI_API_KEY;
  const userId = process.env.PLAYAI_USER_ID;

  const headers = {
    'AUTHORIZATION': apiKey,
    'X-USER-ID': userId,
    'accept': 'application/json'
  };

  const files = {
    sourceFileUrl: SOURCE_FILE_URL,
    synthesisStyle: 'podcast',
    voice1: 's3://voice-cloning-zero-shot/baf1ef41-36b6-428c-9bdf-50ba54682bd8/original/manifest.json',
    voice1Name: 'Angelo',
    voice2: 's3://voice-cloning-zero-shot/e040bd1b-f190-4bdb-83f0-75ef85b18f84/original/manifest.json',
    voice2Name: 'Deedee'
  };

  fetch(url, {
    method: 'POST',
    headers: headers,
    body: JSON.stringify(files)
  })
  .then(response => response.json())
  .then(data => {
    if (response.status === 201) {
      console.log("Request sent successfully!");
      console.log(`Generated PlayNote ID: ${data.id}`);
    } else {
      console.log(`Failed to generate PlayNote: ${response.text}`);
    }
  });
  ```

  ```go Go [expandable] theme={null}
  package main

  import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "net/url"
    "os"
    "time"
  )

  const SOURCE_FILE_URL = "https://godinton.kent.sch.uk/media/2601/goldilocks-story.pdf"
  const apiUrl = "https://api.play.ai/api/v1/playnotes"

  func main() {
    apiKey := os.Getenv("PLAYAI_API_KEY")
    userId := os.Getenv("PLAYAI_USER_ID")

    headers := map[string]string{
      "AUTHORIZATION": apiKey,
      "X-USER-ID": userId,
      "accept": "application/json",
    }

    files := map[string]string{
      "sourceFileUrl": SOURCE_FILE_URL,
      "synthesisStyle": "podcast",
      "voice1": "s3://voice-cloning-zero-shot/baf1ef41-36b6-428c-9bdf-50ba54682bd8/original/manifest.json",
      "voice1Name": "Angelo",
      "voice2": "s3://voice-cloning-zero-shot/e040bd1b-f190-4bdb-83f0-75ef85b18f84/original/manifest.json",
      "voice2Name": "Deedee",
    }

    jsonData, _ := json.Marshal(files)
    req, _ := http.NewRequest("POST", apiUrl, bytes.NewBuffer(jsonData))
    
    for key, value := range headers {
      req.Header.Add(key, value)
    }

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
      log.Fatal(err)
    }
    defer resp.Body.Close()

    if resp.StatusCode == 201 {
      var result map[string]interface{}
      json.NewDecoder(resp.Body).Decode(&result)
      fmt.Println("Request sent successfully!")
      playNoteId := result["id"].(string)
      fmt.Printf("Generated PlayNote ID: %s\n", playNoteId)

      doubleEncodedId := url.QueryEscape(playNoteId)
      statusUrl := fmt.Sprintf("https://api.play.ai/api/v1/playnotes/%s", doubleEncodedId)

      for {
        req, _ := http.NewRequest("GET", statusUrl, nil)
        for key, value := range headers {
          req.Header.Add(key, value)
        }

        resp, err := client.Do(req)
        if err != nil {
          log.Fatal(err)
        }

        var data map[string]interface{}
        json.NewDecoder(resp.Body).Decode(&data)
        resp.Body.Close()

        if resp.StatusCode == 200 {
          status := data["status"].(string)
          if status == "completed" {
            fmt.Println("PlayNote generation complete!")
            fmt.Printf("Audio URL: %v\n", data["audioUrl"])
            break
          } else if status == "generating" {
            fmt.Println("Please wait, your PlayNote is still generating...")
            time.Sleep(120 * time.Second)
          } else {
            fmt.Println("PlayNote creation failed, please try again.")
            break
          }
        } else {
          fmt.Printf("Error polling for PlayNote status: %s\n", resp.Status)
          break
        }
      }
    } else {
      body, _ := io.ReadAll(resp.Body)
      fmt.Printf("Failed to generate PlayNote: %s\n", string(body))
    }
  }
  ```

  ```dart Dart [expandable] theme={null}
  import 'dart:io';
  import 'package:http/http.dart' as http;
  import 'dart:convert';

  const SOURCE_FILE_URL = "https://godinton.kent.sch.uk/media/2601/goldilocks-story.pdf";
  final url = Uri.parse("https://api.play.ai/api/v1/playnotes");

  final apiKey = Platform.environment['PLAYAI_API_KEY'];
  final userId = Platform.environment['PLAYAI_USER_ID'];

  final headers = {
    'AUTHORIZATION': apiKey!,
    'X-USER-ID': userId!,
    'accept': 'application/json'
  };

  final files = {
    'sourceFileUrl': SOURCE_FILE_URL,
    'synthesisStyle': 'podcast',
    'voice1': 's3://voice-cloning-zero-shot/baf1ef41-36b6-428c-9bdf-50ba54682bd8/original/manifest.json',
    'voice1Name': 'Angelo',
    'voice2': 's3://voice-cloning-zero-shot/e040bd1b-f190-4bdb-83f0-75ef85b18f84/original/manifest.json',
    'voice2Name': 'Deedee'
  };

  void main() async {
    try {
      final response = await http.post(
        url,
        headers: headers,
        body: jsonEncode(files),
      );

      if (response.statusCode == 201) {
        final data = jsonDecode(response.body);
        print("Request sent successfully!");
        final playNoteId = data['id'];
        print("Generated PlayNote ID: $playNoteId");

        await pollStatus(playNoteId);
      } else {
        print("Failed to generate PlayNote: ${response.body}");
      }
    } catch (e) {
      print("Error: $e");
    }
  }

  Future<void> pollStatus(String playNoteId) async {
    final doubleEncodedId = Uri.encodeComponent(playNoteId);
    final statusUrl = Uri.parse("https://api.play.ai/api/v1/playnotes/$doubleEncodedId");

    while (true) {
      try {
        final response = await http.get(statusUrl, headers: headers);
        if (response.statusCode == 200) {
          final data = jsonDecode(response.body);
          final status = data['status'];
          
          if (status == 'completed') {
            print("PlayNote generation complete!");
            print("Audio URL: ${data['audioUrl']}");
            break;
          } else if (status == 'generating') {
            print("Please wait, your PlayNote is still generating...");
            await Future.delayed(Duration(seconds: 120));
          } else {
            print("PlayNote creation failed, please try again.");
            break;
          }
        } else {
          print("Error polling for PlayNote status: ${response.body}");
          break;
        }
      } catch (e) {
        print("Error polling status: $e");
        break;
      }
    }
  }
  ```

  ```swift Swift [expandable] theme={null}
  import Foundation

  let SOURCE_FILE_URL = "https://godinton.kent.sch.uk/media/2601/goldilocks-story.pdf"
  let url = URL(string: "https://api.play.ai/api/v1/playnotes")!

  guard let apiKey = ProcessInfo.processInfo.environment["PLAYAI_API_KEY"],
        let userId = ProcessInfo.processInfo.environment["PLAYAI_USER_ID"] else {
    fatalError("Please set PLAYAI_API_KEY and PLAYAI_USER_ID environment variables")
  }

  let headers = [
    "AUTHORIZATION": apiKey,
    "X-USER-ID": userId,
    "accept": "application/json"
  ]

  let files: [String: Any] = [
    "sourceFileUrl": SOURCE_FILE_URL,
    "synthesisStyle": "podcast",
    "voice1": "s3://voice-cloning-zero-shot/baf1ef41-36b6-428c-9bdf-50ba54682bd8/original/manifest.json",
    "voice1Name": "Angelo",
    "voice2": "s3://voice-cloning-zero-shot/e040bd1b-f190-4bdb-83f0-75ef85b18f84/original/manifest.json",
    "voice2Name": "Deedee"
  ]

  func createPlayNote() async throws {
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.allHTTPHeaderFields = headers
    request.httpBody = try JSONSerialization.data(withJSONObject: files)

    let (data, response) = try await URLSession.shared.data(for: request)
    
    guard let httpResponse = response as? HTTPURLResponse else {
      throw NSError(domain: "", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid response"])
    }

    if httpResponse.statusCode == 201 {
        let result = try JSONDecoder().decode([String: Any].self, from: data)
        print("Request sent successfully!")
        if let playNoteId = result["id"] as? String {
            print("Generated PlayNote ID: \(playNoteId)")
            try await pollStatus(playNoteId: playNoteId)
        }
    } else {
        print("Failed to generate PlayNote: \(String(data: data, encoding: .utf8) ?? "")")
    }
  }

  func pollStatus(playNoteId: String) async throws {
    let doubleEncodedId = playNoteId.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? playNoteId
    let statusUrl = URL(string: "https://api.play.ai/api/v1/playnotes/\(doubleEncodedId)")!

    while true {
        var request = URLRequest(url: statusUrl)
        request.allHTTPHeaderFields = headers

        let (data, response) = try await URLSession.shared.data(for: request)
        
        guard let httpResponse = response as? HTTPURLResponse else {
            throw NSError(domain: "", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid response"])
        }

        if httpResponse.statusCode == 200 {
            let result = try JSONDecoder().decode([String: Any].self, from: data)
            if let status = result["status"] as? String {
                switch status {
                case "completed":
                    print("PlayNote generation complete!")
                    if let audioUrl = result["audioUrl"] as? String {
                        print("Audio URL: \(audioUrl)")
                    }
                    return
                case "generating":
                    print("Please wait, your PlayNote is still generating...")
                    try await Task.sleep(nanoseconds: 120_000_000_000) // 120 seconds
                default:
                    print("PlayNote creation failed, please try again.")
                    return
                }
            }
        } else {
            print("Error polling for PlayNote status: \(String(data: data, encoding: .utf8) ?? "")")
            return
        }
    }
  }

  // Run the async function
  Task {
    do {
        try await createPlayNote()
    } catch {
        print("Error: \(error)")
    }
  }
  ```
</CodeGroup>

## Troubleshooting

If you encounter issues, check these common problems:

* **Authentication Issues:**
  * Verify your API key and user ID are correctly set in your environment
  * Confirm the `AUTHORIZATION` header is properly formatted

* **Source File Issues:**
  * Ensure your PDF URL is publicly accessible
  * Verify the PDF file is not corrupted or password-protected

* **Generation Time:**
  * The process typically takes 5-10 minutes depending on the PDF size
  * If the status remains "generating" for an extended period, try creating a new request

* **API Endpoint Errors:**
  * Verify you're using the correct PlayNote API endpoint
  * Check that your request payload matches the expected format

This guide provides a simple yet powerful way to turn text content from a PDF into a rich, conversational podcast format using PlayNote API. Modify the voice parameters to customize the conversation to match your desired style.
