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

# Audio Separation Callbacks

> When vocal and instrument separation generation is complete, the system will call this callback to notify the results.

When you submit a task to the vocal and instrument separation API, you can use the `callBackUrl` parameter to set a callback URL. When the task is completed, the system will automatically push the results to your specified address.

## Callback Mechanism Overview

<Info>
  The callback mechanism eliminates the need to poll the API for task status. The system will proactively push task completion results to your server. The callback data structure varies based on the `type` parameter specified in the request.
</Info>

### Callback Timing

The system will send callback notifications in the following situations:

* Vocal separation completed
* Vocal separation task failed
* Error occurred during task processing

<Note>
  Vocal separation has only one callback stage, but different numbers of separated audio file URLs are provided based on the separation type (`separate_vocal` or `split_stem`)
</Note>

### Callback Method

* **HTTP Method**: POST
* **Content Type**: application/json
* **Timeout**: 15 seconds

## Callback Request Format

When the task is completed, the system will send a POST request to your `callBackUrl` in the following format. The callback data structure varies based on the requested `type` parameter:

<CodeGroup>
  ```json separate_vocal Type Callback theme={null}
  {
    "code": 200,
    "msg": "vocal Removal generated successfully.",
    "data": {
      "task_id": "3e63b4cc88d52611159371f6af5571e7",
      "vocal_removal_info": {
        "instrumental_url": "https://file.aiquickdraw.com/s/d92a13bf-c6f4-4ade-bb47-f69738435528_Instrumental.mp3",
        "origin_url": "",
        "vocal_url": "https://file.aiquickdraw.com/s/3d7021c9-fa8b-4eda-91d1-3b9297ddb172_Vocals.mp3"
      }
    }
  }
  ```

  ```json split_stem Type Callback theme={null}
  {
    "code": 200,
    "msg": "vocal Removal generated successfully.",
    "data": {
      "task_id": "e649edb7abfd759285bd41a47a634b10",
      "vocal_removal_info": {
        "origin_url": "",
        "backing_vocals_url": "https://file.aiquickdraw.com/s/aadc51a3-4c88-4c8e-a4c8-e867c539673d_Backing_Vocals.mp3",
        "bass_url": "https://file.aiquickdraw.com/s/a3c2da5a-b364-4422-adb5-2692b9c26d33_Bass.mp3",
        "brass_url": "https://file.aiquickdraw.com/s/334b2d23-0c65-4a04-92c7-22f828afdd44_Brass.mp3",
        "drums_url": "https://file.aiquickdraw.com/s/ac75c5ea-ac77-4ad2-b7d9-66e140b78e44_Drums.mp3",
        "fx_url": "https://file.aiquickdraw.com/s/a8822c73-6629-4089-8f2a-d19f41f0007d_FX.mp3",
        "guitar_url": "https://file.aiquickdraw.com/s/064dd08e-d5d2-4201-9058-c5c40fb695b4_Guitar.mp3",
        "keyboard_url": "https://file.aiquickdraw.com/s/adc934e0-df7d-45da-8220-1dba160d74e0_Keyboard.mp3",
        "percussion_url": "https://file.aiquickdraw.com/s/0f70884d-047c-41f1-a6d0-7044618b7dc6_Percussion.mp3",
        "strings_url": "https://file.aiquickdraw.com/s/49829425-a5b0-424e-857a-75d4c63a426b_Strings.mp3",
        "synth_url": "https://file.aiquickdraw.com/s/56b2d94a-eb92-4d21-bc43-3460de0c8348_Synth.mp3",
        "vocal_url": "https://file.aiquickdraw.com/s/07420749-29a2-4054-9b62-e6a6f8b90ccb_Vocals.mp3",
        "woodwinds_url": "https://file.aiquickdraw.com/s/d81545b1-6f94-4388-9785-1aaa6ecabb02_Woodwinds.mp3"
      }
    }
  }
  ```

  ```json split_stem_advanced Type Callback theme={null}
  {
    "code": 200,
    "msg": "vocal Removal generated successfully.",
    "data": {
      "task_id": "7220be2955295dda60de46ec6e4ead4c",
      "vocal_removal_info": {
        "origin_data": [
          {
            "extract": {
              "duration": 194.92,
              "audio_url": "https://tempfile.aiquickdraw.com/r/eb7d0f18-8349-4735-a65e-1812705d5ddf_Lead Vocal.mp3",
              "stem_type_group_name": "Lead Vocal",
              "id": "eb7d0f18-8349-4735-a65e-1812705d5ddf"
            },
            "remove": {
              "duration": 194.92,
              "audio_url": "https://tempfile.aiquickdraw.com/r/706d32df-e988-412e-bce4-42c9302e5478_Lead Vocal.mp3",
              "stem_type_group_name": "Lead Vocal",
              "id": "706d32df-e988-412e-bce4-42c9302e5478"
            }
          },
          {
            "extract": {
              "duration": 194.92,
              "audio_url": "https://tempfile.aiquickdraw.com/r/a7c503f6-1265-4f7e-bf5d-c50fb3b07238_Lead Vocal.mp3",
              "stem_type_group_name": "Lead Vocal",
              "id": "a7c503f6-1265-4f7e-bf5d-c50fb3b07238"
            },
            "remove": {
              "duration": 194.92,
              "audio_url": "https://tempfile.aiquickdraw.com/r/a3a0c954-1980-410f-9b34-8539b8eb23f8_Lead Vocal.mp3",
              "stem_type_group_name": "Lead Vocal",
              "id": "a3a0c954-1980-410f-9b34-8539b8eb23f8"
            }
          }
        ]
      }
    }
  }
  ```

  ```json Vocal Separation Failed Callback theme={null}
  {
    "code": 400,
    "msg": "Vocal separation failed, invalid source audio",
    "data": {
      "task_id": "5e72d367bdfbe44785e28d72cb1697c7",
      "vocal_removal_info": null
    }
  }
  ```
