# Autenticación y firma

Las solicitudes a la API de Weydub utilizan las cabeceras `AppKey` y `AppSign`. Mantén `AppSecret` únicamente en el servidor.

## Estructura de la solicitud

| Elemento | Valor |
| --- | --- |
| URL base | `https://api.zhaoli.com` |
| Protocolo | HTTPS |
| Método | `POST` para las llamadas de API documentadas |
| Codificación | UTF-8 |
| Tipo de contenido | `application/json` |
| Cuerpo de la solicitud | JSON, serializado de forma compacta para obtener firmas estables |

## Cabeceras

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

`AppSecret` nunca se envía como cabecera ni como campo del cuerpo. Solo se utiliza en tu servidor para calcular `AppSign`.

## Fórmula de la firma

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

La firma debe calcularse a partir del cuerpo JSON exacto que se envía por la red. Para obtener firmas estables, serializa el JSON sin espacios adicionales.

Si un endpoint permite un cuerpo vacío, firma exactamente los bytes que envías. En la mayoría de las integraciones, se recomienda enviar `{}` y firmar `{}` en las llamadas sin cuerpo.

## Endpoint sin firma

El endpoint de enumeración no requiere firma:

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

Úsalo para obtener enumeraciones dinámicas de idiomas/estados, como `sourceLang`, `Lang`, `ProcessStatus` y `ImageTaskStatus`.

## Ayudante de firma en 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,
    }
```

## Ayudante de firma en 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,
    },
  };
}
```

## Patrón de cURL

Usa tu backend para calcular `AppSign` y después envía el cuerpo exacto:

```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]}'
```

## Firma de callbacks

Cuando Weydub envía un callback, incluye:

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

Verifica los callbacks con la misma fórmula y utiliza el cuerpo sin procesar de la solicitud de callback:

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

Compara `expected` con `Callback-Sign`. Rechaza o pone en cuarentena las cargas útiles de callbacks que no superen la verificación.

## Errores frecuentes

- Firmar JSON con formato legible y enviar JSON compacto.
- Modificar la carga útil después de firmarla.
- Usar un escape de cadenas diferente al firmar y al enviar.
- Firmar un objeto en memoria en lugar de los bytes finales enviados mediante HTTP.
- Olvidar que `extraOptions`, `wyVoiceParam`, `videoInpaintMasks`, `downloadInfo` y `result` de reintento pueden tener que permanecer como cadenas JSON compactas dentro del cuerpo JSON externo.
- Colocar credenciales en código frontend.
- Compartir `AppSecret` con extensiones del navegador, aplicaciones del lado del cliente, capturas de pantalla, registros o prompts públicos.

## Reglas para agentes

- Lee las credenciales desde variables de entorno o un gestor de secretos.
- Nunca muestres `AppSecret`.
- Nunca escribas credenciales en archivos de ejemplo generados.
- Al producir ejemplos ejecutables, usa marcadores de posición o variables de entorno.
- Al depurar un error de firma, compara los bytes del cuerpo y los hashes del cuerpo que no contengan secretos, sin mostrar secretos.
- Verifica `Callback-Sign` en los controladores de webhooks.
