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

# Invoke AI Apps

> Three calling modes for AI apps — sync, async polling, and WebHook — plus task status, cancel, and interrupt APIs

## Overview of Calling Modes

BizyAir offers three calling modes, switched via HTTP headers. **No request body changes are needed:**

| Mode                 | How to enable                       | Behavior                                                                            | Best for                                                         |
| -------------------- | ----------------------------------- | ----------------------------------------------------------------------------------- | ---------------------------------------------------------------- |
| Synchronous blocking | No special header                   | Connection stays open until the task completes, then returns the result             | Short tasks, quick debugging                                     |
| Async polling        | `X-BizyAir-Task-Async: enable`      | Returns `request_id` immediately; client polls for results                          | Long-running tasks, unstable networks, no callback URL available |
| Webhook              | `X-BizyAir-Task-WebHook-Url: <url>` | Returns `request_id` immediately; platform POSTs to your callback URL on completion | Production, high concurrency, long-running tasks                 |

## Synchronous Blocking

The default mode. The HTTP connection stays open until the task completes. No special header is required.

```bash theme={null}
curl -X POST "https://api.bizyair.ai/v1/webapp/task/openapi/create" \
  -H "Authorization: Bearer $BIZYAIR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "web_app_id": 57302,
    "suppress_preview_output": false,
    "input_values": {
      "84:CLIPTextEncode.text": "a futuristic cityscape at sunset",
      "88:KSampler.seed": 354884000907176,
      "81:EmptySD3LatentImage.width": 1280,
      "81:EmptySD3LatentImage.height": 1280
    }
  }'
```

The response contains the task result, including `outputs[].object_url`.

<Note>
  Synchronous mode requires a long-lived connection. Make sure your HTTP client's **read timeout** is at least 60 seconds to prevent the client from disconnecting while the task is still running.
</Note>

## Async Polling

Enable by adding the `X-BizyAir-Task-Async: enable` header to your request.

### Step 1: Submit an async task and get the`request_id`

```bash theme={null}
curl -X POST "https://api.bizyair.ai/v1/webapp/task/openapi/create" \
  -H "Authorization: Bearer $BIZYAIR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "X-BizyAir-Task-Async: enable" \
  -d '{
    "web_app_id": 57302,
    "input_values": {
      "84:CLIPTextEncode.text": "a futuristic cityscape at sunset",
      "88:KSampler.seed": 354884000907176,
      "81:EmptySD3LatentImage.width": 1280,
      "81:EmptySD3LatentImage.height": 1280
    }
  }'
```

Returns `202 Accepted` immediately:

```json theme={null}
{"request_id": "29f53793-12d3-4dd3-b2a8-4d9848e0c7da"}
```

### Step 2: Poll the task status

```bash theme={null}
curl -X GET "https://api.bizyair.ai/v1/webapp/task/openapi/29f53793-12d3-4dd3-b2a8-4d9848e0c7da" \
  -H "Authorization: Bearer $BIZYAIR_API_KEY"
```

### Step 3: Retrieve results once the status is `Success`

```bash theme={null}
curl -X GET "https://api.bizyair.ai/v1/webapp/task/openapi/29f53793-12d3-4dd3-b2a8-4d9848e0c7da/outputs" \
  -H "Authorization: Bearer $BIZYAIR_API_KEY"
```

### Complete Python Example

```python theme={null}
import time
import requests


API_KEY = "YOUR_API_KEY"
BASE = "https://api.bizyair.ai/v1/webapp/task/openapi"
HEADERS = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
    "X-BizyAir-Task-Async": "enable",
}


# 1. Submit task
resp = requests.post(f"{BASE}/create", headers=HEADERS, json={
    "web_app_id": 57302,
    "input_values": {
        "84:CLIPTextEncode.text": "a futuristic cityscape at sunset",
        "88:KSampler.seed": 354884000907176,
        "81:EmptySD3LatentImage.width": 1280,
        "81:EmptySD3LatentImage.height": 1280,
    }
})
request_id = resp.json()["request_id"]
print(f"Task submitted: {request_id}")


# 2. Poll status
HEADERS.pop("X-BizyAir-Task-Async")
while True:
    r = requests.get(f"{BASE}/{request_id}", headers=HEADERS)
    status = r.json()["data"]["status"]
    print(f"Current status: {status}")
    if status == "Success":
        break
    elif status in ("Failed", "Canceled"):
        print("Task failed or canceled")
        exit(1)
    time.sleep(2)


# 3. Get results
r = requests.get(f"{BASE}/{request_id}/outputs", headers=HEADERS)
for out in r.json()["data"]["outputs"]:
    print("Result URL:", out["object_url"])
```