</CodeGroup>

## Status Code Description

<ParamField path="code" type="integer" required>
  Callback status code indicating task processing result:

  | Status Code | Description                                                |
  | ----------- | ---------------------------------------------------------- |
  | 200         | Success - Vocal separation completed                       |
  | 400         | Bad Request - Invalid source audio or parameter error      |
  | 401         | Unauthorized - Invalid API key                             |
  | 429         | Insufficient Credits - Account credit balance insufficient |
  | 500         | Server Error - Please retry later                          |
</ParamField>

<ParamField path="msg" type="string" required>
  Status message providing detailed status description
</ParamField>

<ParamField path="data.task_id" type="string" required>
  Task ID, consistent with the taskId returned when you submitted the task
</ParamField>

<ParamField path="data.vocal_removal_info" type="object">
  Vocal separation result information, returned on success. Fields vary based on separation type
</ParamField>

### separate\_vocal Type Fields

<ParamField path="data.vocal_removal_info.origin_url" type="string">
  Original audio file URL
</ParamField>

<ParamField path="data.vocal_removal_info.vocal_url" type="string">
  Separated vocal audio file URL
</ParamField>

<ParamField path="data.vocal_removal_info.instrumental_url" type="string">
  Separated instrumental audio file URL (no vocals)
</ParamField>

### split\_stem Type Fields

<ParamField path="data.vocal_removal_info.origin_url" type="string">
  Original audio file URL
</ParamField>

<ParamField path="data.vocal_removal_info.vocal_url" type="string">
  Separated vocal audio file URL
</ParamField>

<ParamField path="data.vocal_removal_info.backing_vocals_url" type="string">
  Separated backing vocals audio file URL
</ParamField>

<ParamField path="data.vocal_removal_info.drums_url" type="string">
  Separated drums audio file URL
</ParamField>

<ParamField path="data.vocal_removal_info.bass_url" type="string">
  Separated bass audio file URL
</ParamField>

<ParamField path="data.vocal_removal_info.guitar_url" type="string">
  Separated guitar audio file URL
</ParamField>

<ParamField path="data.vocal_removal_info.keyboard_url" type="string">
  Separated keyboard audio file URL
</ParamField>

<ParamField path="data.vocal_removal_info.percussion_url" type="string">
  Separated percussion instruments audio file URL
</ParamField>

<ParamField path="data.vocal_removal_info.strings_url" type="string">
  Separated string instruments audio file URL
</ParamField>

<ParamField path="data.vocal_removal_info.synth_url" type="string">
  Separated synthesizer audio file URL
</ParamField>

<ParamField path="data.vocal_removal_info.fx_url" type="string">
  Separated sound effects audio file URL
</ParamField>

<ParamField path="data.vocal_removal_info.brass_url" type="string">
  Separated brass instruments audio file URL
