## I. Getting Started

Complete these prerequisites before calling a BizyAir standard model API.

### 1. Register and Add Balance

Sign in or register for a BizyAir account and ensure that the paid balance is sufficient. **Standard model APIs use paid balance.**

### 2. Get an API Key

Move the cursor over the user avatar in the top-right corner and click **API Key** to obtain your key.

**Keep the API Key secure. Do not commit it to source control or print it in logs.**

## II. Submit a Request

You can now submit API requests.

### 1. Request Example

Set `BIZYAIR_API_KEY` in the runtime environment, then copy and run the example for your language.

Before running the request, you can adjust the parameters in the payload to generate the exact output you need.

Important: follow the parameter format and requirements in **2. Request Parameters** carefully.

```python
import os

import requests

api_key = os.environ["BIZYAIR_API_KEY"]
url = "https://api.bizyair.ai/v1/modelzoo/tasks/openapi/gemini-3-6-flash-official/vision"
headers = {
    "Content-Type": "application/json",
    "Authorization": f"Bearer {api_key}"
}
payload = {
  "prompt": "Describe the content, colors, and composition of this image.",
  "image_urls": [
    "https://storage.bizyair.ai/inputs/20260514/faVQcj0qCx8SO56bHyqjINDg1liU9zxw.jpg"
  ],
  "temperature": 1,
  "max_tokens": 8192
}

response = requests.post(url, json=payload, headers=headers)
response.raise_for_status()
result = response.json()
if result.get("code") != 20000 or result.get("status") is not True:
    raise RuntimeError(result.get("message") or "BizyAir API request failed")
print(result)
```

If you add the header `X-Bizyair-Task-WebHook-Url: https://your-website/webhook` when submitting the request, the task will use asynchronous callback mode. When the task finishes, BizyAir sends a POST request with the task result to your URL. Example:

```python
import os

import requests

api_key = os.environ["BIZYAIR_API_KEY"]
webhook_url = os.environ["WEBHOOK_URL"]
webhook_authorization = os.environ["WEBHOOK_AUTHORIZATION"]
webhook_trace_id = os.environ["WEBHOOK_TRACE_ID"]
url = "https://api.bizyair.ai/v1/modelzoo/tasks/openapi/gemini-3-6-flash-official/vision"
headers = {
    "Content-Type": "application/json",
    "Authorization": f"Bearer {api_key}",
    "X-Bizyair-Task-WebHook-Url": webhook_url,
    "X-Bizyair-Task-Authorization": webhook_authorization,
    "X-Bizyair-Task-Trace-Id": webhook_trace_id
}
payload = {
  "prompt": "Describe the content, colors, and composition of this image.",
  "image_urls": [
    "https://storage.bizyair.ai/inputs/20260514/faVQcj0qCx8SO56bHyqjINDg1liU9zxw.jpg"
  ],
  "temperature": 1,
  "max_tokens": 8192
}

response = requests.post(url, json=payload, headers=headers)
response.raise_for_status()
result = response.json()
if result.get("code") != 20000 or result.get("status") is not True:
    raise RuntimeError(result.get("message") or "BizyAir API request failed")
print(result)
```

The request body is the same whether or not a Webhook callback is configured. Pay special attention to these headers:

| Parameter | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| X-Bizyair-Task-WebHook-Url | string | Optional | Callback URL that BizyAir calls when the task finishes. If omitted, no callback is sent; retrieve the result with the query endpoint in Section III. The callback must be an HTTP or HTTPS POST endpoint. BizyAir does not guarantee callback delivery for overseas endpoints. |
| X-Bizyair-Task-Authorization | string | Optional | If the callback endpoint requires authorization, place the credential here. It is the only header that gets rewritten: the `X-Bizyair-Task-` prefix is removed, so it arrives as `Authorization: ${YOUR_WEBHOOK_AUTHORIZATION}`. |
| X-Bizyair-Task-${HEADER_NAME} | string | Optional | Except for `X-Bizyair-Task-Authorization`, every header prefixed with `X-Bizyair-Task-` is copied into the callback request unchanged, prefix included, such as `X-Bizyair-Task-Trace-Id` in the example above. |

