# Autentikasi dan Penandatanganan

Permintaan Weydub API menggunakan header `AppKey` dan `AppSign`. Simpan `AppSecret` hanya di sisi server.

## Struktur Permintaan

| Item | Nilai |
| --- | --- |
| URL Dasar | `https://api.zhaoli.com` |
| Protokol | HTTPS |
| Metode | `POST` untuk panggilan API yang terdokumentasi |
| Pengodean | UTF-8 |
| Jenis konten | `application/json` |
| Isi permintaan | JSON, diserialisasi secara ringkas agar tanda tangan stabil |

## Header

```text
Content-Type: application/json
AppKey: your_app_key
AppSign: computed_signature
```

`AppSecret` tidak pernah dikirim sebagai header atau bidang dalam isi permintaan. Ini hanya digunakan di server Anda untuk menghitung `AppSign`.

## Rumus Tanda Tangan

```text
AppSign = md5(md5(request_body) + AppSecret)
```

Tanda tangan harus dihitung dari isi JSON persis sebagaimana dikirim melalui jaringan. Agar tanda tangan stabil, serialisasikan JSON tanpa spasi tambahan.

Jika endpoint mengizinkan isi permintaan kosong, tandatangani byte persis yang Anda kirim. Pada sebagian besar integrasi, sebaiknya kirim `{}` dan tandatangani `{}` untuk panggilan tanpa isi permintaan.

## Endpoint Tanpa Penandatanganan

Endpoint enum tidak memerlukan penandatanganan:

```text
POST /v-w-c/enum/query2
```

Gunakan endpoint tersebut untuk mengambil enum bahasa/status dinamis seperti `sourceLang`, `Lang`, `ProcessStatus`, dan `ImageTaskStatus`.

## Fungsi Bantu Penandatanganan Python

```python
import hashlib
import json


def signed_body_and_headers(payload: dict, app_key: str, app_secret: str):
    body = json.dumps(payload, ensure_ascii=False, separators=(",", ":"))
    body_md5 = hashlib.md5(body.encode("utf-8")).hexdigest()
    app_sign = hashlib.md5((body_md5 + app_secret).encode("utf-8")).hexdigest()
    return body, {
        "Content-Type": "application/json",
        "AppKey": app_key,
        "AppSign": app_sign,
    }
```

## Fungsi Bantu Penandatanganan Node

```js
import crypto from "node:crypto";

export function signedBodyAndHeaders(payload, appKey, appSecret) {
  const body = JSON.stringify(payload);
  const bodyMd5 = crypto.createHash("md5").update(body).digest("hex");
  const appSign = crypto.createHash("md5").update(bodyMd5 + appSecret).digest("hex");
  return {
    body,
    headers: {
      "Content-Type": "application/json",
      AppKey: appKey,
      AppSign: appSign,
    },
  };
}
```

## Pola cURL

Gunakan backend Anda untuk menghitung `AppSign`, lalu kirim isi permintaan yang persis sama:

```bash
curl -X POST "https://api.zhaoli.com/v-w-c/gateway/ve/work/status" \
  -H "Content-Type: application/json" \
  -H "AppKey: $WEYDUB_APP_KEY" \
  -H "AppSign: $WEYDUB_APP_SIGN" \
  --data '{"idWorks":[488026661]}'
```

## Penandatanganan Callback

Saat Weydub mengirim callback, callback tersebut menyertakan:

```text
Callback-Sign: computed_callback_signature
```

Verifikasi callback dengan rumus yang sama menggunakan isi mentah permintaan callback:

```text
expected = md5(md5(raw_callback_body) + AppSecret)
```

Bandingkan `expected` dengan `Callback-Sign`. Tolak atau karantina payload callback yang gagal diverifikasi.

## Kesalahan Umum

- Menandatangani JSON yang diformat rapi, tetapi mengirim JSON yang ringkas.
- Memodifikasi payload setelah ditandatangani.
- Menggunakan pelolosan string yang berbeda antara proses penandatanganan dan pengiriman.
- Menandatangani objek dalam memori alih-alih byte akhir yang dikirim melalui HTTP.
- Lupa bahwa `extraOptions`, `wyVoiceParam`, `videoInpaintMasks`, `downloadInfo`, dan `result` pada proses pengulangan mungkin perlu tetap berupa string JSON ringkas di dalam isi JSON luar.
- Menempatkan kredensial dalam kode frontend.
- Membagikan `AppSecret` kepada ekstensi browser, aplikasi sisi klien, tangkapan layar, log, atau prompt publik.

## Aturan untuk Agen

- Baca kredensial dari variabel lingkungan atau pengelola rahasia.
- Jangan pernah menampilkan `AppSecret`.
- Jangan pernah menulis kredensial ke dalam file contoh yang dihasilkan.
- Saat membuat contoh yang dapat dijalankan, gunakan placeholder atau variabel lingkungan.
- Saat men-debug kesalahan tanda tangan, bandingkan byte isi permintaan dan hash isi nonrahasia tanpa mencetak nilai rahasia.
- Verifikasi `Callback-Sign` pada handler webhook.
