API v1
Base: https://eclair.kayzen-lyon.com/api/v1. JSON en todas partes, respuestas nunca almacenadas en caché. Los datos binarios van en base64url sin relleno. openapi.json
Regla de oro: cifre antes de llamar a la API. Nunca envíe la clave del enlace, el PIN ni el texto en claro. Lo más sencillo es usar nuestro cliente JavaScript (paquete api-client) o la CLI.
Rutas
| Método | Ruta | Finalidad |
|---|---|---|
POST | /secrets | Stocker un secret déjà chiffré |
POST | /secrets/{id}/preview | Libellé chiffré et indicateurs, sans le contenu |
POST | /secrets/{id}/reveal | Révéler (consomme une lecture) |
GET | /manage/{id} | Statut et historique (accusé de lecture) |
DELETE | /manage/{id} | Détruire avant lecture |
POST | /uploads | Ouvrir un envoi de fichiers chiffrés |
POST | /uploads/{id}/parts | URL présignée (5 min) pour une partie |
POST | /requests | Créer une demande de secret (lien de dépôt) |
POST | /requests/{id}/deposits | Déposer un contenu chiffré pour le demandeur |
GET | /requests/{id}/deposits | Lister les dépôts (demandeur) ou vérifier que le lien est ouvert (sans jeton) |
DELETE | /requests/{id} | Fermer la demande et supprimer les dépôts |
POST | /abuse | Signaler un lien abusif |
POST | /webhooks | Enregistrer un webhook https |
DELETE | /webhooks/{id} | Supprimer un webhook |
POST | /domains | Réserver un domaine personnalisé |
GET | /domains/{domain} | État d'un domaine |
POST | /domains/{domain} | Vérifier l'enregistrement TXT et rattacher le domaine |
DELETE | /domains/{domain} | Libérer le domaine |
GET | /config | Limites de l'instance |
GET | /health | Santé du service |
Ejemplo (TypeScript, cifrado local)
import { sendSecret, parseSecretLink, receiveSecret } from "@sesame-eclair/api-client";
const options = { baseUrl: "https://eclair.kayzen-lyon.com" };
// Encrypts in this process, then uploads only the ciphertext.
const sent = await sendSecret(options, {
content: { v: 1, type: "text", text: "DB_PASSWORD=..." },
views: 1,
ttlSeconds: 3600,
});
if (sent.ok) console.log(sent.url, sent.manageUrl);
// Recipient side: the key comes from the link fragment.
const link = parseSecretLink(sent.ok ? sent.url : "")!;
const received = await receiveSecret(options, link);Códigos de estado
404— misma respuesta para secretos desconocidos, caducados, ya leídos o destruidos.401— PIN incorrecto, con attemptsLeft.403— access_denied: la red o el país del lector no cumple las restricciones del secreto. El secreto permanece intacto.423— aún no legible (revelación diferida), con availableAt.429— demasiadas solicitudes, vuelva a intentarlo dentro de una hora.
Webhooks
Registre una URL https con POST /webhooks y, después, pase webhookId al crear el secreto. Recibirá { event, secretId, at } para created, revealed, burned, revoked y expired: nunca el contenido. El signingSecret se muestra una sola vez; verifique cada llamada así:
import { createHmac, timingSafeEqual } from "node:crypto";
// header = request.headers["eclair-signature"], body = raw request body (string)
function verify(header: string, body: string, signingSecret: string): boolean {
const { t, v1 } = Object.fromEntries(header.split(",").map((p) => p.split("=")));
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false; // replay window
const expected = createHmac("sha256", Buffer.from(signingSecret, "base64url"))
.update(`${t}.${body}`)
.digest();
return timingSafeEqual(expected, Buffer.from(v1, "hex"));
}Restricciones de acceso
accessRules: { cidrs: ["203.0.113.0/24"], countries: ["FR"] } limita la apertura a determinadas redes o países (20 entradas como máximo cada uno). La comprobación se realiza antes de cualquier envío del texto cifrado; un país desconocido se rechaza en cuanto existe una regla de país.
Dominio personalizado
POST /domains reclama un dominio y devuelve un registro TXT de verificación y un CNAME. Una vez creados, POST /domains/{domain} comprueba el TXT y vincula el dominio; el certificado TLS se emite automáticamente. La página Dominio personalizado lo hace todo por usted.