</ParamField>

<ParamField path="data.vocal_removal_info.woodwinds_url" type="string">
  Separated woodwind instruments audio file URL
</ParamField>

### split\_stem\_advanced Type Fields

<ParamField path="data.vocal_removal_info.origin_data" type="array">
  An array of separation results for the original audio, containing extraction and removal information for multiple stem groups. Each element represents an independent stem group (e.g., Lead Vocal).
</ParamField>

<ParamField path="data.vocal_removal_info.origin_data[].extract" type="object">
  Information about the extracted target stem (isolates this stem while removing others).
</ParamField>

<ParamField path="data.vocal_removal_info.origin_data[].extract.duration" type="number">
  The duration of the extracted audio, in seconds.
</ParamField>

<ParamField path="data.vocal_removal_info.origin_data[].extract.audio_url" type="string">
  The download URL of the extracted target stem audio file.
</ParamField>

<ParamField path="data.vocal_removal_info.origin_data[].extract.stem_type_group_name" type="string">
  The stem type group name (e.g., Lead Vocal), indicating which type of stem this group extracts.
</ParamField>

<ParamField path="data.vocal_removal_info.origin_data[].extract.id" type="string">
  The unique identifier for the extracted audio.
</ParamField>

<ParamField path="data.vocal_removal_info.origin_data[].remove" type="object">
  Information about the remaining audio after removing the target stem (removes this stem while keeping others).
</ParamField>

<ParamField path="data.vocal_removal_info.origin_data[].remove.duration" type="number">
  The duration of the audio after removal, in seconds.
</ParamField>

<ParamField path="data.vocal_removal_info.origin_data[].remove.audio_url" type="string">
  The download URL of the remaining audio file after the target stem has been removed.
</ParamField>

<ParamField path="data.vocal_removal_info.origin_data[].remove.stem_type_group_name" type="string">
  The stem type group name (e.g., Lead Vocal), consistent with the corresponding extract entry.
</ParamField>

<ParamField path="data.vocal_removal_info.origin_data[].remove.id" type="string">
  The unique identifier for the remaining audio.
</ParamField>

## Callback Reception Examples

Here are example codes for receiving callbacks in various popular programming languages, supporting both separation types:

<Tabs>
  <Tab title="Node.js">
    ```javascript theme={null}
    const express = require('express');
    const fs = require('fs');
    const https = require('https');
    const app = express();

    app.use(express.json());

    app.post('/vocal-separation-callback', (req, res) => {
      const { code, msg, data } = req.body;
      
      console.log('Received vocal separation callback:', {
        taskId: data.task_id,
        status: code,
        message: msg
      });
      
      if (code === 200 && data.vocal_removal_info) {
        // Vocal separation successful
        const vocalInfo = data.vocal_removal_info;
        console.log('Vocal separation completed successfully');
        
        // Determine separation type and download corresponding files
        let audioTypes = [];
        
        if (vocalInfo.instrumental_url) {
          // separate_vocal type
          audioTypes = [
            { name: 'original', url: vocalInfo.origin_url },
            { name: 'vocal', url: vocalInfo.vocal_url },
            { name: 'instrumental', url: vocalInfo.instrumental_url }
          ];
        } else {
          // split_stem type
          audioTypes = [
            { name: 'original', url: vocalInfo.origin_url },
            { name: 'vocal', url: vocalInfo.vocal_url },
            { name: 'backing_vocals', url: vocalInfo.backing_vocals_url },
            { name: 'drums', url: vocalInfo.drums_url },
            { name: 'bass', url: vocalInfo.bass_url },
            { name: 'guitar', url: vocalInfo.guitar_url },
            { name: 'keyboard', url: vocalInfo.keyboard_url },
            { name: 'percussion', url: vocalInfo.percussion_url },
            { name: 'strings', url: vocalInfo.strings_url },
            { name: 'synth', url: vocalInfo.synth_url },
            { name: 'fx', url: vocalInfo.fx_url },
            { name: 'brass', url: vocalInfo.brass_url },
            { name: 'woodwinds', url: vocalInfo.woodwinds_url }
          ];
        }
        
        // Download all separated audio files
        audioTypes.forEach(audio => {
          if (audio.url) {
            const filename = `${data.task_id}_${audio.name}.mp3`;
            const file = fs.createWriteStream(filename);
            
            https.get(audio.url, (response) => {
              response.pipe(file);
              
              file.on('finish', () => {
                file.close();
                console.log(`${audio.name} audio downloaded as ${filename}`);
              });
            }).on('error', (err) => {
              console.error(`${audio.name} audio download failed:`, err.message);
            });
          }
        });
        
      } else {
        // Task failed
        console.log('Vocal separation failed:', msg);
        
        // Handle failure cases...
        if (code === 400) {
          console.log('Invalid source audio or parameter error');
        } else if (code === 429) {
          console.log('Insufficient credits');
        } else if (code === 500) {
          console.log('Server internal error');
        }
      }
      
      // Return 200 status code to confirm callback received
      res.status(200).json({ status: 'received' });
    });

    app.listen(3000, () => {
      console.log('Vocal separation callback server running on port 3000');
    });
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    from flask import Flask, request, jsonify
    import requests
    import os

    app = Flask(__name__)

    @app.route('/vocal-separation-callback', methods=['POST'])
    def handle_callback():
        data = request.json
        
        code = data.get('code')
        msg = data.get('msg')
        callback_data = data.get('data', {})
        task_id = callback_data.get('task_id')
        vocal_info = callback_data.get('vocal_removal_info')
        
        print(f"Received vocal separation callback: {task_id}, Status: {code}")
        
        if code == 200 and vocal_info:
            # Vocal separation successful
            print("Vocal separation completed successfully")
            
            # Determine separation type based on callback content
            if vocal_info.get('instrumental_url'):
                # separate_vocal type
                audio_types = [
                    ('original', vocal_info.get('origin_url')),
                    ('vocal', vocal_info.get('vocal_url')),
                    ('instrumental', vocal_info.get('instrumental_url'))
                ]
            else:
                # split_stem type
                audio_types = [
                    ('original', vocal_info.get('origin_url')),
                    ('vocal', vocal_info.get('vocal_url')),
                    ('backing_vocals', vocal_info.get('backing_vocals_url')),
                    ('drums', vocal_info.get('drums_url')),
                    ('bass', vocal_info.get('bass_url')),
                    ('guitar', vocal_info.get('guitar_url')),
                    ('keyboard', vocal_info.get('keyboard_url')),
                    ('percussion', vocal_info.get('percussion_url')),
                    ('strings', vocal_info.get('strings_url')),
                    ('synth', vocal_info.get('synth_url')),
                    ('fx', vocal_info.get('fx_url')),
                    ('brass', vocal_info.get('brass_url')),
                    ('woodwinds', vocal_info.get('woodwinds_url'))
                ]
            
            # Download all separated audio files
            for audio_name, audio_url in audio_types:
                if audio_url:
                    try:
                        response = requests.get(audio_url)
                        if response.status_code == 200:
                            filename = f"{task_id}_{audio_name}.mp3"
                            with open(filename, "wb") as f:
                                f.write(response.content)
                            
                            # Check file size
                            file_size = os.path.getsize(filename)
                            print(f"{audio_name} audio downloaded as {filename}, size: {file_size} bytes")
                            
                    except Exception as e:
                        print(f"{audio_name} audio download failed: {e}")
            
        else:
            # Task failed
            print(f"Vocal separation failed: {msg}")
            
            # Handle failure cases...
            if code == 400:
                print("Invalid source audio or parameter error")
            elif code == 429:
                print("Insufficient credits")
            elif code == 500:
                print("Server internal error")
        
        # Return 200 status code to confirm callback received
        return jsonify({'status': 'received'}), 200

    if __name__ == '__main__':
        app.run(host='0.0.0.0', port=3000)
    ```
  </Tab>

  <Tab title="PHP">
    ```php theme={null}
    <?php
    header('Content-Type: application/json');

    // Get POST data
    $input = file_get_contents('php://input');
    $data = json_decode($input, true);

    $code = $data['code'] ?? null;
    $msg = $data['msg'] ?? '';
    $callbackData = $data['data'] ?? [];
    $taskId = $callbackData['task_id'] ?? '';
    $vocalInfo = $callbackData['vocal_removal_info'] ?? null;

    error_log("Received vocal separation callback: $taskId, Status: $code");

    if ($code === 200 && $vocalInfo) {
        // Vocal separation successful
        error_log("Vocal separation completed successfully");
        
        // Determine separation type and download corresponding files
        if (isset($vocalInfo['instrumental_url'])) {
            // separate_vocal type
            $audioTypes = [
                'original' => $vocalInfo['origin_url'] ?? '',
                'vocal' => $vocalInfo['vocal_url'] ?? '',
                'instrumental' => $vocalInfo['instrumental_url'] ?? ''
            ];
        } else {
            // split_stem type
            $audioTypes = [
                'original' => $vocalInfo['origin_url'] ?? '',
                'vocal' => $vocalInfo['vocal_url'] ?? '',
                'backing_vocals' => $vocalInfo['backing_vocals_url'] ?? '',
                'drums' => $vocalInfo['drums_url'] ?? '',
                'bass' => $vocalInfo['bass_url'] ?? '',
                'guitar' => $vocalInfo['guitar_url'] ?? '',
                'keyboard' => $vocalInfo['keyboard_url'] ?? '',
                'percussion' => $vocalInfo['percussion_url'] ?? '',
                'strings' => $vocalInfo['strings_url'] ?? '',
                'synth' => $vocalInfo['synth_url'] ?? '',
                'fx' => $vocalInfo['fx_url'] ?? '',
                'brass' => $vocalInfo['brass_url'] ?? '',
                'woodwinds' => $vocalInfo['woodwinds_url'] ?? ''
            ];
        }
        
        // Download all separated audio files
        foreach ($audioTypes as $audioName => $audioUrl) {
            if ($audioUrl) {
                try {
                    $audioContent = file_get_contents($audioUrl);
                    if ($audioContent !== false) {
                        $filename = "{$taskId}_{$audioName}.mp3";
                        file_put_contents($filename, $audioContent);
                        
                        // Check file size
                        $fileSize = filesize($filename);
                        error_log("$audioName audio downloaded as $filename, size: $fileSize bytes");
                    }
                } catch (Exception $e) {
                    error_log("$audioName audio download failed: " . $e->getMessage());
                }
            }
        }
        
    } else {
        // Task failed
        error_log("Vocal separation failed: $msg");
        
        // Handle failure cases...
        if ($code === 400) {
            error_log("Invalid source audio or parameter error");
        } elseif ($code === 429) {
            error_log("Insufficient credits");
        } elseif ($code === 500) {
            error_log("Server internal error");
        }
    }



    // Return 200 status code to confirm callback received
    http_response_code(200);
    echo json_encode(['status' => 'received']);
    ?>
    ```
  </Tab>
