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

# 替换音乐分区回调

> 当音乐分区替换完成时，系统会调用此回调通知结果。

当您向Suno API提交音乐分区替换任务时，可以使用 `callBackUrl` 参数设置回调URL。任务完成时，系统将自动向您指定的地址推送结果。

## 回调机制概述

<Info>
  回调机制消除了轮询API获取任务状态的需要。系统会主动向您的服务器推送任务完成结果。
</Info>

### 回调时机

系统将在以下情况发送回调通知：

* 音乐分区替换任务成功完成
* 音乐分区替换任务失败
* 任务处理过程中发生错误

### 回调方式

* **HTTP方法**: POST
* **内容类型**: application/json
* **超时设置**: 15秒

## 回调请求格式

任务完成时，系统将以下格式向您的 `callBackUrl` 发送POST请求：

<CodeGroup>
  ```json 成功回调 theme={null}
  {
    "code": 200,
    "msg": "All generated successfully.",
    "data": {
      "callbackType": "complete",
      "task_id": "2fac****9f72",
      "data": [
        {
          "id": "e231****-****-****-****-****8cadc7dc",
          "audio_url": "https://example.cn/****.mp3",
          "stream_audio_url": "https://example.cn/****",
          "image_url": "https://example.cn/****.jpeg",
          "prompt": "[Verse] 替换后的音乐内容",
          "model_name": "chirp-v3-5",
          "title": "替换后的标题",
          "tags": "electrifying, rock",
          "createTime": "2025-01-01 00:00:00",
          "duration": 198.44
        }
      ]
    }
  }
  ```

  ```json 失败回调 theme={null}
  {
    "code": 501,
    "msg": "...",
    "data": {
      "callbackType": "error",
      "task_id": "2fac****9f72",
      "data": null
    }
  }
  ```
</CodeGroup>

## 状态码说明

<ParamField path="code" type="integer" required>
  回调状态码，表示任务处理结果：

  | 状态码 | 描述                              |
  | --- | ------------------------------- |
  | 200 | 成功 - 请求已成功处理                    |
  | 400 | 验证错误 - 参数验证失败                   |
  | 408 | 超出限制 - 超时                       |
  | 500 | 服务器错误 - 处理请求时发生意外错误             |
  | 501 | 音频生成失败                          |
  | 531 | 服务器错误 - 抱歉，由于问题生成失败。您的积分已退还。请重试 |
</ParamField>

<ParamField path="msg" type="string" required>
  状态消息，提供更详细的状态描述
</ParamField>

## 响应数据字段

<ParamField path="data" type="object" required>
  包含回调数据的容器对象
</ParamField>

<ParamField path="data.callbackType" type="string" required>
  回调类型，表示当前回调阶段：

  | 类型       | 描述        |
  | -------- | --------- |
  | complete | 替换任务全部完成  |
  | error    | 任务失败或发生错误 |
</ParamField>

<ParamField path="data.task_id" type="string" required>
  任务唯一标识符，用于追踪和查询
</ParamField>

<ParamField path="data.data" type="array">
  生成的音乐数据数组。成功时包含替换后的音乐详细信息，失败时为 null

  <Expandable title="音乐对象属性">
    <ParamField path="id" type="string">
      音乐片段的唯一标识符
    </ParamField>

    <ParamField path="audio_url" type="string">
      替换后音乐的完整URL，可直接下载
    </ParamField>

    <ParamField path="stream_audio_url" type="string">
      替换后音乐的流媒体URL，用于在线播放
    </ParamField>

    <ParamField path="image_url" type="string">
      替换后音乐的封面图片URL
    </ParamField>

    <ParamField path="prompt" type="string">
      用于生成替换片段的提示词
    </ParamField>

    <ParamField path="model_name" type="string">
      使用的AI模型名称（例如 chirp-v3-5）
    </ParamField>

    <ParamField path="title" type="string">
      替换后的音乐标题
    </ParamField>

    <ParamField path="tags" type="string">
      替换片段的音乐风格标签
    </ParamField>

    <ParamField path="createTime" type="string">
      替换任务创建时间（格式：YYYY-MM-DD HH:MM:SS）
    </ParamField>

    <ParamField path="duration" type="number">
      替换后音乐的总时长（秒）
    </ParamField>
  </Expandable>
</ParamField>

## 实现回调处理器

以下示例展示如何实现回调处理器：