### 2. Request Parameters

Read **Request Parameters** below to refine your request. Following these parameter requirements improves the likelihood of a successful run.

| Parameter | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| prompt | string | Required | Prompt |
| image_urls | string[] | Required | Minimum uploads: 1<br/>Maximum uploads: 8<br/>Image Urls |
| temperature | number | Optional | Value range: 0 ~ 2<br/>Step: 0.1<br/>Temperature |
| max_tokens | number | Optional | Value range: 1 ~ 65536<br/>Max Tokens |
| system_prompt | string | Optional | System Prompt |

> To protect sensitive business information such as prompt design, BizyAir supports masking specific fields in API call logs. Masked fields appear as `[Masked by caller]` in log queries without affecting execution or billing.
>
> **How to use it:** send `X-Bizyair-Log-Mask-Fields` in the request header and provide the fields to mask, separated by commas.
>
> ```http
> Content-Type: application/json
> Authorization: Bearer ${BIZYAIR_API_KEY}
> X-Bizyair-Log-Mask-Fields: prompt, system_prompt
> ```

### 3. Response Example

After a successful submission, you receive a response similar to the following.

This is an **asynchronous task submission receipt**. It indicates that the request has been accepted and the task is queued for execution.

If you receive a different response, refer to **4. Response Fields** below for details.

```json
{
  "code": 20000,
  "message": "Ok",
  "status": true,
  "data": {
    "request_id": "4569bb94-1d30-417a-a987-9715de1e2633"
  }
}
```

### 4. Response Fields

Read the **Response Fields** section below for field meanings and possible values.

| Parameter | Type | Description |
| :--- | :--- | :--- |
| code | integer | Response code, 20000 indicates success. |
| message | string | Message about the API call itself. |
| status | boolean | Whether the API call succeeded. It is not the same field as the task-state string data.status. |
| data | object | Response data container. |
| data.request_id | string | Request ID for subsequent task status queries. |

## III. Query the Result

At this stage, use the generated **request_id** to check whether the task has finished and retrieve the final result.

### 1. Request Example

Set `BIZYAIR_API_KEY` in the runtime environment, and replace the sample `request_id` with the ID returned by the submit response.

```python
import os

import requests

api_key = os.environ["BIZYAIR_API_KEY"]
request_id = "${REQUEST_ID}"
url = f"https://api.bizyair.ai/v1/modelzoo/tasks/openapi/{request_id}"
headers = {
    "Authorization": f"Bearer {api_key}"
}

response = requests.get(url, headers=headers)
response.raise_for_status()
result = response.json()
if result.get("code") != 20000 or result.get("status") is not True:
    raise RuntimeError(result.get("message") or "BizyAir API request failed")
print(result)
```

### 2. Response Example

This is the final receipt returned by the BizyAir query endpoint after the task completes successfully and generates content.

It is the **final result** of the entire generation workflow. By examining this response, you can understand the outcome of every step above.

If you receive a different response, refer to **3. Response Fields** below for details.