## Webhook Callback

Enable by adding the `X-BizyAir-Task-WebHook-Url` header to your request.

### Step 1: Submit a task with a webhook

```bash theme={null}
curl -X POST "https://api.bizyair.ai/v1/webapp/task/openapi/create" \
  -H "Authorization: Bearer $BIZYAIR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "X-BizyAir-Task-WebHook-Url: https://your-server.com/api/callback" \
  -H "X-BizyAir-Task-Authorization: Bearer YOUR_CALLBACK_TOKEN" \
  -d '{
    "web_app_id": 35661,
    "input_values": {
      "1:EmptyLatentImage.width": "1024",
      "1:EmptyLatentImage.height": "1024",
      "2:BizyAir_BasicScheduler.steps": "20",
      "3:BizyAir_RandomNoise.noise_seed": "1",
      "4:BizyAirSiliconCloudLLMAPI.user_prompt": "A kitten, Van Gogh style",
      "4:BizyAirSiliconCloudLLMAPI.system_prompt": "You are a stable diffusion prompt expert..."
    }
  }'
```

Returns `202 Accepted` + `request_id` immediately.

### Step 2: Receive results at your callback endpoint

When the task completes, BizyAir sends a POST request to the URL you specified:

* **Method**: `POST`
* **Headers**: `Content-Type: application/json`, `User-Agent: Go-http-client/1.1`, along with your `X-BizyAir-Task-Authorization` and any other `X-BizyAir-Task-*` headers you set
* **Body**: Contains the complete task result

### Node.js Callback Server Example

```javascript theme={null}
const express = require("express");
const app = express();
app.use(express.json());


const EXPECTED_TOKEN = process.env.CALLBACK_TOKEN;


app.post("/api/callback", (req, res) => {
  const auth = req.get("Authorization");
  if (EXPECTED_TOKEN) {
    const ok = auth?.startsWith("Bearer ") && auth.split(" ")[1] === EXPECTED_TOKEN;
    if (!ok) return res.status(401).json({ message: "invalid token" });
  }


  const payload = req.body;
  console.log("Received callback for request_id:", payload.request_id);


  res.status(200).json({ ok: true });
});


app.listen(3000, () => console.log("Callback server on :3000"));
```

<Warning>
  Your callback endpoint **must return HTTP 200 OK**. If it returns a non-200 status, times out, or is unreachable, the platform will retry on a schedule (approximately every 6 seconds, up to 10 attempts). The per-request timeout is approximately 10 seconds.
</Warning>

## Choosing a Calling Mode

| Your scenario                                | Recommended mode         | Why                                                          |
| -------------------------------------------- | ------------------------ | ------------------------------------------------------------ |
| Quick local script testing                   | Synchronous blocking     | Simplest — one request returns the result directly           |
| Short tasks integrated into a backend        | Synchronous blocking     | HTTP connection overhead is acceptable for short tasks       |
| Video generation / 3D rendering (long tasks) | Webhook                  | Doesn't block your service; supports large-scale parallelism |
| Unstable client network                      | Async polling            | No long-lived connection needed; poll on demand              |
| Batch processing hundreds of tasks           | Async polling or Webhook | Queue everything, then collect results at your own pace      |
| Production high availability                 | Webhook                  | Push-based with built-in retries                             |

## Query Task Status

Get the current status and metadata of a task (queue info, runtime, etc.).

```bash theme={null}
curl -X GET "https://api.bizyair.ai/v1/webapp/task/openapi/{request_id}" \
  -H "Authorization: Bearer $BIZYAIR_API_KEY"
```

**Response fields** (inside `data`):

