# Khái niệm

> **Tóm tắt** — Run là một lệnh gọi một style. Priority đúng hạn hoặc miễn phí; Relax rẻ hơn và phải chờ. Run không có kết quả thì miễn phí. Webhook có ký; lệnh gửi idempotent; `end_user_id` bắt buộc.

## Run
Một **run** là một lệnh gọi một style cho ra một kết quả. Bạn gửi, run ở `queued`, rồi `running`, rồi trạng thái cuối.

Priority: bắt đầu ở **2 s**, nhân 1.5 mỗi lần, tối đa **10 s**, cộng thêm 0–0.5 s ngẫu nhiên. Relax: 10 s đến 60 s. Trạng thái cuối: `completed`, `failed`, `nsfw`, `canceled`.

Run mang `price` và `charge`: `held` khi đang chạy, `charged` khi hoàn tất, `released` khi miễn phí, `none` với key test. Huỷ run đang xếp hàng bằng `POST` vào `cancel_url`; tiền giữ được trả lại.

## Style và lane
**Style** là một kết quả làm sẵn (ví dụ kiểu chân dung hay một clip chuyển động). Bạn không chọn model: Wandura giữ các nhà cung cấp phía sau mỗi style và đổi được mà bạn không phải sửa code. Mỗi style có schema `inputs` tại `/v2/public/styles/{style}/openapi.json`.

Mỗi run chọn một **lane**:

- **Priority**: xong trong thời gian cam kết của style (xem [danh sách style](https://docs.wandura.ai/vi/developers/api-v2/styles)) nếu không run miễn phí.
- **Relax**: rẻ hơn, xếp hàng chờ, mỗi end user một run chạy cùng lúc.

`POST /v2/quote` nhận cùng body như run và trả giá và ETA mà không tính tiền.

## Run miễn phí
Bạn không bao giờ trả tiền cho run không có kết quả. Run miễn phí kết thúc với `free_run.reason`:

| `free_run.reason` | Khi nào |
|---|---|
| `priority_late` | Priority did not finish within its promise. |
| `provider_error` | The run failed on our side. |
| `bad_input` | An input could not be used (for example a URL that is not http(s)). |
| `content_blocked` | The input or output was blocked by the content filter (status nsfw). |

## Webhook
Đặt một URL webhook cho mỗi product trong [console](https://open.wandura.ai/webhooks). Mỗi lần run đổi trạng thái được POST như một event, **có ký**:

```
Wandura-Signature: t=1791600000,v1=5f2b…
```

`v1` là HMAC-SHA256 dạng hex của `t + "." + raw body` với webhook secret của bạn. Kiểm trên raw body, từ chối `t` lệch quá 5 phút so với bây giờ, rồi trả 2xx nhanh. Non-2xx sẽ được gửi lại (30 s, 2 phút, 10 phút, 1 giờ, 6 giờ, 24 giờ). Có thể nhận lặp: khử trùng theo `Wandura-Event-Id`, và giữ `sequence` cao nhất cho mỗi run. [SDK](https://docs.wandura.ai/vi/developers/api-v2/sdks) có sẵn hàm kiểm.

Loại event: `run.running`, `run.completed`, `run.failed`, `run.nsfw`, `run.canceled`. Link kết quả được giữ 72 giờ.

## Giới hạn
| Giới hạn | Mặc định | Điều xảy ra |
|---|---|---|
| Run mỗi end user mỗi ngày | 20 | Vượt: 429 `end_user_cap_reached` kèm `Retry-After` (đặt lại 00:00 UTC). Tổ chức của bạn có thể đổi mức trần. |
| Run đồng thời mỗi product | 20 | Run thừa xếp hàng (queued) thay vì lỗi; Priority đi trước. |
| Run Relax đang chạy mỗi end user | 1 | Run Relax kế tiếp của end user đó chạy khi run trước kết thúc. |
| Cửa sổ chữ ký webhook | 300 s | Từ chối webhook có timestamp cũ hơn hoặc mới hơn mức này. |

Cần nhiều hơn? Cho chúng tôi biết khối lượng của bạn, chúng tôi nâng giới hạn của tổ chức.

## Idempotency
Mỗi lệnh gửi (`POST /v2/styles/{style}` hoặc `POST /v2/runs`) phải có header `Idempotency-Key`, một chuỗi duy nhất tối đa 255 ký tự. Nếu mạng đứt và bạn thử lại với cùng key và body, bạn nhận lại run đầu tiên (`200`, header `Idempotent-Replayed: true`): không bao giờ chạy hay tính tiền hai lần. Cùng key mà body khác là `409 idempotency_key_reused`. Dùng key mới cho mỗi run mới.

## End-user ID
`end_user_id` bắt buộc trên mọi run: id của người trong app của bạn mà run này dành cho (chuỗi tự chọn, tối đa 255 ký tự; đừng gửi email hay tên). Trần theo ngày và quy tắc Relax tính theo end user, nên một người dùng nặng không ăn hết cả product. Dùng nó trong console để trả lời khiếu nại của người dùng.

## Tải tệp lên
Không có chỗ lưu trữ riêng? `POST /v2/uploads` với `{content_type, size_bytes}` trả `upload_url` đã ký sẵn. PUT dữ liệu vào đó, rồi truyền `file_url` trong `inputs`. Tệp được giữ 24–48 giờ.

## Test và live
Key test (`wdr_test_…`) trả kết quả mẫu với giá $0 và theo cùng quy tắc (idempotency, end-user ID, webhook), nên code bạn thử là code bạn chạy thật. Key live chạy thật.
