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

# Async TTS API Quickstart

> Learn how to use PlayAI's asynchronous Text-to-Speech API

This guide provides a step-by-step approach to using the PlayAI Text-to-Speech API to convert text into natural human-like sounding audio using [the Async (non-streaming) API Endpoint](/api-reference/text-to-speech/endpoints/v1/create-speech).

In this example, we'll have [Dialog 1.0](/documentation/text-to-speech/tts-models#dialog-10) create a simple audio from the given input text.

## Prerequisites

* [Access credentials](https://play.ai/api/keys) (Secret key and User ID)
* Development environment for your chosen programming language

## 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 for your chosen language:

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

      api_key = os.getenv("PLAYAI_API_KEY")
      user_id = os.getenv("PLAYAI_USER_ID")

      headers = {
          'Authorization': f'Bearer {api_key}',
          'Content-Type': 'application/json',
          'X-USER-ID': user_id
      }
      ```

      ```javascript JavaScript theme={null}
      const apiKey = process.env.PLAYAI_API_KEY;
      const userId = process.env.PLAYAI_USER_ID;

      const headers = {
        'Authorization': `Bearer ${apiKey}`,
        'Content-Type': 'application/json',
        'X-USER-ID': userId
      };
      ```

      ```go Go theme={null}
      apiKey := os.Getenv("PLAYAI_API_KEY")
      userId := os.Getenv("PLAYAI_USER_ID")

      headers := map[string]string{
        "Authorization": fmt.Sprintf("Bearer %s", apiKey),
        "Content-Type": "application/json",
        "X-USER-ID": userId,
      }
      ```

      ```dart Dart theme={null}
      final apiKey = Platform.environment['PLAYAI_API_KEY'];
      final userId = Platform.environment['PLAYAI_USER_ID'];

      final headers = {
        'Authorization': 'Bearer $apiKey',
        'Content-Type': 'application/json',
        'X-USER-ID': userId,
      };
      ```

      ```swift Swift theme={null}
      let apiKey = ProcessInfo.processInfo.environment["PLAYAI_API_KEY"] ?? ""
      let userId = ProcessInfo.processInfo.environment["PLAYAI_USER_ID"] ?? ""

      let headers = [
        "Authorization": "Bearer \(apiKey)",
        "Content-Type": "application/json",
        "X-USER-ID": userId
      ]
      ```
    </CodeGroup>
  </Step>

  <Step title="Submit TTS Job">
    Create and submit your TTS job in your chosen language:

    <CodeGroup>
      ```python Python theme={null}
      json_data = {
          'model': 'PlayDialog',
          'text': "This is the greatest moment to be alive",
          'voice': 's3://voice-cloning-zero-shot/baf1ef41-36b6-428c-9bdf-50ba54682bd8/original/manifest.json',
          'outputFormat': 'mp3',
          'speed': 1,
          'language': 'english',
      }

      response = requests.post('https://api.play.ai/api/v1/tts',
                             headers=headers,
                             json=json_data)

      if response.status_code == 201:
          job_id = response.json().get('id')
          print(f"Job submitted successfully. Job ID: {job_id}")
      else:
          print(f"Job submission failed with status code {response.status_code}: {response.text}")
      ```

      ```javascript JavaScript theme={null}
      const jsonData = {
        model: 'PlayDialog',
        text: "This is the greatest moment to be alive",
        voice: 's3://voice-cloning-zero-shot/baf1ef41-36b6-428c-9bdf-50ba54682bd8/original/manifest.json',
        outputFormat: 'mp3',
        speed: 1,
        language: 'english'
      };

      fetch('https://api.play.ai/api/v1/tts', {
        method: 'POST',
        headers: headers,
        body: JSON.stringify(jsonData)
      })
      .then(response => {
        if (response.status === 201) {
          return response.json();
        }
        throw new Error(`Request failed with status ${response.status}`);
      })
      .then(data => {
        const jobId = data.id;
        console.log(`Job submitted successfully. Job ID: ${jobId}`);
      })
      .catch(error => console.error('Error:', error));
      ```

      ```go Go theme={null}
      jsonData := map[string]interface{}{
        "model": "PlayDialog",
        "text": "This is the greatest moment to be alive",
        "voice": "s3://voice-cloning-zero-shot/baf1ef41-36b6-428c-9bdf-50ba54682bd8/original/manifest.json",
        "outputFormat": "mp3",
        "speed": 1,
        "language": "english",
      }

      jsonBytes, _ := json.Marshal(jsonData)
      req, _ := http.NewRequest("POST", "https://api.play.ai/api/v1/tts", bytes.NewBuffer(jsonBytes))

      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)
        jobId := result["id"].(string)
        fmt.Printf("Job submitted successfully. Job ID: %s\n", jobId)
      } else {
        body, _ := io.ReadAll(resp.Body)
        fmt.Printf("Job submission failed with status code %d: %s\n", resp.StatusCode, string(body))
      }
      ```

      ```dart Dart theme={null}
      final jsonData = {
        'model': 'PlayDialog',
        'text': 'This is the greatest moment to be alive',
        'voice': 's3://voice-cloning-zero-shot/baf1ef41-36b6-428c-9bdf-50ba54682bd8/original/manifest.json',
        'outputFormat': 'mp3',
        'speed': 1,
        'language': 'english',
      };

      final response = await http.post(
        Uri.parse('https://api.play.ai/api/v1/tts'),
        headers: headers,
        body: jsonEncode(jsonData),
      );

      if (response.statusCode == 201) {
        final data = jsonDecode(response.body);
        final jobId = data['id'];
        print('Job submitted successfully. Job ID: $jobId');
      } else {
        print('Job submission failed with status code ${response.statusCode}: ${response.body}');
      }
      ```

      ```swift Swift theme={null}
      let jsonData: [String: Any] = [
        "model": "PlayDialog",
        "text": "This is the greatest moment to be alive",
        "voice": "s3://voice-cloning-zero-shot/baf1ef41-36b6-428c-9bdf-50ba54682bd8/original/manifest.json",
        "outputFormat": "mp3",
        "speed": 1,
        "language": "english"
      ]

      guard let jsonData = try? JSONSerialization.data(withJSONObject: jsonData) else {
        print("Failed to serialize JSON data")
        exit(1)
      }

      var request = URLRequest(url: URL(string: "https://api.play.ai/api/v1/tts")!)
      request.httpMethod = "POST"
      request.allHTTPHeaderFields = headers
      request.httpBody = jsonData

      let task = URLSession.shared.dataTask(with: request) { data, response, error in
        if let error = error {
            print("Error: \(error)")
            return
        }

        guard let httpResponse = response as? HTTPURLResponse else {
            print("Invalid response")
            return
        }

        if httpResponse.statusCode == 201 {
            if let data = data,
               let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
               let jobId = json["id"] as? String {
                print("Job submitted successfully. Job ID: \(jobId)")
            }
        } else {
            print("Job submission failed with status code \(httpResponse.statusCode)")
            if let data = data, let responseString = String(data: data, encoding: .utf8) {
                print("Response: \(responseString)")
            }
        }
      }
      task.resume()
      ```
    </CodeGroup>
  </Step>

  <Step title="Poll Job Status">
    Monitor your job's progress in your chosen language:

    <CodeGroup>
      ```python Python theme={null}
      polling_url = f'https://api.play.ai/api/v1/tts/{job_id}'

      while True:
          response = requests.get(polling_url, headers=headers)
          status = response.json()['output']['status']

          if status == 'COMPLETED':
              audio_url = response.json()['output']['url']
              print(f"Job completed. Audio URL: {audio_url}")
              break
          elif status == 'IN_PROGRESS':
              print("Job is still in progress. Retrying in 5 seconds...")
              time.sleep(5)
          else:
              print(f"Job failed or encountered an unknown status: {status}")
              break
      ```

      ```javascript JavaScript theme={null}
      const pollJobStatus = async (jobId) => {
        while (true) {
          const response = await fetch(`https://api.play.ai/api/v1/tts/${jobId}`, {
            headers: headers
          });
          const data = await response.json();
          const status = data.output.status;

          if (status === 'COMPLETED') {
            const audioUrl = data.output.url;
            console.log(`Job completed. Audio URL: ${audioUrl}`);
            break;
          } else if (status === 'IN_PROGRESS') {
            console.log("Job is still in progress. Retrying in 5 seconds...");
            await new Promise(resolve => setTimeout(resolve, 5000));
          } else {
            console.log(`Job failed or encountered an unknown status: ${status}`);
            break;
          }
        }
      };
      ```

      ```go Go theme={null}
      func pollJobStatus(jobId string) {
        for {
          req, _ := http.NewRequest("GET", fmt.Sprintf("https://api.play.ai/api/v1/tts/%s", jobId), nil)
          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()

          var result map[string]interface{}
          json.NewDecoder(resp.Body).Decode(&result)
          status := result["output"].(map[string]interface{})["status"].(string)

          if status == "COMPLETED" {
            audioUrl := result["output"].(map[string]interface{})["url"].(string)
            fmt.Printf("Job completed. Audio URL: %s\n", audioUrl)
            break
          } else if status == "IN_PROGRESS" {
            fmt.Println("Job is still in progress. Retrying in 5 seconds...")
            time.Sleep(5 * time.Second)
          } else {
            fmt.Printf("Job failed or encountered an unknown status: %s\n", status)
            break
          }
        }
      }
      ```

      ```dart Dart theme={null}
      Future<void> pollJobStatus(String jobId) async {
        while (true) {
          final response = await http.get(
            Uri.parse('https://api.play.ai/api/v1/tts/$jobId'),
            headers: headers,
          );

          final data = jsonDecode(response.body);
          final status = data['output']['status'];

          if (status == 'COMPLETED') {
            final audioUrl = data['output']['url'];
            print('Job completed. Audio URL: $audioUrl');
            break;
          } else if (status == 'IN_PROGRESS') {
            print('Job is still in progress. Retrying in 5 seconds...');
            await Future.delayed(Duration(seconds: 5));
          } else {
            print('Job failed or encountered an unknown status: $status');
            break;
          }
        }
      }
      ```

      ```swift Swift theme={null}
      func pollJobStatus(jobId: String) {
        while true {
          var request = URLRequest(url: URL(string: "https://api.play.ai/api/v1/tts/\(jobId)")!)
          request.allHTTPHeaderFields = headers

          let task = URLSession.shared.dataTask(with: request) { data, response, error in
            if let error = error {
                print("Error: \(error)")
                return
            }

            guard let httpResponse = response as? HTTPURLResponse,
                  let data = data,
                  let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
                  let output = json["output"] as? [String: Any],
                  let status = output["status"] as? String else {
                return
            }

            if status == "COMPLETED" {
                if let audioUrl = output["url"] as? String {
                    print("Job completed. Audio URL: \(audioUrl)")
                }
                exit(0)
            } else if status == "IN_PROGRESS" {
                print("Job is still in progress. Retrying in 5 seconds...")
                Thread.sleep(forTimeInterval: 5)
            } else {
                print("Job failed or encountered an unknown status: \(status)")
                exit(1)
            }
          }
          task.resume()
          RunLoop.main.run(until: Date(timeIntervalSinceNow: 5))
        }
      }
      ```
    </CodeGroup>
  </Step>

  <Step title="Download and Save Audio">
    Save the generated audio file in your chosen language:

    <CodeGroup>
      ```python Python theme={null}
      audio_url = response.json()['output']['url']
      audio_response = requests.get(audio_url)

      if audio_response.status_code == 200:
          with open('output.mp3', 'wb') as f:
              f.write(audio_response.content)
          print("Audio file saved as output.mp3")
      else:
          print(f"Failed to download audio. Status code: {audio_response.status_code}")
      ```

      ```javascript JavaScript theme={null}
      const downloadAudio = async (audioUrl) => {
        const response = await fetch(audioUrl);
        if (response.ok) {
          const blob = await response.blob();
          const url = window.URL.createObjectURL(blob);
          const a = document.createElement('a');
          a.href = url;
          a.download = 'output.mp3';
          a.click();
          window.URL.revokeObjectURL(url);
          console.log("Audio file saved as output.mp3");
        } else {
          console.log(`Failed to download audio. Status: ${response.status}`);
        }
      };
      ```

      ```go Go theme={null}
      func downloadAudio(audioUrl string) {
        resp, err := http.Get(audioUrl)
        if err != nil {
          log.Fatal(err)
        }
        defer resp.Body.Close()

        if resp.StatusCode == 200 {
          out, _ := os.Create("output.mp3")
          defer out.Close()
          io.Copy(out, resp.Body)
          fmt.Println("Audio file saved as output.mp3")
        } else {
          fmt.Printf("Failed to download audio. Status code: %d\n", resp.StatusCode)
        }
      }
      ```

      ```dart Dart theme={null}
      Future<void> downloadAudio(String audioUrl) async {
        final response = await http.get(Uri.parse(audioUrl));
        if (response.statusCode == 200) {
          final file = File('output.mp3');
          await file.writeAsBytes(response.bodyBytes);
          print('Audio file saved as output.mp3');
        } else {
          print('Failed to download audio. Status code: ${response.statusCode}');
        }
      }
      ```

      ```swift Swift theme={null}
      func downloadAudio(audioUrl: String) {
        guard let url = URL(string: audioUrl) else { return }
        
        let task = URLSession.shared.dataTask(with: url) { data, response, error in
          if let error = error {
            print("Error: \(error)")
            return
          }

          guard let httpResponse = response as? HTTPURLResponse else {
            print("Invalid response")
            return
          }

          if httpResponse.statusCode == 200 {
            if let data = data {
              do {
                try data.write(to: URL(fileURLWithPath: "output.mp3"))
                print("Audio file saved as output.mp3")
              } catch {
                print("Error saving file: \(error)")
              }
            }
          } else {
            print("Failed to download audio. Status code: \(httpResponse.statusCode)")
          }
        }
        task.resume()
      }
      ```
    </CodeGroup>
  </Step>
</Steps>

## Complete Code

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

  api_key = os.getenv("PLAYAI_API_KEY")
  user_id = os.getenv("PLAYAI_USER_ID")

  headers = {
      'Authorization': f'Bearer {api_key}',
      'Content-Type': 'application/json',
      'X-USER-ID': user_id
  }

  # Submit TTS Job
  json_data = {
      'model': 'PlayDialog',
      'text': "This is the greatest moment to be alive",
      'voice': 's3://voice-cloning-zero-shot/baf1ef41-36b6-428c-9bdf-50ba54682bd8/original/manifest.json',
      'outputFormat': 'mp3',
      'speed': 1,
      'language': 'english',
  }

  response = requests.post('https://api.play.ai/api/v1/tts',
                         headers=headers,
                         json=json_data)

  if response.status_code == 201:
      job_id = response.json().get('id')
      print(f"Job submitted successfully. Job ID: {job_id}")

      # Poll Job Status
      polling_url = f'https://api.play.ai/api/v1/tts/{job_id}'
      while True:
          response = requests.get(polling_url, headers=headers)
          status = response.json()['output']['status']

          if status == 'COMPLETED':
              audio_url = response.json()['output']['url']
              print(f"Job completed. Audio URL: {audio_url}")

              # Download Audio
              audio_response = requests.get(audio_url)
              if audio_response.status_code == 200:
                  with open('output.mp3', 'wb') as f:
                      f.write(audio_response.content)
                  print("Audio file saved as output.mp3")
              else:
                  print(f"Failed to download audio. Status code: {audio_response.status_code}")
              break
          elif status == 'IN_PROGRESS':
              print("Job is still in progress. Retrying in 5 seconds...")
              time.sleep(5)
          else:
              print(f"Job failed or encountered an unknown status: {status}")
              break
  else:
      print(f"Job submission failed with status code {response.status_code}: {response.text}")
  ```

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

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

  const headers = {
    'Authorization': `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
    'X-USER-ID': userId
  };

  // Submit TTS Job
  const jsonData = {
    model: 'PlayDialog',
    text: "This is the greatest moment to be alive",
    voice: 's3://voice-cloning-zero-shot/baf1ef41-36b6-428c-9bdf-50ba54682bd8/original/manifest.json',
    outputFormat: 'mp3',
    speed: 1,
    language: 'english'
  };

  fetch('https://api.play.ai/api/v1/tts', {
    method: 'POST',
    headers: headers,
    body: JSON.stringify(jsonData)
  })
  .then(response => {
    if (response.status === 201) {
      return response.json();
    }
    throw new Error(`Request failed with status ${response.status}`);
  })
  .then(data => {
    const jobId = data.id;
    console.log(`Job submitted successfully. Job ID: ${jobId}`);

    // Poll Job Status
    const pollJobStatus = async (jobId) => {
      while (true) {
        const response = await fetch(`https://api.play.ai/api/v1/tts/${jobId}`, {
          headers: headers
        });
        const data = await response.json();
        const status = data.output.status;

        if (status === 'COMPLETED') {
          const audioUrl = data.output.url;
          console.log(`Job completed. Audio URL: ${audioUrl}`);

          // Download Audio
          const audioResponse = await fetch(audioUrl);
          if (audioResponse.ok) {
            const blob = await audioResponse.blob();
            const url = window.URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = 'output.mp3';
            a.click();
            window.URL.revokeObjectURL(url);
            console.log("Audio file saved as output.mp3");
          } else {
            console.log(`Failed to download audio. Status: ${audioResponse.status}`);
          }
          break;
        } else if (status === 'IN_PROGRESS') {
          console.log("Job is still in progress. Retrying in 5 seconds...");
          await new Promise(resolve => setTimeout(resolve, 5000));
        } else {
          console.log(`Job failed or encountered an unknown status: ${status}`);
          break;
        }
      }
    };

    return pollJobStatus(jobId);
  })
  .catch(error => console.error('Error:', error));
  ```

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

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

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

    headers := map[string]string{
      "Authorization": fmt.Sprintf("Bearer %s", apiKey),
      "Content-Type": "application/json",
      "X-USER-ID": userId,
    }

    // Submit TTS Job
    jsonData := map[string]interface{}{
      "model": "PlayDialog",
      "text": "This is the greatest moment to be alive",
      "voice": "s3://voice-cloning-zero-shot/baf1ef41-36b6-428c-9bdf-50ba54682bd8/original/manifest.json",
      "outputFormat": "mp3",
      "speed": 1,
      "language": "english",
    }

    jsonBytes, _ := json.Marshal(jsonData)
    req, _ := http.NewRequest("POST", "https://api.play.ai/api/v1/tts", bytes.NewBuffer(jsonBytes))
    
    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)
      jobId := result["id"].(string)
      fmt.Printf("Job submitted successfully. Job ID: %s\n", jobId)

      // Poll Job Status
      for {
        req, _ := http.NewRequest("GET", fmt.Sprintf("https://api.play.ai/api/v1/tts/%s", jobId), nil)
        for key, value := range headers {
          req.Header.Add(key, value)
        }

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

        var result map[string]interface{}
        json.NewDecoder(resp.Body).Decode(&result)
        status := result["output"].(map[string]interface{})["status"].(string)

        if status == "COMPLETED" {
          audioUrl := result["output"].(map[string]interface{})["url"].(string)
          fmt.Printf("Job completed. Audio URL: %s\n", audioUrl)

          // Download Audio
          resp, err := http.Get(audioUrl)
          if err != nil {
            log.Fatal(err)
          }
          defer resp.Body.Close()

          if resp.StatusCode == 200 {
            out, _ := os.Create("output.mp3")
            defer out.Close()
            io.Copy(out, resp.Body)
            fmt.Println("Audio file saved as output.mp3")
          } else {
            fmt.Printf("Failed to download audio. Status code: %d\n", resp.StatusCode)
          }
          break
        } else if status == "IN_PROGRESS" {
          fmt.Println("Job is still in progress. Retrying in 5 seconds...")
          time.Sleep(5 * time.Second)
        } else {
          fmt.Printf("Job failed or encountered an unknown status: %s\n", status)
          break
        }
      }
    } else {
      body, _ := io.ReadAll(resp.Body)
      fmt.Printf("Job submission failed with status code %d: %s\n", resp.StatusCode, string(body))
    }
  }
  ```

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

  void main() async {
    final apiKey = Platform.environment['PLAYAI_API_KEY'];
    final userId = Platform.environment['PLAYAI_USER_ID'];

    final headers = {
      'Authorization': 'Bearer $apiKey',
      'Content-Type': 'application/json',
      'X-USER-ID': userId,
    };

    // Submit TTS Job
    final jsonData = {
      'model': 'PlayDialog',
      'text': 'This is the greatest moment to be alive',
      'voice': 's3://voice-cloning-zero-shot/baf1ef41-36b6-428c-9bdf-50ba54682bd8/original/manifest.json',
      'outputFormat': 'mp3',
      'speed': 1,
      'language': 'english',
    };

    final response = await http.post(
      Uri.parse('https://api.play.ai/api/v1/tts'),
      headers: headers,
      body: jsonEncode(jsonData),
    );

    if (response.statusCode == 201) {
      final data = jsonDecode(response.body);
      final jobId = data['id'];
      print('Job submitted successfully. Job ID: $jobId');

      // Poll Job Status
      while (true) {
        final response = await http.get(
          Uri.parse('https://api.play.ai/api/v1/tts/$jobId'),
          headers: headers,
        );

        final data = jsonDecode(response.body);
        final status = data['output']['status'];

        if (status == 'COMPLETED') {
          final audioUrl = data['output']['url'];
          print('Job completed. Audio URL: $audioUrl');

          // Download Audio
          final audioResponse = await http.get(Uri.parse(audioUrl));
          if (audioResponse.statusCode == 200) {
            final file = File('output.mp3');
            await file.writeAsBytes(audioResponse.bodyBytes);
            print('Audio file saved as output.mp3');
          } else {
            print('Failed to download audio. Status code: ${audioResponse.statusCode}');
          }
          break;
        } else if (status == 'IN_PROGRESS') {
          print('Job is still in progress. Retrying in 5 seconds...');
          await Future.delayed(Duration(seconds: 5));
        } else {
          print('Job failed or encountered an unknown status: $status');
          break;
        }
      }
    } else {
      print('Job submission failed with status code ${response.statusCode}: ${response.body}');
    }
  }
  ```

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

  let apiKey = ProcessInfo.processInfo.environment["PLAYAI_API_KEY"] ?? ""
  let userId = ProcessInfo.processInfo.environment["PLAYAI_USER_ID"] ?? ""

  let headers = [
    "Authorization": "Bearer \(apiKey)",
    "Content-Type": "application/json",
    "X-USER-ID": userId
  ]

  // Submit TTS Job
  let jsonData: [String: Any] = [
    "model": "PlayDialog",
    "text": "This is the greatest moment to be alive",
    "voice": "s3://voice-cloning-zero-shot/baf1ef41-36b6-428c-9bdf-50ba54682bd8/original/manifest.json",
    "outputFormat": "mp3",
    "speed": 1,
    "language": "english"
  ]

  guard let jsonData = try? JSONSerialization.data(withJSONObject: jsonData) else {
    print("Failed to serialize JSON data")
    exit(1)
  }

  var request = URLRequest(url: URL(string: "https://api.play.ai/api/v1/tts")!)
  request.httpMethod = "POST"
  request.allHTTPHeaderFields = headers
  request.httpBody = jsonData

  let task = URLSession.shared.dataTask(with: request) { data, response, error in
    if let error = error {
        print("Error: \(error)")
        return
    }

    guard let httpResponse = response as? HTTPURLResponse else {
        print("Invalid response")
        return
    }

    if httpResponse.statusCode == 201 {
        if let data = data,
           let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
           let jobId = json["id"] as? String {
            print("Job submitted successfully. Job ID: \(jobId)")

            // Poll Job Status
            func pollJobStatus(jobId: String) {
                while true {
                    var request = URLRequest(url: URL(string: "https://api.play.ai/api/v1/tts/\(jobId)")!)
                    request.allHTTPHeaderFields = headers

                    let task = URLSession.shared.dataTask(with: request) { data, response, error in
                        if let error = error {
                            print("Error: \(error)")
                            return
                        }

                        guard let httpResponse = response as? HTTPURLResponse,
                              let data = data,
                              let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
                              let output = json["output"] as? [String: Any],
                              let status = output["status"] as? String else {
                            return
                        }

                        if status == "COMPLETED" {
                            if let audioUrl = output["url"] as? String {
                                print("Job completed. Audio URL: \(audioUrl)")

                                // Download Audio
                                guard let url = URL(string: audioUrl) else { return }
                                let downloadTask = URLSession.shared.dataTask(with: url) { data, response, error in
                                    if let error = error {
                                        print("Error: \(error)")
                                        return
                                    }

                                    guard let httpResponse = response as? HTTPURLResponse else {
                                        print("Invalid response")
                                        return
                                    }

                                    if httpResponse.statusCode == 200 {
                                        if let data = data {
                                            do {
                                                try data.write(to: URL(fileURLWithPath: "output.mp3"))
                                                print("Audio file saved as output.mp3")
                                            } catch {
                                                print("Error saving file: \(error)")
                                            }
                                        }
                                    } else {
                                        print("Failed to download audio. Status code: \(httpResponse.statusCode)")
                                    }
                                }
                                downloadTask.resume()
                            }
                            exit(0)
                        } else if status == "IN_PROGRESS" {
                            print("Job is still in progress. Retrying in 5 seconds...")
                            Thread.sleep(forTimeInterval: 5)
                        } else {
                            print("Job failed or encountered an unknown status: \(status)")
                            exit(1)
                        }
                    }
                    task.resume()
                    RunLoop.main.run(until: Date(timeIntervalSinceNow: 5))
                }
            }

            pollJobStatus(jobId: jobId)
        }
    } else {
        print("Job submission failed with status code \(httpResponse.statusCode)")
        if let data = data, let responseString = String(data: data, encoding: .utf8) {
            print("Response: \(responseString)")
        }
    }
  }
  task.resume()
  RunLoop.main.run()
  ```
</CodeGroup>

## Troubleshooting

If you encounter issues, check these common problems:

* **Authentication Issues:**
  * Verify your API key and user ID
  * Confirm the `AUTHORIZATION` header includes "Bearer " prefix

* **Job Status Polling:**
  * Ensure you're using the correct job ID
  * Check that the polling URL is properly formatted
  * Verify the polling interval is appropriate for your use case

* **API Endpoint Errors:**
  * Verify the correct PlayAI's Dialog 1.0 API endpoint URL
  * Confirm the model name is correct
  * Check that all required parameters are included in the request

* **Language-Specific Issues:**
  * JavaScript: Ensure `node-fetch` is installed for Node.js environments
  * Go: Check for proper error handling and response body closing
  * Dart: Verify the `http` package is added to your `pubspec.yaml`
  * Swift: Make sure you're running on macOS for file system access