```json
{
  "code": 20000,
  "message": "Ok",
  "status": true,
  "data": {
    "request_id": "4569bb94-1d30-417a-a987-9715de1e2633",
    "status": "Success",
    "message": null,
    "created_at": "2026-04-15T13:32:30Z",
    "executed_at": "2026-04-15T13:32:32Z",
    "ended_at": "2026-04-15T13:42:32Z",
    "outputs": {
      "texts": [
        "Here is a detailed breakdown of the content, colors, and composition of the image:\n\n### **Content**\n* **Main Subject:** The iconic tidal island of **Mont Saint-Michel** in Normandy, France. At top center sits the towering Gothic abbey with its sharp spire topped by a golden statue. Below the abbey, medieval stone buildings, defense walls, and turrets form a clustered village rising out of the rocky mount.\n* **Foreground and Access Road:** A modern, gently curving causeway bridge leads toward the island. It features an asphalt lane on the left where a few shuttle buses and pedestrians are visible, and a broad wooden-plank pedestrian walkway on the right where several tourists are strolling.\n* **Surrounding Landscape:** Vast, flat tidal sandbanks and mudflats extend around the base of the island, indicating low tide. Small patches of green marsh grass appear in the lower-right foreground.\n* **Sky:** A completely clear, cloudless blue sky stretches across the top half of the frame.\n\n### **Colors**\n* **Dominant Tones:** \n  * **Blue:** A bright, clear azure sky dominates the upper half, softening slightly toward a lighter sky-blue near the horizon.\n  * **Earthy Neutrals:** The architecture and surrounding sands consist of muted stone shades—warm tan, beige, slate gray, and pale silver-sand.\n* **Accents:**\n  * **Dark Green:** Clusters of trees and vegetation grow along the rocky base of the mount, offering a rich contrast to the pale stone walls.\n  * **Wood & Metal:** The bridge features light brownish-gray weathered timber planks alongside metallic gray guardrails.\n  * **Pops of Color:** Small, subtle specks of color (reds, blues, yellows) appear in the clothing of the tourists walking along the bridge.\n\n### **Composition**\n* **Leading Lines:** The curving causeway enters from the bottom-left corner and sweeps dramatically across the lower portion of the frame toward the right center, drawing the viewer's eye directly toward Mont Saint-Michel.\n* **Focal Point:** The apex of the abbey's spire serves as the ultimate focal point, creating a strong vertical anchor slightly left of center.\n* **Balance & Depth:** \n  * **Negative Space:** The expansive, open sky occupies nearly half the image, balancing the dense, intricate detail of the island structure below.\n  * **Depth:** The long foreshortening of the bridge, combined with the shrinking scale of pedestrians and buses, creates a powerful sense of distance and perspective leading to the massive island."
      ]
    },
    "cost_times": {
      "total_cost_time": 600000,
      "inference_duration": 598000
    }
  }
}
```

### 3. Response Fields

Read the **Response Fields** section below for field meanings and possible values.

| Parameter | Type | Description |
| :--- | :--- | :--- |
| code | integer | Response code, 20000 indicates success. |
| message | string | Message about the API call itself; the reason a task failed is in data.message. |
| status | boolean | Whether the API call succeeded. It is not the same field as the task-state string data.status. |
| data | object | Response data container. |
| data.request_id | string | Request ID for subsequent task status queries. |
| data.status | string | Task status. Confirmed terminal states are Success and Failed; continue querying for other states. |
| data.message | string or null | Error details for Failed tasks; null or omitted for other states. |
| data.created_at | string | Task creation time in ISO 8601 UTC, e.g. 2026-09-07T07:34:56Z. |
| data.executed_at | string | Task execution start time in ISO 8601 UTC. |
| data.ended_at | string | Task end time in ISO 8601 UTC; some Failed responses omit this field. |
| data.outputs | object | Output object; an empty object {} while incomplete or when no output exists. |
| data.outputs.texts | string[] | Text outputs. |
| data.cost_times | object | Timing object; an empty object {} before completion or when timing is unavailable. |
| data.cost_times.total_cost_time | integer | Total task duration in milliseconds. Returned after the task completes. |
| data.cost_times.inference_duration | integer | Model inference duration in milliseconds. Returned after the task completes. |

> Note: output URLs are CDN download links and are not guaranteed to stay available. Copy the files to your own storage soon after the task completes.

### 4. Webhook Callback

If you specify a Webhook callback URL with the `X-Bizyair-Task-WebHook-Url` header when creating the task, BizyAir sends a callback notification to that address when the task finishes.

When the task succeeds:

```json
{
  "code": 20000,
  "message": "Ok",
  "status": true,
  "data": {
    "request_id": "6b88a97e-76e8-480a-bae7-a6f7f37b4e97",
    "status": "Success",
    "message": null,
    "created_at": "2026-05-22T17:14:07Z",
    "executed_at": "2026-05-22T17:14:07Z",
    "ended_at": "2026-05-22T17:14:44Z",
    "outputs": {
      "texts": [
        "Here is a detailed breakdown of the content, colors, and composition of the image:\n\n### **Content**\n* **Main Subject:** The iconic tidal island of **Mont Saint-Michel** in Normandy, France. At top center sits the towering Gothic abbey with its sharp spire topped by a golden statue. Below the abbey, medieval stone buildings, defense walls, and turrets form a clustered village rising out of the rocky mount.\n* **Foreground and Access Road:** A modern, gently curving causeway bridge leads toward the island. It features an asphalt lane on the left where a few shuttle buses and pedestrians are visible, and a broad wooden-plank pedestrian walkway on the right where several tourists are strolling.\n* **Surrounding Landscape:** Vast, flat tidal sandbanks and mudflats extend around the base of the island, indicating low tide. Small patches of green marsh grass appear in the lower-right foreground.\n* **Sky:** A completely clear, cloudless blue sky stretches across the top half of the frame.\n\n### **Colors**\n* **Dominant Tones:** \n  * **Blue:** A bright, clear azure sky dominates the upper half, softening slightly toward a lighter sky-blue near the horizon.\n  * **Earthy Neutrals:** The architecture and surrounding sands consist of muted stone shades—warm tan, beige, slate gray, and pale silver-sand.\n* **Accents:**\n  * **Dark Green:** Clusters of trees and vegetation grow along the rocky base of the mount, offering a rich contrast to the pale stone walls.\n  * **Wood & Metal:** The bridge features light brownish-gray weathered timber planks alongside metallic gray guardrails.\n  * **Pops of Color:** Small, subtle specks of color (reds, blues, yellows) appear in the clothing of the tourists walking along the bridge.\n\n### **Composition**\n* **Leading Lines:** The curving causeway enters from the bottom-left corner and sweeps dramatically across the lower portion of the frame toward the right center, drawing the viewer's eye directly toward Mont Saint-Michel.\n* **Focal Point:** The apex of the abbey's spire serves as the ultimate focal point, creating a strong vertical anchor slightly left of center.\n* **Balance & Depth:** \n  * **Negative Space:** The expansive, open sky occupies nearly half the image, balancing the dense, intricate detail of the island structure below.\n  * **Depth:** The long foreshortening of the bridge, combined with the shrinking scale of pedestrians and buses, creates a powerful sense of distance and perspective leading to the massive island."
      ]
    },
    "cost_times": {
      "total_cost_time": 36815,
      "inference_duration": 36090
    }
  }
}
```

When the task fails:

```json
{
  "code": 20000,
  "message": "Ok",
  "status": true,
  "data": {
    "request_id": "ee8f5246-77ff-4df7-af62-7c55f311bcb2",
    "status": "Failed",
    "message": "Third-party api response error. No image generated.",
    "created_at": "2026-05-25T13:13:04Z",
    "executed_at": "2026-05-25T13:13:04Z",
    "ended_at": "2026-05-25T13:13:06Z",
    "outputs": {
      "texts": [
        "Sorry, I can't provide an image for this kind of content."
      ]
    },
    "cost_times": {
      "total_cost_time": 1930
    }
  }
}
```

Refer to **Response Fields** above for the meaning and value range of each field.

## IV. File Upload

Use this workflow to upload image, audio, or video resources to the BizyAir server.

Uploaded files can then be referenced as input resources in your tasks: pass the returned URL to this endpoint's media parameter `image_urls`.

Note: upload credentials come from `https://api.bizyair.ai/v1`, while committing and listing input resources use the metadata service at `https://meta.bizyair.ai/v1`. The different hosts are expected.

### 1. Get Upload Credentials and Parameters

Call the upload-token endpoint. The server returns the OSS information and temporary STS credentials required for the upload.

```python
import os

import requests

api_key = os.environ["BIZYAIR_API_KEY"]
url = "https://api.bizyair.ai/v1/upload/token"
params = {
    "file_name": "example.webp",
    "file_type": "inputs_temp"
}
headers = {
    "Authorization": f"Bearer {api_key}"
}

response = requests.get(url, params=params, headers=headers)
response.raise_for_status()
result = response.json()
if result.get("code") != 20000 or result.get("status") is not True:
    raise RuntimeError(result.get("message") or "BizyAir API request failed")
print(result)
```