</Tabs>

## Best Practices

<Tip>
  ### Vocal Separation Callback Configuration

  1. **Multi-track Management**: Organize separated tracks with clear naming conventions
  2. **Quality Assessment**: Verify separation quality for each track type
  3. **Storage Organization**: Create folder structures for different separation projects
  4. **Batch Processing**: Implement efficient batch downloads for multiple tracks
  5. **Track Analysis**: Analyze separated tracks for remix and production purposes
  6. **Backup Strategy**: Maintain backups of both original and separated tracks
</Tip>

<Warning>
  ### Separation-Specific Considerations

  * Separation quality depends on the complexity of the original mix
  * Some instruments may not separate cleanly in all cases
  * Vocal separation works best with clear, well-mixed source material
  * Multiple separated files require significant storage space
  * Processing time varies based on track length and complexity
</Warning>

## Troubleshooting

Common issues specific to vocal separation callbacks:

<AccordionGroup>
  <Accordion title="Separation Quality">
    * Verify the source audio quality and mixing
    * Check if the original track has clear instrument separation
    * Consider the complexity of the musical arrangement
    * Test with different source materials to understand limitations
  </Accordion>

  <Accordion title="Multi-file Downloads">
    * Ensure stable network connection for multiple large file downloads
    * Implement error handling for partial download failures
    * Verify all track URLs are accessible and not expired
    * Monitor download progress for all separated tracks
  </Accordion>

  <Accordion title="Storage and Organization">
    * Plan adequate storage for multiple separated track files
    * Implement consistent naming conventions for track identification
    * Consider automated organization based on task IDs
    * Monitor disk space usage for large separation projects
  </Accordion>
</AccordionGroup>

## Alternative Solutions

If you cannot use the callback mechanism, you can also use polling:

<Card title="Poll Separation Results" icon="radar" href="/suno-api/get-vocal-separation-details">
  Use the Get Vocal Separation Details interface to regularly query separation task status. Recommend querying every 30 seconds.
</Card>