| Field                 | Type           | Description                           |
| --------------------- | -------------- | ------------------------------------- |
| `type`                | string         | Task type, e.g. `"API"`               |
| `status`              | string         | Task status enum                      |
| `created_at`          | string         | Created time (UTC+8)                  |
| `updated_at`          | string         | Last updated time                     |
| `executed_at`         | string         | Execution start time                  |
| `ended_at`            | string \| null | End time; `null` if not finished      |
| `expired_at`          | string         | Result file expiry time               |
| `inference_cost_time` | integer        | Inference duration (seconds)          |
| `queue_info`          | object \| null | Only present when status is `Queuing` |

**Status enum**:

| Status      | Meaning                                 | Suggested action                        |
| ----------- | --------------------------------------- | --------------------------------------- |
| `Queuing`   | Queued, waiting for resource scheduling | Keep polling every 1-3 seconds          |
| `Preparing` | Preparing, loading model / environment  | Keep polling                            |
| `Running`   | Running                                 | Keep polling                            |
| `Success`   | Completed successfully                  | **Stop polling**; retrieve results      |
| `Failed`    | Failed                                  | **Stop polling**; check `error_message` |
| `Canceled`  | Cancelled                               | **Stop polling**                        |

## Query Task Results

Retrieve the outputs (`object_url`, etc.) of a **completed task**.

```bash theme={null}
curl -X GET "https://api.bizyair.ai/v1/webapp/task/openapi/{request_id}/outputs" \
  -H "Authorization: Bearer $BIZYAIR_API_KEY"
```

**Response example**:

```json theme={null}
{
  "code": 20000,
  "message": "Ok",
  "status": true,
  "data": {
    "request_id": "29f53793-12d3-4dd3-b2a8-4d9848e0c7da",
    "status": "Success",
    "outputs": [
      {
        "object_url": "https://storage.bizyair.ai/outputs/xxx.png",
        "output_ext": ".png",
        "cost_time": 10657,
        "audit_status": 2,
        "error_type": "NOT_ERROR"
      }
    ]
  }
}
```

**`outputs[]` field reference**:

| Field          | Type    | Description                                                         |
| -------------- | ------- | ------------------------------------------------------------------- |
| `object_url`   | string  | Result file download URL                                            |
| `output_ext`   | string  | File extension (includes `.`)                                       |
| `cost_time`    | integer | Time from task start to this output (ms)                            |
| `audit_status` | integer | Audit status: `1` pending / `2` approved / `3` rejected / `4` error |
| `error_type`   | string  | Error code on failure; `"NOT_ERROR"` on success                     |
| `error_msg`    | string  | Detailed failure reason (optional)                                  |

## Cancel Task

Only works for tasks in the **Queuing** state; removes the task from the queue.

```bash theme={null}
curl -X PUT "https://api.bizyair.ai/v1/webapp/task/openapi/{request_id}/cancel" \
  -H "Authorization: Bearer $BIZYAIR_API_KEY" \
  -H "Content-Type: application/json"
```

<Note>
  Cancellation is idempotent — repeated calls have no side effects. If the task is already running, use Interrupt instead.
</Note>

## Interrupt Task

Only works for tasks in the **Running** state; forces a stop.

```bash theme={null}
curl -X PUT "https://api.bizyair.ai/v1/webapp/task/openapi/{request_id}/interrupt" \
  -H "Authorization: Bearer $BIZYAIR_API_KEY" \
  -H "Content-Type: application/json"
```

<Warning>
  Interrupting a running task **still incurs charges for the portion already executed**. Only tasks in the `Queuing` state can be cancelled at no charge.
</Warning>

## Get AI App Information

You can retrieve metadata for any AI app (WebApp) you have permission to access via `web_app_id`, including the app name, author info, cover image, and all input node definitions (`input_nodes`) required to call the app.

Developers can use this to **dynamically discover** an app's input parameters: the `variable_name` in `input_nodes` corresponds one-to-one with the keys of `input_values` in the "Invoke AI Apps" request body, making it ideal for building DIY plugins. A plugin can first call this endpoint to fetch the input fields, then auto-render a form and construct the call request.

### Endpoint

```text theme={null}
GET https://meta.bizyair.ai/v1/webapp/{web_app_id}/detail
```