<CodeGroup>
  ```javascript Node.js theme={null}
  const express = require('express');
  const app = express();

  app.use(express.json());

  app.post('/suno-replace-section-callback', (req, res) => {
    const { code, msg, data } = req.body;
    
    console.log('收到替换分区回调:', {
      taskId: data.task_id,
      type: data.callbackType,
      status: code
    });
    
    if (code === 200 && data.callbackType === 'complete') {
      // 替换任务成功完成
      const musicData = data.data;
      
      if (musicData && musicData.length > 0) {
        musicData.forEach((music, index) => {
          console.log(`替换后的音乐 ${index + 1}:`, {
            id: music.id,
            title: music.title,
            audioUrl: music.audio_url,
            duration: music.duration
          });
          
          // 处理替换后的音乐
          saveReplacedMusic(music);
        });
      }
    } else {
      // 替换任务失败
      console.error('替换分区失败:', msg);
      handleReplacementError(data.task_id, msg);
    }
    
    // 返回200确认收到回调
    res.status(200).json({ status: 'received' });
  });

  function saveReplacedMusic(music) {
    // 实现您的保存逻辑
    console.log('保存替换后的音乐:', music.title);
  }

  function handleReplacementError(taskId, errorMsg) {
    // 实现您的错误处理逻辑
    console.error(`任务 ${taskId} 失败:`, errorMsg);
  }

  app.listen(3000, () => {
    console.log('回调服务器运行在端口 3000');
  });
  ```

  ```python Python Flask theme={null}
  from flask import Flask, request, jsonify
  import json

  app = Flask(__name__)

  @app.route('/suno-replace-section-callback', methods=['POST'])
  def handle_replace_section_callback():
      data = request.json
      
      code = data.get('code')
      msg = data.get('msg')
      callback_data = data.get('data', {})
      
      task_id = callback_data.get('task_id')
      callback_type = callback_data.get('callbackType')
      
      print(f"收到替换分区回调:")
      print(f"任务 ID: {task_id}")
      print(f"回调类型: {callback_type}")
      print(f"状态: {code}, 消息: {msg}")
      
      if code == 200 and callback_type == 'complete':
          # 替换任务成功完成
          music_list = callback_data.get('data', [])
          
          if music_list:
              for i, music in enumerate(music_list, 1):
                  print(f"替换后的音乐 {i}:")
                  print(f"  ID: {music.get('id')}")
                  print(f"  标题: {music.get('title')}")
                  print(f"  音频URL: {music.get('audio_url')}")
                  print(f"  时长: {music.get('duration')}秒")
                  
                  # 处理替换后的音乐
                  save_replaced_music(music)
      else:
          # 替换任务失败
          print(f"替换分区失败: {msg}")
          handle_replacement_error(task_id, msg)
      
      return jsonify({'status': 'received'}), 200

  def save_replaced_music(music):
      """保存替换后的音乐"""
      print(f"保存替换后的音乐: {music.get('title')}")
      # 实现您的保存逻辑

  def handle_replacement_error(task_id, error_msg):
      """处理替换错误"""
      print(f"任务 {task_id} 失败: {error_msg}")
      # 实现您的错误处理逻辑

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

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

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

  $code = $data['code'] ?? null;
  $msg = $data['msg'] ?? '';
  $callbackData = $data['data'] ?? [];

  $taskId = $callbackData['task_id'] ?? '';
  $callbackType = $callbackData['callbackType'] ?? '';

  error_log("收到替换分区回调:");
  error_log("任务 ID: $taskId");
  error_log("回调类型: $callbackType");
  error_log("状态: $code, 消息: $msg");

  if ($code === 200 && $callbackType === 'complete') {
      // 替换任务成功完成
      $musicList = $callbackData['data'] ?? [];
      
      if (!empty($musicList)) {
          foreach ($musicList as $index => $music) {
              $musicIndex = $index + 1;
              error_log("替换后的音乐 $musicIndex:");
              error_log("  ID: " . ($music['id'] ?? ''));
              error_log("  标题: " . ($music['title'] ?? ''));
              error_log("  音频URL: " . ($music['audio_url'] ?? ''));
              error_log("  时长: " . ($music['duration'] ?? 0) . "秒");
              
              // 处理替换后的音乐
              saveReplacedMusic($music);
          }
      }
  } else {
      // 替换任务失败
      error_log("替换分区失败: $msg");
      handleReplacementError($taskId, $msg);
  }

  // 返回200确认收到回调
  http_response_code(200);
  echo json_encode(['status' => 'received']);

  function saveReplacedMusic($music) {
      // 实现您的保存逻辑
      error_log("保存替换后的音乐: " . ($music['title'] ?? ''));
  }

  function handleReplacementError($taskId, $errorMsg) {
      // 实现您的错误处理逻辑
      error_log("任务 $taskId 失败: $errorMsg");
  }
  ?>
  ```
</CodeGroup>

## 回调安全建议

<Warning>
  为确保回调的安全性，建议实施以下措施：

  1. **验证请求来源**：检查请求IP或使用签名验证
  2. **使用HTTPS**：确保回调URL使用HTTPS协议
  3. **实现幂等性**：处理可能的重复回调
  4. **超时处理**：确保在15秒内响应回调请求
  5. **错误日志**：记录所有回调详情以便调试
</Warning>

## 常见问题

<AccordionGroup>
  <Accordion title="为什么没有收到回调？">
    可能的原因：

    * 回调URL不可访问（检查防火墙设置）
    * 回调处理器响应超时（超过15秒）
    * URL格式错误或使用了HTTP而非HTTPS
    * 服务器返回了非200状态码
  </Accordion>

  <Accordion title="如何处理回调重试？">
    系统可能会在以下情况重试回调：

    * 回调URL返回非200状态码
    * 请求超时
    * 网络错误

    建议：

    * 实现幂等性处理，使用task\_id识别重复回调
    * 快速响应200状态码，然后异步处理数据
  </Accordion>

  <Accordion title="替换分区的时长有限制吗？">
    * 替换时间范围必须在 6 秒到 60 秒之间
    * 替换时长建议不超过原音乐总时长的50%
    * 替换片段会自动与原音乐融合
  </Accordion>
</AccordionGroup>

## 替代方案：轮询查询

如果您不使用回调，也可以通过轮询方式查询任务状态：

<Card title="查询任务状态" icon="rotate" href="/cn/suno-api/get-music-generation-details">
  使用获取音乐详情接口定期查询任务状态，建议每30秒查询一次。
</Card>

## 下一步

<CardGroup cols={2}>
  <Card title="替换音乐分区" icon="scissors" href="/cn/suno-api/replace-section">
    了解如何使用替换分区接口
  </Card>

  <Card title="获取音乐详情" icon="circle-info" href="/cn/suno-api/get-music-generation-details">
    查询替换任务的状态和结果
  </Card>
</CardGroup>
