# 画幅扩展与平移（Midjourney）
> 向外扩展与平移都通过 `/mj/submit/action` 触发
> 原图像素保持不变，只在四周补画
> 父任务必须是放大后的单图
`POST /mj/submit/action`
## 认证
- `Authorization` (string / 必填) — 所有接口均使用 Bearer Token 进行认证。 获取 API Key：[访问控制台](https://api.oairoute.com/keys) 创建。 请求时在请求头中添加： ```http Authorization: Bearer YOUR_OAIRoute_KEY ```
## 请求参数
- `customId` (string / 必填) — 动作标识，从父任务 `buttons` 里取。
- `taskId` (string / 必填) — 父任务 ID，必须是放大后的单图任务。
- `notifyHook` (string / 可选) — 回调地址。
- `state` (string / 可选) — 自定义透传字段。
- `noStorage` (boolean / 可选) — 为 `true` 时返回官方链接，默认 `false`。
## 扩展与平移的按钮
| 按钮 | 效果 |
|---|---|
| `Zoom Out 2x` | 画幅扩到 2 倍，原图居中 |
| `Zoom Out 1.5x` | 画幅扩到 1.5 倍 |
| `Pan Left` | 向左平移，右侧补画 |
| `Pan Right` | 向右平移，左侧补画 |
| `Pan Up` | 向上平移，下方补画 |
| `Pan Down` | 向下平移，上方补画 |
> **Note:** 
> 平移动作的 `customId` 里已经包含方向，不需要额外传方向字段。传错方向的 `customId` 会得到相反的结果。
## 连续扩展
同方向的平移可以连续做，把每次的结果当作下一次的父任务，就能拼成长图。每次扩展都会重新生成一张完整图片，不是简单的画布拼接。
## 两步流程
| 步骤 | 端点 | 作用 |
|---|---|---|
| 1 | `POST /mj/submit/action` | 先用 `U1` 放大，拿到单图任务 |
| 2 | `GET /mj/task/{id}/fetch` | 取扩展按钮的 `customId` |
| 3 | `POST /mj/submit/action` | 执行 `Zoom Out` 或 `Pan` |
## 错误码
| HTTP | 含义 |
|---|---|
| 200 | 请求已受理，看 `code` 判断是否成功 |
| 401 | Token 缺失或无效 |
| 429 | 触发限流 |
常见失败：父任务还是四宫格（没先放大）；`customId` 已过期。
更多状态码与重试建议见[错误码与限流](../../../support/errors.html)，常见报错的排查步骤见[常见问题](../../../support/faq.html)。
## 使用示例
### 向外扩展
对放大后的单图执行 `Zoom Out 2x`，得到一张更大画幅、主体不变的新图。
### 单方向平移
用 `Pan Left` 这类按钮，只往一个方向扩，适合续画场景。
### 拼接长图
连续做同方向平移，每次用上一次的结果当父任务。
**向外扩展{Zoom out}::cURL**
```
curl --request POST \
  --url 'https://api.oairoute.com/mj/submit/action' \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
  "customId": "MJ::JOB::outpaint::1::2::UUID",
  "taskId": "1320098173412550"
}'
```
**向外扩展{Zoom out}::Python**
```
import requests

res = requests.post(
    "https://api.oairoute.com/mj/submit/action",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    json={
        "customId": "MJ::JOB::outpaint::1::2::UUID",
        "taskId": "1320098173412550",
    },
)
print(res.json())
```
**向外扩展{Zoom out}::JavaScript**
```
const res = await fetch("https://api.oairoute.com/mj/submit/action", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    customId: "MJ::JOB::outpaint::1::2::UUID",
    taskId: "1320098173412550",
  }),
});
console.log(await res.json());
```
**平移{Pan}::cURL**
```
curl --request POST \
  --url 'https://api.oairoute.com/mj/submit/action' \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
  "customId": "MJ::JOB::pan_left::1::UUID",
  "taskId": "1320098173412550"
}'
```
**平移{Pan}::Python**
```
import requests

res = requests.post(
    "https://api.oairoute.com/mj/submit/action",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    json={
        "customId": "MJ::JOB::pan_left::1::UUID",
        "taskId": "1320098173412550",
    },
)
print(res.json())
```
**平移{Pan}::JavaScript**
```
const res = await fetch("https://api.oairoute.com/mj/submit/action", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    customId: "MJ::JOB::pan_left::1::UUID",
    taskId: "1320098173412550",
  }),
});
console.log(await res.json());
```
**200 向外扩展{Zoom out}**
```
{
  "code": 1,
  "description": "提交成功",
  "result": "1320098173412560"
}
```
**200 平移{Pan}**
```
{
  "code": 1,
  "description": "提交成功",
  "result": "1320098173412561"
}
```
