Un compte, toutes vos applications — inscription vérifiée (email + SMS), crédit global, débits par app.
app_id public et un app_secret privé.auto) ou sur approbation (manual) ; révocable par utilisateur dans le back-office.Deux niveaux d'API, deux niveaux de confiance : l'API client s'utilise depuis le navigateur avec un token utilisateur ; l'API serveur (débits) exige l'app_secret et ne doit être appelée que par votre backend.
Le plus simple : le widget embarquable. Il affiche connexion / inscription / mot de passe oublié aux couleurs de votre app (avec son animation d'entrée), et vous rend une session.
<script src="https://account.ebsoft.studio/widget/ebsoft-account.js"></script>
<script>
EBSoftAccount.init({
app: "mon-app", // identifiant déclaré dans le back-office
lang: "fr", // "fr" | "en" (défaut : langue du navigateur)
onLogin: function (session) {
// session = { email, token, salt, profile }
// profile = { nom, prenom, email, balance, approved, status, apps, … }
console.log("Connecté :", session.email, "solde :", session.profile.balance);
},
onLogout: function () { console.log("Déconnecté"); }
});
// Login auto au chargement (session mémorisée + validée serveur) :
EBSoftAccount.me().then(function (session) {
if (!session) EBSoftAccount.open(); // sinon : ouvre l'écran de connexion
});
</script>
| Méthode | Rôle |
|---|---|
init(options) | Configure le widget pour votre app (une fois au chargement). |
open(vue?) | Ouvre l'écran — "login" (défaut), "signup" ou "reset". |
close() | Ferme l'écran. |
session() | Session mémorisée (localStorage) ou null — sans appel réseau. |
me() | Valide la session auprès du serveur (login auto). Promesse → session à jour ou null. |
logout() | Déconnexion serveur + locale. |
request(action, payload) | Appel bas niveau de l'API client (ex. usage). |
init : remember:false (pas de session en localStorage),
baseUrl (autre instance, ex. serveur de dev), zIndex.POST https://account.ebsoft.studio/api/account.php — corps JSON { action, app?, lang?, … }.
Le champ app personnalise les emails, applique la politique d'accès de votre app et alimente les statistiques : envoyez-le toujours.
| Action | Corps | Réponse |
|---|---|---|
register | {nom, prenom, email, address, country, phone} | {ok} — code envoyé par email |
verify_email | {email, code} | {ok, smsSent} — rappeler = renvoi du SMS |
confirm | {email, smsCode?, password} | {ok, token, profile, salt, appAccess} + bonus de bienvenue |
login | {email, password} | {ok, token, profile, salt} |
me | {email, token} | {ok, profile, salt} |
logout | {email, token} | {ok} |
update_profile | {email, token, address?, country?} | {ok, profile} (email/téléphone : admin uniquement) |
usage | {email, token, limit?} | {ok, ops:[{at, app, task, charged}], balance} |
pwd_change_request | {email, token} | {ok} — code envoyé par email |
verify_password | {email, token, password, code?} | {ok} — à appeler AVANT une migration de chiffrement |
change_password | {email, token, oldPassword, newPassword, code} | {ok, token, salt} — SEL CONSERVÉ, autres sessions coupées |
reset_request | {email} | {ok} (toujours — anti-énumération) |
reset_verify_email | {email, code} | {ok, smsSent} |
reset_confirm | {email, smsCode, newPassword} | {ok, token, salt, profile} — NOUVEAU SEL (cf. §7) |
POST https://account.ebsoft.studio/api/billing.php — corps JSON
{ action, app_id, app_secret, … }.
app_secret ne doit JAMAIS être exposé au navigateur.
Il vit dans la configuration privée de VOTRE serveur (comme une clé d'API IA). Le flux type :
votre client appelle votre backend avec {email, token} → votre backend vérifie
(check), appelle son fournisseur IA, calcule le prix, puis débite (debit).| Action | Corps | Réponse |
|---|---|---|
check | {email, token} | {ok, balance, approved, granted} — ok:false + no-credit si solde ≤ 0. À appeler AVANT l'appel IA. |
debit | {email, token, amount, task, detail?} | {ok, balance} — amount en euros, montant FINAL (votre coût × votre marge). À appeler APRÈS l'appel IA. |
user | {email} | {ok, profile, balance, granted} — serveur à serveur, sans token (tâches de fond). |
detail (libre, journalisé — jamais de contenu de requête) :
{model?, in?, out?, pages?, cost?, meta?}.
function eba_api(string $action, array $payload): array {
$body = json_encode(array_merge([
'action' => $action,
'app_id' => 'mon-app',
'app_secret' => MON_APP_EBA_SECRET, // config privée serveur
], $payload));
$ch = curl_init('https://account.ebsoft.studio/api/billing.php');
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $body, CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_TIMEOUT => 20]);
$res = json_decode((string)curl_exec($ch), true);
curl_close($ch);
return is_array($res) ? $res : ['ok' => false, 'error' => 'invalid-response'];
}
// 1) Garde AVANT l'appel IA
$chk = eba_api('check', ['email' => $email, 'token' => $token]);
if (empty($chk['ok'])) { http_response_code(402); exit(json_encode($chk)); }
// 2) … appel IA, calcul du prix final en euros …
// 3) Débit APRÈS l'appel (journalisé avec votre app_id)
eba_api('debit', ['email' => $email, 'token' => $token,
'amount' => $prixEuros, 'task' => 'summarize',
'detail' => ['model' => 'mistral-small', 'in' => $tin, 'out' => $tout, 'cost' => $cout]]);
Tout se règle dans le back-office (onglet Applications) et se sert au widget via
GET /api/app.php?app=<id> :
| Champ | Rôle |
|---|---|
accent / accent2 | Dégradé des boutons, focus des champs, logo par défaut. |
bg | Couleur du voile derrière la carte de connexion. |
animation | Animation d'entrée de la carte : fade-up, slide, zoom, flip, none. |
logo | URL d'un logo (sinon : monogramme sur dégradé). |
tagline_fr/en | Phrase d'accroche sous le nom de l'app. |
| Code | HTTP | Signification |
|---|---|---|
auth-required | 401 | email/token manquants ou compte inconnu |
session-expired | 401 | token invalide ou expiré (30 j) |
account-disabled | 403 | compte désactivé |
account-pending-approval | 403 | compte non approuvé (console) |
app-access-pending | 403 | accès à l'app en attente d'approbation (politique manual) |
app-access-denied | 403 | accès à l'app révoqué |
app-auth-failed | 401 | app_id/app_secret invalides (API serveur) |
app-inactive | 403 | app désactivée dans le registre |
no-credit | 200 | solde ≤ 0 (réponse de check, ok:false) |
amount-exceeds-cap | 400 | débit unitaire au-delà du plafond de sécurité |
| « Trop de tentatives… » | 429 | quota anti-abus (fenêtre glissante) — en-tête Retry-After |
password_hash (bcrypt), jamais réversibles. Codes à 6 chiffres : 15 min, 5 essais, comparaison à temps constant.change_password CONSERVE le sel : votre app doit re-chiffrer ses données avec la nouvelle clé AVANT d'appeler l'action (utilisez verify_password avec le code d'abord — un code erroné doit échouer avant le re-chiffrement).reset_confirm RÉGÉNÈRE le sel (l'utilisateur a perdu son mot de passe : l'ancienne clé est irrécupérable). Le compte porte alors saltChangedAt ; si votre app stocke des données chiffrées, prévenez l'utilisateur qu'elles deviennent illisibles et purgez-les côté app.init({app}), brancher onLogin/onLogout.check avant chaque usage payant, debit après (montant final en euros, task parlant).EBSoft Account — PHP 7.4, stockage fichier, zéro dépendance externe (hors PHPMailer). Console : back-office.