The credential response contains `data.file.object_key`, temporary STS credentials, and `data.storage`:

```json
{
  "code": 20000,
  "message": "Ok",
  "status": true,
  "data": {
    "file": {
      "object_key": "inputs_temp/20260907/example.png",
      "access_key_id": "STS.xxxx",
      "access_key_secret": "xxxx",
      "expiration": "2026-09-07T08:00:00Z",
      "security_token": "xxxx"
    },
    "storage": {
      "endpoint": "https://example-oss-endpoint",
      "bucket": "example-bucket",
      "region": "oss-example-region"
    },
    "access_url": "https://storage.example/inputs_temp/20260907/example.png"
  }
}
```

### 2. Upload to Alibaba Cloud OSS

Use the returned `endpoint`, `bucket`, `region`, `object_key`, and STS credentials to upload a local file to OSS. For more details, see [Alibaba Cloud OSS simple upload](https://help.aliyun.com/zh/oss/user-guide/simple-upload) and the [BizyAir upload guide](https://docs.bizyair.ai/en/api/upload-tutorial.html#oss).

```python
# pip install alibabacloud-oss-v2
import os
import alibabacloud_oss_v2 as oss

def upload_to_oss(region, endpoint, bucket, object_key, file_path, access_key_id, access_key_secret, security_token):
    os.environ["ALIBABA_CLOUD_ACCESS_KEY_ID"] = access_key_id
    os.environ["ALIBABA_CLOUD_ACCESS_KEY_SECRET"] = access_key_secret
    os.environ["ALIBABA_CLOUD_SECURITY_TOKEN"] = security_token

    cfg = oss.config.load_default()
    cfg.credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()
    cfg.region = region[4:] if region.startswith("oss-") else region
    cfg.endpoint = endpoint

    client = oss.Client(cfg)
    return client.put_object_from_file(
        oss.PutObjectRequest(bucket=bucket, key=object_key),
        file_path,
    )
```

Notes:

- Some SDKs require removing the `oss-` prefix from `region`, for example `oss-us-east-1` becomes `us-east-1`.
- It is recommended to set both `region` and `endpoint`, with the returned `endpoint` taking precedence.

### 3. Commit the Input Resource

After the OSS upload succeeds, commit the uploaded input resource so it can be referenced directly in subsequent tasks.

```python
import os

import requests

api_key = os.environ["BIZYAIR_API_KEY"]
url = "https://meta.bizyair.ai/v1/input_resource/commit"
payload = {
    "name": "example.webp",
    "object_key": "inputs_temp/20250911/abc123.webp"
}
headers = {
    "Authorization": f"Bearer {api_key}",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)
response.raise_for_status()
result = response.json()
if result.get("code") != 20000 or result.get("status") is not True:
    raise RuntimeError(result.get("message") or "BizyAir API request failed")
print(result)
```

The commit request must reuse `data.file.object_key` from the credential response. After commit succeeds, pass the returned `data.url` to this endpoint's media parameter `image_urls`:

```json
{
  "code": 20000,
  "message": "Ok",
  "status": true,
  "data": {
    "id": 1711,
    "name": "example.png",
    "ext": ".png",
    "url": "https://storage.example/inputs/20260907/example.png"
  }
}
```

### 4. Query the Inputs List (Optional)

You can query your inputs list to verify the uploaded content.

```python
import os

import requests

api_key = os.environ["BIZYAIR_API_KEY"]
url = "https://meta.bizyair.ai/v1/input_resource"
params = {
    "current": 1,
    "page_size": 20
}
headers = {
    "Authorization": f"Bearer {api_key}"
}

response = requests.get(url, params=params, headers=headers)
response.raise_for_status()
result = response.json()
if result.get("code") != 20000 or result.get("status") is not True:
    raise RuntimeError(result.get("message") or "BizyAir API request failed")
print(result)
```