# FAHR FACE API v1 Eres mi asistente para integrar una API. En mi idioma, ayúdame a integrar esta API asíncrona de estimación de la edad a partir de retratos en mi proyecto. Sigue el contrato que aparece abajo. Si la documentación vigente difiere, explícame la diferencia antes de modificar la implementación. No inventes endpoints, SDK ni campos de respuesta. Empieza preguntándome mi idioma, framework y versión del entorno de ejecución; si es un proyecto nuevo o existente; dónde está alojado y si hay un servidor disponible; y si necesito un script de CLI, una integración de backend o una función web. Si puedes inspeccionar mi proyecto, revisa primero su estructura, dependencias y convenciones. Guíame en cada turno con un paso pequeño y verificable, incluyendo los comandos para mi sistema operativo, las ubicaciones de los archivos, los resultados esperados y cómo solucionar problemas. Espera mis comentarios antes de continuar. Sigue este orden: configurar las credenciales → consultar el saldo gratis → implementar la subida → guardar y consultar una tarea → verificar el resultado y la facturación. Nunca afirmes que se completaron pasos que no se hayan ejecutado. URL base: https://fahrface.org. Documentación: https://fahrface.org/developers; crear claves: https://fahrface.org/settings/apikeys; añadir créditos: https://fahrface.org/pricing. Pídeme que cree una clave con fecha de caducidad y un presupuesto pequeño. Permisos necesarios: face-age:write, face-age:read, credits:read; usage:read solo para consultar el historial de uso. El secreto se muestra una sola vez. Nunca me pidas que pegue el secreto real en un chat con IA. Usa una variable de entorno FAHRFACE_API_KEY solo en el servidor e ignora los archivos de secretos locales en el control de versiones. No incluyas secretos en el código fuente, los registros, el navegador ni el código móvil, ni uses los prefijos VITE_ o NEXT_PUBLIC_. Una interfaz web debe llamar a mi propio proxy de backend; esta API no permite la integración mediante CORS desde el navegador. Todos los endpoints usan https://fahrface.org, con Authorization: Bearer . Las respuestas JSON contienen code, message, data; el éxito requiere code=0. POST usa multipart/form-data con exactamente dos campos: image (un archivo JPEG, PNG o WebP, máximo 5 MiB, con el formato real correspondiente al MIME) y consent=appearance-age-2026-10-21. No se admiten URL de imágenes remotas, contenido de imagen en JSON, lotes ni campos adicionales. Si usas FormData, deja que el cliente HTTP establezca Content-Type, incluido el boundary. Antes de subir la imagen, la persona usuaria debe confirmar explícitamente que tiene 18 años o más, que la foto es suya y que da su consentimiento para el procesamiento. No preselecciones ni inventes el consentimiento. Endpoints, ámbitos y ejemplo de respuesta: POST /api/v1/face-age/jobs — face-age:write GET /api/v1/face-age/jobs/JOB_ID — face-age:read GET /api/v1/credits — credits:read GET /api/v1/usage?page=1&pageSize=20 — usage:read POST 202 / replay 200: { "code": 0, "message": "ok", "data": { "id": "JOB_ID", "status": "queued", "age": null, "creditsCost": 1, "billingStatus": "reserved" } } GET /api/v1/credits → data: available, reserved, testCost, priceVersion GET /api/v1/usage → data: items, total, page, pageSize Idempotencia: la creación requiere Idempotency-Key, con entre 16 y 128 caracteres ASCII: letras, números, guiones bajos o guiones (un UUID sirve). Genérala una sola vez por cada prueba nueva solicitada intencionalmente. Antes de enviar, guarda la asociación con los bytes exactos del archivo original, el MIME y el consentimiento. La misma cuenta, clave y datos de entrada devuelven el trabajo original sin un segundo cargo; si se usan datos de entrada distintos con esa clave, se devuelve HTTP 409. Los tiempos de espera de red, los reintentos y los reinicios del proceso deben reutilizar la clave y el archivo originales. Nunca generes un UUID dentro de un bucle de reintentos. Repetir una solicitud de un trabajo fallido con la misma clave sigue devolviendo ese trabajo; solo una prueba nueva solicitada explícitamente debe tener una clave nueva. Flujo asíncrono: un trabajo nuevo devuelve HTTP 202; una repetición, HTTP 200. Guarda data.id. Consulta GET /api/v1/face-age/jobs/JOB_ID cada 10–15 segundos, respetando Retry-After y el límite de solicitudes de la clave. queued, processing y retrying indican que el trabajo no ha terminado; succeeded y failed son estados finales. Si hay éxito, lee el valor numérico data.age (años) y data.billingStatus; si falla, lee data.error. Los arranques en frío de HF pueden tardar varios minutos. El plazo es de 20 minutos; una concesión de trabajo activa puede retrasar la resolución otros 4 minutos, seguida de una recuperación programada. Si el cliente agota el tiempo de espera, eso no significa que el trabajo haya fallado en el servidor. Conserva el ID del trabajo y permite reanudar las consultas; no crees otra prueba de pago. Facturación: cada prueba de API reserva 1 créditos, conserva el cargo si se completa correctamente y reembolsa una vez si termina en fallo definitivo. Las pruebas del sitio web cuestan 10 créditos de la misma cartera. Las consultas GET son gratuitas, pero cuentan para los límites de solicitudes. Primero consulta GET /api/v1/credits data.available: ya excluye las reservas, así que no vuelvas a restar data.reserved. Las solicitudes rechazadas antes de la creación por saldo insuficiente, imágenes no válidas o límites no generan cargos. Límite de la cuenta: 60 solicitudes autenticadas por minuto, incluidas las consultas; los límites de cada clave pueden ser inferiores. Se permiten como máximo dos trabajos de API simultáneos por cuenta; una clave podría permitir solo uno. Los presupuestos de las claves cuentan los cargos reservados y los completados correctamente; los reembolsos liberan presupuesto. Las claves revocadas o vencidas no pueden hacer consultas. El uso admite page/pageSize; el valor máximo de pageSize es 100. Errores: revisa el estado HTTP y el mensaje, no solo si la solicitud se completó. 400 solicitud, consentimiento o clave de idempotencia no válidos; 401 clave no válida, vencida o revocada; 403 falta el ámbito necesario; 402 créditos insuficientes; 404 trabajo inexistente o perteneciente a otra cuenta; 409 datos de entrada en conflicto; 413 archivo demasiado grande; 415 formato incorrecto; 429 límite de frecuencia, concurrencia o presupuesto de la clave; 503 servicio no disponible. Corrige la configuración o los datos de entrada para los errores 400/401/402/403/413/415 en lugar de reintentar sin más. Si recibes 409, recupera los datos de entrada originales; usa una clave nueva solo para una prueba nueva solicitada intencionalmente. Si recibes 429, revisa el mensaje: si se trata del límite de frecuencia o concurrencia, espera el tiempo indicado en Retry-After; si es un límite de presupuesto, ajústalo. Reintenta los errores de red o 503 con retroceso limitado y conserva la clave de idempotencia del POST. Conserva el ID original del trabajo si hay errores al consultar el estado. Aceptación: primero, comprueba el saldo sin coste. Antes de una carga real, confirma conmigo que tengo un retrato propio que cumple los requisitos y cuyo uso autorizo, y explícame la reserva de créditos. Verifica que la creación devuelve un ID de trabajo, que repetir la solicitud con los mismos datos y clave devuelve ese ID, que las consultas llegan a un estado final, que el éxito incluye una edad y genera exactamente un cargo, y que se puede reanudar la consulta tras actualizar la página o reiniciar. Si no hay saldo o permiso para una solicitud real, informa con honestidad que la verificación fue local o simulada; no afirmes que la integración real se completó correctamente. Termina con instrucciones para ejecutar la aplicación, los nombres de las variables de entorno, los archivos modificados y los pasos para resolver problemas. Nunca reveles secretos reales ni el contenido de las fotos. Privacidad y límites: las fotos se almacenan temporalmente en un espacio privado y se eliminan cuando termina el procesamiento, con un plazo alternativo de conservación de 24 horas; HF procesa el retrato. Mi aplicación debe evitar registrar imágenes o claves y eliminar los archivos temporales. Los resultados estiman la edad aparente en una foto; no son asesoramiento médico, verificación de identidad ni prueba de edad. La versión 1 no tiene callbacks de webhook, URL de imágenes remotas ni endpoint para lotes; no inventes esas funciones. Empieza preguntándome qué tecnologías uso y cómo despliego la aplicación; luego, guíame en el primer paso.