`{web_app_id}` is the app ID, the same as the numeric ID in the app detail page URL and the `web_app_id` in the Invoke AI Apps request body. Public apps can be accessed without additional authentication; a 404 is returned if the app does not exist or you lack access.

### Request Example

```bash theme={null}
curl -X GET "https://meta.bizyair.ai/v1/webapp/57302/detail"
```

### Response Example

```json theme={null}
{
  "code": 20000,
  "message": "Ok",
  "status": true,
  "data": {
    "id": 57302,
    "name": "Anima_HiresFix_1.5x Refinement",
    "user_id": "01kwv421t34pg5xtyrtbsvb3t7",
    "nick_name": "Gugugaga",
    "user_avatar": "https://storage.bizyair.ai/users/01kwv421t34pg5xtyrtbsvb3t7/...webp",
    "user_description": "Happy everyday",
    "base_model": "Anima",
    "description": "About $0.03 per run",
    "original_user_id": "01kwv421t34pg5xtyrtbsvb3t7",
    "created_at": "2026-08-05T10:10:55Z",
    "cover_urls": [
      "https://storage.bizyair.ai/img/20260805/431c5578-..._1536_1536.png"
    ],
    "counter": {
      "used_count": 14,
      "liked_count": 1
    },
    "input_nodes": [
      {
        "id": 37986,
        "node_id": 5,
        "node_name": "Positive Prompt",
        "node_type": "CLIPTextEncode",
        "field_name": "text",
        "field_type": "customtext",
        "field_options": "{\"hideOnZoom\":true,\"minNodeSize\":[400,200]}",
        "field_label": "Positive Prompt",
        "field_value": "masterpiece, best quality, ...",
        "variable_name": "5:CLIPTextEncode.text"
      }
    ],
    "source": "others",
    "ref_bizy_model_id": 56210
  }
}
```

`input_nodes` contains all input nodes for the app; the actual response may include multiple nodes. Some field values are omitted in this example.

### Response Field Reference

Fields inside `data`:

| Field                | Type      | Description                                                         |
| -------------------- | --------- | ------------------------------------------------------------------- |
| id                   | integer   | App ID (web\_app\_id)                                               |
| name                 | string    | App name                                                            |
| user\_id             | string    | Author user ID                                                      |
| nick\_name           | string    | Author nickname                                                     |
| user\_avatar         | string    | Author avatar URL                                                   |
| user\_description    | string    | Author bio                                                          |
| base\_model          | string    | Base model                                                          |
| description          | string    | App description (e.g., cost per run)                                |
| original\_user\_id   | string    | Original author user ID (points to the source author on Fork)       |
| created\_at          | string    | Creation time (ISO 8601, UTC)                                       |
| cover\_urls          | string\[] | Cover image URL list                                                |
| counter              | object    | Usage stats: `used_count` (usage count), `liked_count` (like count) |
| input\_nodes         | array     | Input node definition list, used to construct call parameters       |
| source               | string    | App source, e.g. `"others"`                                         |
| ref\_bizy\_model\_id | integer   | Associated BizyAir model ID                                         |

Fields inside `input_nodes[]`:

| Field          | Type    | Description                                                                                       |
| -------------- | ------- | ------------------------------------------------------------------------------------------------- |
| id             | integer | Input field ID                                                                                    |
| node\_id       | integer | Node ID                                                                                           |
| node\_name     | string  | Node name                                                                                         |
| node\_type     | string  | Node type, e.g. `CLIPTextEncode`                                                                  |
| field\_name    | string  | Field name                                                                                        |
| field\_type    | string  | Field type, e.g. `customtext`                                                                     |
| field\_options | string  | Node config (JSON string)                                                                         |
| field\_label   | string  | Field display name, can be used to render form labels                                             |
| field\_value   | string  | Field default value                                                                               |
| variable\_name | string  | Variable name, i.e. the key of `input_values` when calling the app (e.g. `5:CLIPTextEncode.text`) |
| sort           | integer | Sort order (optional)                                                                             |

### Error Response

Returns HTTP 404 when the app does not exist or you lack access:

```json theme={null}
{
  "code": 20230,
  "message": "Resource version not found.",
  "data": null
}
```
